在静态嵌套类匿名方法Java中访问外部类变量的最佳实践

时间:2018-07-10 04:35:04

标签: java oop memory-management memory-leaks

在基于Android的应用程序中,我的静态onClick Listener中有一个匿名函数,即InnerClass,它可以从OuterClass访问视图。问题是我尝试访问时从所需位置的特定视图指出从静态角度不能访问非静态成员...当我从OuterClass使视图静态时,它可以工作,但这是一个好习惯吗?不会导致任何形式的内存泄漏吗?在这种情况下可以做什么?

public class OuterClass extends CustomAppCompatActiivity {
static EditText city_et;
 public static class InnerClass extends DialogFragment {
 @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            okBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                        //the view to access
                        city_et.setText("");

                    }
                    getDialog().dismiss();
                }
            });
        }

 }


}

2 个答案:

答案 0 :(得分:0)

在不了解全部上下文的情况下很难回答。 EditText city_et很可能不是 static ,而是仅用于编译代码。 (OuterClass的所有实例都具有相同的city_et吗?我不这样认为。)

您可以将city_et作为参数传递给RecyclerDialogFragment构造函数,并将其存储为实例变量,以使您拥有静态的嵌套类而不是内部类。

答案 1 :(得分:0)

静态嵌套类InnerClass无法访问封闭实例的成员,因为InnerClass的实例可能不归OuterClass所有。想象一下:

public class Outer {
    public String out = "out";

    public static class StaticInner {
        public void printEnclosing() {
            System.out.println(Outer.this.out); // Let's say this compiles
        }
    }
}

public class Test {
    public static void main(String[] args) {
        StaticInner si = new StaticInner();
        si.printEnclosing();
    }
}

请注意,从未创建Outer的实例。那么如何打印out的值?

您需要的是内部类。除了封闭类或其子类之外,任何其他人都无法实例化内部类。这样可以确保只有在已有外部类实例的情况下,才能实例化内部类。

public class Outer {
    public String out = "out";
    public Inner inner = new Inner();

    public class Inner {   
        public void printEnclosing() {
            System.out.println(Outer.this.out); // "out" can be safely referenced
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Inner inner = new Inner(); // Compile-time error

        Outer out = new Outer();
        out.inner.printEnclosing(); // This works, because you are calling method of the Inner class instance owned by Outer class.
    }
}

因此,这就是您的代码的样子:

public class OuterClass extends CustomAppCompatActiivity {
    private EditText city_et;
    private final InnerClass inner = new InnerClass();
    public class InnerClass extends DialogFragment {
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            okBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //the view to access
                    city_et.setText("");

                    getDialog().dismiss();
                }
            });
        }
    }

    public InnerClass getInnerClass() {
        return inner;
    }
}

更新

出于对内存泄漏的关注,我认为问题是:InnerClassOuterClass的作用是什么。每当您有一个新的InnerClass时,您就可以每次创建一个InnerClass实例(或OuterClass实例的集合)。 InnerClass需要引用OuterClass才能调用setText()

因此,此处的合同为:InnerClass不能没有OuterClass,并且InnerClass始终具有InnerClassInnerClass将与OuterClass一起被垃圾回收。

如果InnerClassOuterClass之间的关系是InnerClass可以在没有OuterClass的情况下运行,而您所需的只是EditText city_et引用,那么您应该传递该引用。由于InnerClass现在独立于OuterClass,因此您可以使用静态嵌套类,也可以将其移动到另一个单独的类中。

public class OuterClass extends CustomAppCompatActiivity {
    private EditText city_et;

    public static class InnerClass extends DialogFragment {
        private EditText city_et;

        public InnerClass(EditText city_et) { // Pass a reference in
            this.city_et = city_et;
        }

        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            okBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //the view to access
                    city_et.setText("");

                    getDialog().dismiss();
                }
            });
        }
    }
}

通过这种方式,只要有资格OuterClass,就可以独立于InnerClass进行垃圾回收。唯一不能被垃圾收集的引用是该EditText实例。

更新2

EJP指出“内部类不能被封闭类或其子类之外的任何人实例化”是错误的,并且在签出后,他是对的。最重要的是,“内部类”一词是“非静态嵌套类”的正式术语。

但是,如果您认为DialogFragment子类的生存期可能长于封闭类,则仍然应该使用静态嵌套类或单独的类。