4

如果我有一个嵌套类的类,你为什么不希望它是静态的?有没有办法让同一个类的两个实例拥有不同的嵌套类?

例如:

class MyClass {  
    public static class myInnerClass {

    }
}
4

6 回答 6

6

你为什么不希望它是静态的

因为我希望它访问父对象的实例数据。

有没有办法让同一个类的两个实例拥有不同的嵌套类?

你是什​​么意思have?宣布?一个类只有一个声明,您可以在其中列出所有嵌套类。所以,在这种情况下,答案是否定的。

于 2012-12-20T20:22:21.710 回答
3

以一个ComparatorRunnable(多线程)实现为例。当您需要一个可以访问当前实例的字段和方法但在该类之外无用的额外类时,这是一个经典示例。但是,静态类在封闭类型之外也很有用。

public class EnclosingType
{

    private static final class StaticRunnableImplementation implements Runnable
    {
        private final EnclosingType instance;

        public StaticRunnableImplementation(EnclosingType instance)
        {
            this.instance = instance;
        }

        @Override
        public void run()
        {
            instance.getSomething();
            //getSomething() leads to compile error
        }
    }

    public class NonStaticRunnableImplementation implements Runnable
    {
        @Override
        public void run()
        {
            doStuff();
        }

    }

    public int getSomething()
    {
        return 42;
    } 

    public synchronized void doStuff()
    {
        ;
    }

    public void doSomething()
    {
        Thread t1 = new Thread(new StaticRunnableImplementation(this));
        Thread t2 = new Thread(new NonStaticRunnableImplementation());

        t1.start();
        t2.start();
    }
}

如果嵌套类被声明为静态,则无法访问封闭类型的当前实例的非静态方法和字段。

于 2012-12-20T20:21:13.510 回答
2

我不知道我是否正确理解了您的问题,但是静态内部类与非静态之间的区别在于,第二个内部类需要创建父类的引用。

最好创建静态类,因为可以创建“隐藏的 ciclic 引用”。例如,在 GUI 开发中你会做类似的事情是正常的

public class View {
    private Table table;        
    ...
    private void addListeners() {
        this.table.addListener(new TableSelectionListener());
    }

    privte class TableSelectionListener implements Table.SelectionListener {
        @Overrides
        public void selected(SelectionEvent evt) { /* do stuff.*/ }
    }
}

很多程序员没有意识到,但是你现在在Viewand之间有一个循环引用Table,因为SelectionListener是非静态的,保存了对其父级的引用。所以

视图 -> 表 -> TableSelectionListener -> 视图

如果您声明TableSelectionListener static它只需要创建视图中的“命名空间”,但除此之外,View除非您将其保存在字段中,否则它不会保存对任何引用。但是,您将回到第一个问题:P

希望有帮助:)

于 2012-12-20T20:29:02.153 回答
0

一个非静态嵌套类是关联的并且可以访问封闭类实例的成员:

非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有。

于 2012-12-20T20:22:01.717 回答
0

例如,如果您实现Listener某种类型的 a,您通常希望在收到事件时调用外部类上的方法。在这种情况下,内部类比具有对外部类实例的显式引用的嵌套类更简单。

这通常用于 GUI 组件。例如(使用实际上不存在的 API):

public class CircleView extends View {
     private final Circle circle = new Circle();
     private final Button button = new Button();

     public CircleView() {
         circle.setColor(Color.RED);
         button.addClickListener(new MyClickListener());
     }

     private toggleColor() {
         circle.setColor(circle.getColor() == Color.RED ? Color.BLUE : Color.RED);
     }

     private class MyClickListener implements ClickListener() {
         @Override
         public void onClick() {
             // Only possible because of the implicit reference:
             toggleColor();
         }
     }
}
于 2012-12-20T20:22:29.020 回答
0

非静态嵌套类以隐式/神奇的方式允许以下内容:

class MyClass {  
    public static class MyInnerClass {
        final MyClass myClass_this;
        public MyInnerClass(MyClass parent) {
            // Nested class instance has/keeps access to "parent" object.
            // In a nested non-static class the "parent" is -guaranteed- to be
            // non-null as the nested class can only be created with
            // an instance of the containing class.
            myClass_this = parent;
        }
        public Foo bar() {
            // Use myClass_this
            // Would be available as MyClass.this or implicit resolution in a
            // a nested non-static class.
        }
    }
}

范围访问的规则也有点不同,但上面应该显示它何时可能有用/可取。在这两种情况下,内部类 ( )只有一种类型MyClass$MyInnerClass,尽管可以有很多实例。

拥有这种非静态嵌套类型行为是否是一件“好事”值得商榷,但它在 Java 中提供的。

然而,这种“非静态”行为在 Java 中非常有用的一种情况是匿名类(例如事件处理程序或回调),它们表现为非静态嵌套类。而“不同”构造相同的机制允许访问封闭类型中定义的方法。因此,将匿名类移动到非静态嵌套类只能被视为这种常见习语的扩展,它也允许暴露主格类型。

(C# 没有“非静态”嵌套类的概念,但按照上面的方法很容易模拟它——尽管我认为传递更精细的接口通常会更好。此外,闭包等其他构造最小化需要/使用更多。)

于 2012-12-20T20:44:59.777 回答