内部类
为什需要内部类?
Think in java中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
内部类允许把一些逻辑相关的类组织在一起,并控制位于内部类的可视性。
从外部类的非静态方法之外的任意位置创建某个内部类的对象,必须指明这个对象的类型:OuterClassName.InnerClassName
生成一个内部类时,对象与外围类之间就有关系,它能访问外围对象的所有成员,而不需要任何条件;当某个外围类的对象创建一个内部类对象时,内部类对象必定会秘密捕获
一个指向外围类对象的引用。
package mypack; public class Sequence{ private Object[] items; private int next=0; public Sequence(int size) { items=new Object[size]; } public void add(Object obj) { if(next<items.length) items[next++]=obj; } private class GeneratorSelector implements Selector{ private int i=0; @Override public boolean end() { // TODO Auto-generated method stub return i==items.length; } @Override public Object current() { // TODO Auto-generated method stub return items[i]; } @Override public void next() { // TODO Auto-generated method stub if(i<items.length) i++; } } public Selector getGenerator() { return new GeneratorSelector(); } public static void main(String[] args) { // TODO Auto-generated method stub Sequence sequence = new Sequence(10); for(int i=0;i<10;i++) sequence.add(Integer.toString(i)); Selector selector = sequence.getGenerator(); while(!selector.end()) { System.out.print(selector.current()+" "); selector.next(); } } }
生成对外部类对象的引用使用:外部类.this
创建某个内部类的对象,必须在new表达式中提供对其他外部类对象的引用
1 package mypack; 2 3 public class Outer { 4 5 public void test() { 6 System.out.println("test"); 7 } 8 public class Inner{ 9 public Outer getOuter() { 10 return Outer.this; 11 } 12 } 13 14 public Inner getInner() { 15 return new Inner(); 16 } 17 18 public static void main(String[] args) { 19 // TODO Auto-generated method stub 20 Outer outer = new Outer(); 21 Inner inner = outer.getInner(); 22 Inner inner2 = outer.new Inner(); 23 inner.getOuter().test(); 24 } 25 26 }
当内部类型上转型为其基类,尤其转型为一个接口时,可以方面的隐藏实现细节,阻止任何依赖与类型的编码
1 package mypack; 2 3 public class Parcel { 4 5 private class ContentsImpl implements Contents{ 6 7 @Override 8 public String test() { 9 // TODO Auto-generated method stub 10 return "a test"; 11 } 12 } 13 14 public Contents getContents() { 15 return new ContentsImpl(); 16 } 17 18 public static void main(String[] args) { 19 Parcel parcel = new Parcel(); 20 Contents contents = parcel.getContents(); 21 System.out.println(contents.test()); 22 } 23 24 }
如果定义一个匿名内部类,希望他使用一个在其外部定义的对象,那么编译器会要求参数引用是final,原因:
1. 这里所说的“匿名内部类”主要是指在其外部类的成员方法内定义,同时完成实例化的类,若其访问该成员方法中的局部变量,局部变量必须要被final修饰。
2. 原因是编译程序实现上的困难:内部类对象的生命周期会超过局部变量的生命周期。局部变量的生命周期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。而内部类对象生命周期与其它类一样:自创建一个匿名内部类对象,系统为该对象分配内存,直到没有引用变量指向分配给该对象的内存,它才会死亡(被JVM垃圾回收)。所以完全可能出现的一种情况是:成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。
3. 如果匿名内部类的对象访问了同一个方法中的局部变量,就要求只要匿名内部类对象还活着,那么栈中的那些它要所访问的局部变量就不能“死亡”。
4. 解决方法:匿名内部类对象可以访问同一个方法中被定义为final类型的局部变量。定义为final后,编译程序的实现方法:对于匿名内部类对象要访问的所有final类型局部变量,都拷贝成为该对象中的一个数据成员。这样,即使栈中局部变量已死亡,但被定义为final类型的局部变量的值永远不变,因而匿名内部类对象在局部变量死亡后,照样可以访问final类型的局部变量,因为它自己拷贝了一份,且与原局部变量的值始终一致。
5、Java 8更加智能:如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final修饰。
1 package mypack; 2 3 public class Parcel { 4 5 public Destination destination(final String dest) { 6 return new Destination() { 7 private String label=dest; 8 public String readLabel() { 9 return label; 10 } 11 }; 12 } 13 14 public static void main(String[] args) { 15 Parcel parcel = new Parcel(); 16 String result=parcel.destination("test").readLabel(); 17 System.out.println(result); 18 } 19 20 }
匿名工厂的应用
package mypack; interface Game{ public boolean move(); } interface Gamefactory{ public Game getGame(); } class chess implements Game{ private chess() {}//私有方法 private int moves=0; private final int MOVES=4; @Override public boolean move() { // TODO Auto-generated method stub System.out.println("Chess move "+moves); return ++moves==MOVES; } public static Gamefactory gameFactory=new Gamefactory() { //static单一工厂,匿名内部类 @Override public Game getGame() { // TODO Auto-generated method stub return new chess(); } }; } public class Games{ public static void playGames(Gamefactory factory) { Game game = factory.getGame(); while(!game.move()); } public static void main(String[] args) { // TODO Auto-generated method stub playGames(chess.gameFactory); } }
Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类
成员内部类
成员内部类是最普通的内部类,是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类
public class OuterClass { private String str; public void outerDisplay(){ System.out.println("outerClass..."); } public class InnerClass{ public void innerDisplay(){ //使用外围内的属性 str = "chenssy..."; System.out.println(str); //使用外围内的方法 outerDisplay(); } } /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */ public InnerClass getInnerClass(){ return new InnerClass(); } public static void main(String[] args) { OuterClass outer = new OuterClass(); OuterClass.InnerClass inner = outer.getInnerClass(); inner.innerDisplay(); } } -------------------- chenssy... outerClass...
局部内部类
内部类,它是嵌套在方法和作用域内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。
方法内:
public class Parcel5 { public Destionation destionation(String str){ class PDestionation implements Destionation{ private String label; private PDestionation(String whereTo){ label = whereTo; } public String readLabel(){ return label; } } return new PDestionation(str); } public static void main(String[] args) { Parcel5 parcel5 = new Parcel5(); Destionation d = parcel5.destionation("chenssy"); } }
作用域内
public class Parcel6 { private void internalTracking(boolean b){ if(b){ class TrackingSlip{ private String id; TrackingSlip(String s) { id = s; } String getSlip(){ return id; } } TrackingSlip ts = new TrackingSlip("chenssy"); String string = ts.getSlip(); } } public void track(){ internalTracking(true); } public static void main(String[] args) { Parcel6 parcel6 = new Parcel6(); parcel6.track(); } }
静态内部类
非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:
1、 它的创建是不需要依赖于外围类的。
2、 它不能使用任何外围类的非static成员变量和方法
public class OuterClass { private String sex; public static String name = "chenssy"; /** *静态内部类 */ static class InnerClass1{ /* 在静态内部类中可以存在静态成员 */ public static String _name1 = "chenssy_static"; public void display(){ /* * 静态内部类只能访问外围类的静态成员变量和方法 * 不能访问外围类的非静态成员变量和方法 */ System.out.println("OutClass name :" + name); } } /** * 非静态内部类 */ class InnerClass2{ /* 非静态内部类中不能存在静态成员 */ public String _name2 = "chenssy_inner"; /* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */ public void display(){ System.out.println("OuterClass name:" + name); } } /** * @desc 外围类方法 * @return void */ public void display(){ /* 外围类访问静态内部类:内部类. */ System.out.println(InnerClass1._name1); /* 静态内部类 可以直接创建实例不需要依赖于外围类 */ new InnerClass1().display(); /* 非静态内部的创建需要依赖于外围类 */ OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2(); /* 方位非静态内部类的成员需要使用非静态内部类的实例 */ System.out.println(inner2._name2); inner2.display(); } public static void main(String[] args) { OuterClass outer = new OuterClass(); outer.display(); } } ---------------- Output: chenssy_static OutClass name :chenssy chenssy_inner OuterClass name:chenssy
参考:
https://www.cnblogs.com/chenssy/p/3388487.html
浙公网安备 33010602011771号