(Thinking in Java)内部类的简单使用
1. 成员内部类
1. 最基本使用
1 public class Demo { 2 class Contents{ 3 private int i=11; 4 public int value(){ 5 return i; 6 } 7 } 8 9 class Destination{ 10 private String label; 11 Destination(String whereTo){ 12 label=whereTo; 13 } 14 String readLabel(){ 15 return label; 16 } 17 } 18 19 public void ship(String dest){ 20 Contents c=new Contents(); 21 Destination d=new Destination(dest); 22 System.out.println(d.readLabel()); 23 } 24 25 public static void main(String[] args) { 26 Demo d=new Demo(); 27 d.ship("Tasmania"); 28 } 29 }
2.内部类可以访问外部类的成员
内部类可以访问外部类的成员变量。如下:
1 public class Demo { 2 private Object[] items; 3 private int next = 0; 4 5 public Demo(int size) { 6 items = new Object[size]; 7 } 8 9 public void add(Object x) { 10 if (next < items.length) { 11 items[next++] = x; 12 } 13 } 14 15 private class SequenceSelector implements Selector { 16 private int i = 0; 17 18 public boolean end() { 19 return i == items.length; 20 } 21 22 public Object current() { 23 return items[i]; 24 } 25 26 public void next() { 27 if (i < items.length) { 28 i++; 29 } 30 } 31 } 32 33 public Selector selector() { 34 return new SequenceSelector(); 35 } 36 37 public static void main(String[] args) { 38 Demo d = new Demo(10); 39 for (int i = 0; i < 10; i++) { 40 d.add(Integer.toString(i)); 41 } 42 Selector selector = d.selector(); 43 while (!selector.end()) { 44 System.out.print(selector.current() + " "); 45 selector.next(); 46 } 47 } 48 } 49 50 interface Selector { 51 boolean end(); 52 53 Object current(); 54 55 void next(); 56 }
因为在创建内部类对象的时候,内部类对象会捕获一个指向外部类对象的引用。访问外部类成员的时候,就是用这个引用来获取外部类成员的。内部类中也可以取得这个外部类对象引用。举例如下:
1 public class DotThis{ 2 void f(){ 3 System.out.println("DotThis.f()"); 4 } 5 class Inner{ 6 public DotThis outer(){ 7 return DotThis.this; 8 //A plain "this" would be Inner's this 9 } 10 } 11 12 public Inner inner(){ 13 return new Inner(); 14 } 15 16 public static void main(String[] args) { 17 DotThis dt=new DotThis(); 18 DotThis.Inner dti=dt.inner(); 19 dti.outer().f(); 20 } 21 }
当要在其他类中创建一个内部类对象的时候,可以使用.new语法。
public class DotNew{ public class Inner{ } public static void main(String[] args){ Inner dni=new DotNew().new Inner(); } }
当创造内部类对象的时候,如果这个内部类不是嵌套类(静态内部类),那么就必须要通过外部类对象,才能创建这个内部类对象,为什么呢,之前说过,因为这个内部类对象要获取外部类的引用啊。
并且在存在多个内部类的时候,多个内部类之间可以互相创建对象。例子就不举了。
小结:现在所说的都是成员内部类,其实内部类没那么复杂,既然叫做成员内部类了,他就只是类的成员罢了。他也可以带修饰符,他的修饰符和其他普通的成员变量的修饰符的意义也没有什么不同。
3. 内部类权限修饰符
当内部类被private修饰的时候,该类只能被外部类内的方法使用,其他类不能获取该内部类的引用,因为是private的,所以其他类根本不知道存在一个这样的类。当然也可以作为一个成员变量使用,但是如果作为成员变量,则其他类并不能直接创建内部类的引用,需要用其他手段获取该引用,如下:
class Outer{ Inner in; private class Inner implements a_interface{ void show(){ System.out.println("123"); } } } interface a_interface{ void show(); } class test{ //Inner in=new Outer().in;这是错误的,因为test并不知道Outer类有一个Inner内部类,因为是私有的 a_interface in=new Outer().in;//可以运用向上转型的方法获取private修饰的内部类。 }
小结:其实这也很好记,无论是public还是private,修饰到内部类上的时候,和他们修饰普通的成员变量(如string,int之类)的时候没什么不同,规则都一样,public就都能使用,private就类内可以用。所以规则就记住三条就好:1.先考虑外部类的权限,是否可以获取一个外部类对象。2.创建成员内部类对象的时候需要外部类对象。3.考虑内部类的权限,是否可以获取这样的一个内部类对象(或者说,在外部知不知道有这样一个内部类)。
2. 方法和作用域内的内部类
当我们需要解决一个复杂的问题,想创建一个类来辅助解决问题,但是不希望这个类是公共可用的,甚至不希望在外部类之内的其他地方可以访问到这个辅助类。我们可以运用方法内的内部类
1 public class Outer { 2 public InterfaceDemo get_InterfaceDemo(String s) { 3 class InterfaceDemoTool implements InterfaceDemo { 4 private String label; 5 6 private InterfaceDemoTool(String label) { 7 this.label = label; 8 } 9 10 public String readLabel() { 11 return label; 12 } 13 } 14 15 return new InterfaceDemoTool(s); 16 } 17 18 public static void main(String[] args) { 19 Outer o = new Outer(); 20 InterfaceDemo i = o.get_InterfaceDemo("123"); 21 } 22 } 23 24 interface InterfaceDemo { 25 String readLabel(); 26 }
当然在方法中还可以定义多个内部类,并且这些内部类之间的关系和普通一个Java文件中多个类之间的关系好像没什么不同。也可以相互继承和创建对象。另外在方法中的内部类不能加private等权限修饰符,只能加abstract和final修饰符。
另外也可以在某个作用域内创建内部类对象
1 if(a==b){ 2 class inner{ 3 } 4 new inner(); 5 }
上面的例子中,在if外就不能知道有这么个inner类了,他的作用域只在{…}之中,同理,在方法内定义的内部类,在方法外也不能知道存在这么个类,因为这个内部类的作用域只在这个方法内。
3.匿名内部类
下面这块代码中get_inner()的意思是,创建一个继承自InnerFather的匿名类对象,并且自动向上转型为InnerFather后返回。
1 public class Outer { 2 public InnerFather get_inner() { 3 return new InnerFather() { 4 void print(){ 5 System.out.println("Inner_Override"); 6 } 7 }; 8 } 9 10 class InnerFather { 11 InnerFather() { 12 13 } 14 void print(){ 15 System.out.println("InnerFather"); 16 } 17 } 18 19 public static void main(String[] args) { 20 Outer o = new Outer(); 21 InnerFather i = o.get_inner(); 22 i.print(); 23 } 24 }
当然这只是有无参构造函数,当父类只有一个含参构造函数的时候,我们可以这样向匿名内部类传入一个构造函数参数。
1 public class Outer { 2 public InnerFather get_inner(int i) { 3 return new InnerFather(i) { 4 void print(){ 5 System.out.println("Inner_Override"); 6 } 7 }; 8 } 9 10 class InnerFather { 11 InnerFather(int i) { 12 13 } 14 void print(){ 15 System.out.println("InnerFather"); 16 } 17 } 18 19 public static void main(String[] args) { 20 Outer o = new Outer(); 21 InnerFather i = o.get_inner(10); 22 i.print(); 23 } 24 }
可以通过构造代码块来实现匿名内部类的自定义的构造函数
abstract class Base { public Base(int i) { System.out.println("Base constructor"); } public abstract void f(); } public class AnonymousConstructor { public static Base getBase(int i){ return new Base(i){ {System.out.println("AnonymousConstructor constructor");} public void f(){ } }; } public static void main(String[] args) { Base base = getBase(47); } }
(书上说,如果传入了新的对象,就比如下面例子中的s_in,这个s_in就必须是final的,但是我实验了一下发现并不用啊,我也没太搞懂。)
1 abstract class Base { 2 public Base(int i) { 3 System.out.println("Base constructor"); 4 } 5 6 public abstract void f(); 7 } 8 9 public class AnonymousConstructor { 10 public static Base getBase(int i,String s_in){ 11 return new Base(i){ 12 {System.out.println("AnonymousConstructor constructor");} 13 String s=s_in; 14 public void f(){ 15 } 16 }; 17 } 18 19 public static void main(String[] args) { 20 Base base = getBase(47,"hello"); 21 } 22 }
4.嵌套类
嵌套类指的是被static修饰的内部类。这意味着:1.创建嵌套类对象不需要外部类对象。2.不能再嵌套类对象之中访问非静态的外围类对象。普通内部类的成员和方法只能放在类的外部层次上(这句话我没搞懂= =),所以普通内部类不能有static的成员和方法。但是嵌套类可以有。
public class Outer { static class Inner{ static int i=5; } public static void main(String[] args) { Inner i=new Outer.Inner(); } }
可以从上面的例子看到,在创建这个嵌套类对象的时候,并没有像最开始那样,用一个外部类对象来创建这个内部类对象。其实这和静态方法差不多。
可以在接口内部定义内部类,而且他们即使没有static修饰,也会自动变成public static的。
1 public interface ClassInInterface { 2 void howdy(); 3 class Test implements ClassInInterface{ 4 public void howdy(){ 5 System.out.println("howdy!"); 6 } 7 public static void main(String[] args) { 8 new Test().howdy(); 9 } 10 } 11 }
书上有句话说的很好,在开发的时候建议在每个类中都写一个main方法测试,但是这又必须带着那些已经编译过的额外代码,所以我们可以用嵌套类放置测试代码。
1 public class Outer { 2 public void f(){ 3 System.out.println("I need to be tested"); 4 } 5 6 public static class Tester{ 7 public static void main(String[] args) { 8 Outer o=new Outer(); 9 o.f(); 10 } 11 } 12 }
当然以上两段代码如果是在eclipse上运行的话,需要设置一下运行的main函数在哪,否则会报错

5.多层内部类嵌套
纸老虎,爱有几层有几层,反正只要是外部类的东西,不管哪层外部类,都能访问到。
1 public class Outer { 2 void f(){ 3 System.out.println("hello"); 4 } 5 class Inner1{ 6 void g(){ 7 System.out.println("java"); 8 } 9 class Inner2{ 10 void h(){ 11 f(); 12 g(); 13 } 14 } 15 } 16 public static void main(String[] args) { 17 Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2(); 18 in2.h(); 19 } 20 }
下面是个好玩的
public class Outer { void f(){ System.out.println("hello"); } class Inner1{ void f(){ System.out.println("java"); } class Inner2{ void h(){ f(); } } } public static void main(String[] args) { Outer.Inner1.Inner2 in2=new Outer().new Inner1().new Inner2(); in2.h(); } }
最后打印结果是java。
大概就这么多吧,以后如果还有新东西再补。

浙公网安备 33010602011771号