1.普通的内部类(内部类非static)
内部类可以访问外围对象的所有成员,某个外围类对象创建一个内部类对象时,此内部类对象会捕获一个指向外围类的引用。然后在访问外围类的成员时,就是用那个引用来选择外围类的成员。编译器访问不到这个引用就会报错。
普通内部类不能有static的属性和方法,若有则要使用嵌套类。
class Outer{
public class Inner{
}
Inner in = new Inner();// 包含了这个外部对象的引用为this
}
public class Test{
public static void main(String[] args) {
// Outer outer = new Outer();
// Outer.Inner in = outer.new Inner();// 这两句和下面完全等价
Outer.Inner in = new Outer().new Inner();
}
}
注意:Outer.Inner in = new Outer().new Inner(); 当导包的时候导入到具体的内部类时就可以写成Inner in = new Outer().new Inner();否则就要把外部类带上。在new对象的时候必须先得到外围类的对象的引用。
2.匿名内部类
下面的例子将返回值的生成和表示这个返回值类型的定义结合在一起,他没有名字。在创建A对象的的时候,A实际是一个接口,并不能直接new对象,因此要实现未实现的方法,实际上就是实现了一个接口的类对象然后被向上转型成父类的引用。
使用匿名内部类时,如要在其内部使用外部定义的对象,那么该参数引用必须是final的。
interface A{
public void method();
}
class AImp implements A{
public void method(){
System.out.println("AImp");
}
}
class Test{
private static A getA(){
// return new A() {
// public void method() {
// System.out.println("Aimp_Test");
// }
// };
return new AImp();
}
public static void main(String[] args) {
getA().method();;
}
}
3.嵌套类
如果不需要内部类对象与其外为对象之间有联系,就可以将内部类声明为static。不同的内部类对象隐式的保存了一个指向它外为对象的引用。嵌套类在创建对象时不需要外围类对象,但是嵌套类里面不能访问外围类中的非静态的属性和方法。
Android中的广播接收者在使用静态声明的时候就要求为静态的嵌套类,不然找不到该类。
class Outer{
private int x;
public static class Inner{
//int y = x;// error
}
Inner in = new Inner();
}
public class Test{
public static void main(String[] args) {
Outer.Inner in = new Outer.Inner();
}
}
Android中如下使用Handler,会警告ThisHandler class should be static or leaks might occur,Handler类应该是静态的,否则会内存泄露,原因就是创建MyHandler这个内部类的时候,还保留了一个对外部类的引用,一般是Activity,一旦activity被销毁,就会出问题。
class MyHandler extends Handler{
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
}
};
};
private Handler handler = new MyHandler();
4.内部类向上转型为接口——暴露/隐藏部分实现
class B{
private void f(){System.out.println("f()");}
private void g(){System.out.println("g()");}
public class AImp{
public void method1(){
f();
}
public void method2(){
g();
}
}
}
public class Test{
public static void main(String[] args) {
B b = new B();
AImp aImp = b.new AImp();
aImp.method1();
aImp.method2();
}
}
由于AImp是public的,因此就可以访问到它,也就能访问他的所有方法。下面使用接口来只暴露method1函数。向上转型为一个接口就可以在这里接口里放想要暴露的函数。
interface A{
void method1();
}
class B{
private void f(){System.out.println("f()");}
private void g(){System.out.println("g()");}
public A getA(){
return new AImp();
}
private class AImp implements A{
public void method1(){
f();
}
public void method2(){
g();
}
}
}
public class Test{
public static void main(String[] args) {
B b = new B();
//AImp aImp = b.new AImp(); // 由于AImp是private的 error
A aImp = b.getA();// b.getA()向上转型,转型为一个接口 就可以在这里接口里放想要暴露的函数。
aImp.method1(); // 只暴露menthod1
// aImp.method2(); // The method method2() is undefined for the type A
}
}