内部类是java中一个重要但是难以理解其作用的概念。
内部类分为:
1.实例内部类
2.静态内部类
3.局部内部类
4.匿名类
1,2统称为成员内部类,因为它们可以作为一个类的成员而存在。而局部内部类则一般存在于类的成员方法当中。
这些内部类之间分别具有以下一些特点
实例内部类:
1.创建实例内部类的实例时,外部类的实例必须存在,因为实例内部类在创建的时候必须持有一个指向外部类的实例的引用this。
2.实例内部类可以访问外部类的所有成员
3.实例内部类中不能定义静态成员,而只能定义动态成员。这个特点跟局部内部类是一样的。
4.实例内部类跟外部类有同名成员的时候,this.a表示实例内部类的a,Outer.this.a表示外部类的a。
静态内部类:
1.由于静态内部类在创建的时候不会持有外部类实例的引用,所以在初始化静态内部类的时候不要求创建相应外部类的实例。如:Outer.Inner inner = new Outer.Inner();
2.静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,就必须通过外部类的实例去访问。
3.与实例内部类跟局部内部类不同的是,静态内部类可以有静态成员变量。
4.客户类可以通过完整的类名去访问静态内部类的静态成员变量(废话....),如:Outer.Inner.a=1;
局部内部类:
1.局部内部类的可见范围只在方法内,但是和实例内部类一样,可以访问外部类的所有成员。
2.不包含静态成员。
一个类在继承一个外部类的内部类的时候,必须提供相应的构造方法,通过传递一个外部类的实例给构造方法来初始化该类。(真是拗口。。。)这一点上java编译器会做检查。
子类跟父类如果内部类重名的话是不冲突的,因为这两个内部类分处不同的命名空间。
匿名类:
1.匿名类没有构造方法,但是会调用父类的构造方法。如果要初始化匿名类,可以提供一段初始化代码,在执行了“父类”的构造方法之后会执行该初始化代码。如:
A a = new A(v){
{System.out.println("Initialize instance");}
}
这种说法是不是很有继承的感觉?“父类”~因为这个类A你不能凭空去捏造,它必须已经存在。
2.事实证明:匿名类无法访问“父类”的成员变量和方法,只能覆写方法,但是在覆写方法内可以用super.xx()访问到“父类”的xx()方法。
3.匿名类除了可以继承类外,还可以实现接口。(果真是继承哦~)如:
Thread t = new Thread(Runnable(){
public void run(){
System.out.println("run");
}
}
4.跟前面的内部类一样,匿名类可以访问外部类的成员。
匿名类的一个最大特点是它只能创建一次,所以一个类你只需要用到一次的话,你最好弄成匿名类。
内部类的用途:
1.封装类型
(1)顶层类只能使public 和 默认的访问级别,所以考虑到封装,必要的部分可以放到内部类,因为它支持public, protected, private和默认四种访问级别。
(2)如果一个类仅仅是为某一个方法提供服务,那么可以将其作为一个局部内部类放到一个方法中,这样就可以做到封装了。
2.直接访问外部类的成员。比如外部类的成员a声明为private,因为不希望a在类以外被修改,那么可以弄一个内部类来修改a。
3.回调
我觉得这是内部类最巧妙地一个用途。这里引用下书上的代码例子:
第一段代码是一个具有相同方法名的一个接口和一个类。接口中的adjust方法用来调节温度,而类中的adjust方法则用来调节风速。
public interface Adjustable{ public void adjust(int temperature); } public class Base{ private int speed; public void adjust(int speed){ this.speed=speed; } }
那如果有一个Sub类同时要具有两种功能怎么办呢?你可能会这样做:public class Sub extends Base implements Adjustable{ private int temperature; public void adjust(int temperature){ this.temperature = temperature; } }
然后这样做虽然实现了调节温度,但是会覆盖掉Base中的调节风速的方法。要兼具两者,则需要利用到内部类。public class Sub extends Base { private int temperature; private void adjustTemperature(int temperature){ this.temperature = temperature; } private class Closure implements Adjustable{ public void adjust(int temperature){ adjustTemperature(temperature); } } public Adjustable getCallbaAdjustable(){ return new Closure(); } }
这样你会发现调节风速的方法并没有被覆盖,而如果你需要调节温度呢?只需:Sub sub = new Sub(); Adjustable ad = sub.getCallbackAdjustable(); ad.adjust(10); //调节温度 sub.adjust(10); //调节风速
书上有句话解释地很透彻:回调实质上是指一个类(Sub)尽管实现了某个功能,但是并没有提供相应的接口,客户类可以通过这个类的内部类实现的接口来获得这种功能。这个内部类本身并没有提供真正的实现,仅仅调用了外部类的实现。
这些大概就是内部类需要注意的地方,感觉还是挺复杂的。不过最后回调的使用还是java设计中的亮点啊