提起java内裤类(innerClass)不少人不太熟悉,实际上相似的概念在c++里面也有,那就是嵌套类(Nested Class),关于这俩者的区别,在下文中会有对比。内部类从表面上看,就是在类中定义了一个类(下文能够看到,内部类能够在不少地方定义),而实际上并无那么简单,乍看上去内部相似乎有些多余,他的用处可能对于初学者来讲并非那么显著,可是随着对他的深刻了解,你会发现java的设计者在内裤类上面的确是用心良苦。学会使用内部类,是掌握java高级编程的一部分,他可让你更优雅的设计你的程序结构。下面从如下几个方面来介绍:java
第一次见面: c++
public class TestInnerClass{ public static void main(String args[]){ Goods good = new Goods(); Contents content = good.dest(); System.out.println(content.value()); Destination destination = good.cont("BeiJing"); System.out.println(destination.readLabel()); } } interface Contents{ int value(); } interface Destination{ String readLabel(); } class Goods{ private class Content implements Contents{ private int i = 11; public int value(){ return i; } } protected class GDestination implements Destination{ private String label; private GDestination(String whereTo){ label = whereTo; } public String readLabel(){ return label; } } public Content dest(){ return new Content(); } public GDestination cont(String s){ return new GDestination(s); } }
在这个例子里,类Content和GDestination被定义在了Goods类内部,而且分别有着private和protected修饰符来控制访问级别。Content表明着Goods的内容,而GDestination表明着Goods的目的地。在后面的main()方法里面,直接用Contents content 和Destination destination进行操做,你甚至连这俩个内部类的名字都没有见过,这样,内部类的好处就体现出来了,隐藏你不想让别人知道的操做,即封装性。程序员
同时,咱们也发现了外部类做用范围以外获得内部类对象的第一个方法,那就是利用其外部类的方法建立并返回。上例中dest()和cont()方法就是这么作的。那么,还有没有别的方法呢?固然有,其语法格式以下:编程
OuterClass outerObject = new OuterClass(Constructor parameters);数组
OuterClass .InnerClass innerObject = outerObject.new InnerClass(Constructor parameters); //固然这时候要把内部类的构造行数改成public,不能是private了函数
注意在建立非静态内部类对象时,必定要先建立起相应的外部类对象。至于缘由,也就引出了咱们的下一个话题 非静态内部类对象有着指向其外部类对象的引用,对刚才的例子稍做修改:this
public class TestInnerClass{ public static void main(String args[]){ Goods good = new Goods(); Contents content = good.dest(); System.out.println(content.value()); } } interface Contents{ int value(); } interface Destination{ String readLabel(); } class Goods{ private int valueRate = 2; private class Content implements Contents{ private int i = 11 * valueRate; public int value(){ return i; } } protected class GDestination implements Destination{ private String label; public GDestination(String whereTo){ label = whereTo; } public String readLabel(){ return label; } } public Content dest(){ return new Content(); } public GDestination cont(String s){ return new GDestination(s); } }
在这里咱们给Goods添加了一个新的private 成员变量 valueRate,意义是货物的价值系数,在内部类Content的方法value()计算价值时把他乘上。咱们发现,value()能够访问valueRate,这也是内部类的第二个好处,一个内部类对象能够访问建立他的外部类对象的内容,甚至包括私有变量!这是一个很是有用的特性,为咱们在设计时提供了更多的思路跟捷径。要想实现这个功能,内部类对象必须有指向外部类对象的引用。spa
java编译器在建立内部类对象时,隐式的把其余外部类的对象也传了进来并一直保存着。这样就使得内部类的对象始终能够访问其外部类的对象。同时这也是为何在外部类做用范围以外想要建立内部类对象必须建立起外部类对象的缘由。设计
有人会问,若是一个外部类的成员变量与内部类的成员变量同名,也即外部类的成员变量被屏蔽了,怎么办?没事,java里面有以下格式表达外部类的引用:code
outerClass.this
有了它,咱们就不怕这种屏蔽的状况了。
静态内部类
和普通类同样,内部类也能够由静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部类的引用。这实际上和c++中的嵌套类很相像了。java内部类与c++嵌套类最大的不一样就是在因而否有指向外部类引用这一点上,固然从设计的细节及其余的一些角度来说还有一些区别。
除此以外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套能够不仅一层)。不过静态内部类中能够拥有者一切。这也算俩者的第二个区别吧。
局部内部类:
是的,java内部类能够定义在一个方法里面甚至一个代码块以内。
public class TestInnerClass{ public static void main(String args[]){ Goods good = new Goods(); Destination destination = good.dest("beijing"); System.out.println(destination.readLabel()); } } interface Destination{ String readLabel(); } class Goods{ public Destination dest(String s){ class GDestination implements Destination{ private String label; public GDestination(String whereTo){ label = whereTo; } public String readLabel(){ return label; } } return new GDestination(s); } }
上面就是这样一个例子。在方法dest()中咱们定义了一个内部类,最后由这个方法返回这个内部类。若是咱们在建立一个对象的时候仅须要建立一个对象而且创给外部,就能够这样作。固然,定义在方法中的内部类可使设计多样化,用途毫不仅仅在这一点。
下面有一个更怪的例子:
public class TestInnerClass{ private void into(boolean b){ if(b){ class GDestination { private String label; public GDestination(String whereTo){ label = whereTo; } public String readLabel(){ return label; } } GDestination destination = new GDestination("beijing"); System.out.println(destination.readLabel()); } } public void dest(boolean b){ into(b); } public static void main(String args[]){ TestInnerClass inner = new TestInnerClass(); inner.dest(true); } }
你不能再if()语句以外建立这个内部类的对象,应为这已经超出了他的做用域。不过在编译的时候,内部类GDestination和其余类同样同时被编译,不过他有他本身的做用域。超出了这个范围就无效,除此以外和其余的内部类并无区别。
匿名内部类
java的匿名内部类看上去有些古怪,不过如同匿名数组同样,单你只须要建立一个类的对象而用不上他的名字的时候,使用内部类看上去可使代码更简洁清楚。他的语法规则是这样的:
new interfaceName(){...................};或:new superClassName(){................................};
下面接着前面继续举例子:
public class TestInnerClass{ public Contents cont(){ return new Contents(){ private int i = 11; public int value(){ return i; } }; } public static void main (String args[]){ TestInnerClass test = new TestInnerClass(); Contents content = test.cont(); System.out.println(content.value()); } } interface Contents{ public int value(); }
这里的cont()使用匿名内部类直接返回了一个实现了接口Contents的类对象,看上去的确十分简洁。
在java的事件处理机制的匿名适配器中,匿名内部类被大量使用。例如在关闭窗口时附加上这样一段代码:
frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } });
有一点须要注意的是,匿名内部类因为没有名字,因此他没有构造函数(可是若是这个匿名内部类继承了一个只含有带参构造函数的父类,建立他的时候必须带上这些参数,并在实现的过程当中使用super关键字调用相应的内容)。若是你想初始化他的成员变量,有下面几种方法:
若是是在一个方法的匿名内部类,能够利用这个方法传进你想要的参数,不过记住,这些参数必须声明为final 。
将匿名内部类改形成有名字的局部内部类,这样他就能够拥有构造函数了。
在这个匿名内部类中使用初始化代码块。
为何须要内部类?
java内部类有什么好处?为何须要内部类?
首先举一个简单的例子,若是你想实现一个接口,可是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你能够建立一个内部类实现这个接口。因为内部类对于外部类的全部内容都是能够访问的,因此这样作能够完成你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法不就能够了吗?
的确,以此做为设计内部类的理由,没有说服力。
真正的缘由是这样的,java中的内部类和接口加在一块儿,能够解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,c++的多继承设计起来很复杂,而java经过内部类+接口,能够很好的实现多继承的效果。