内部类(嵌套类)
嵌套类是指被定义在另一个类的内部的类。
嵌套类存在的目的是:只是为它的外部类提供服务;
outer.java里面定义了一个内部类inner,运行时,一旦编译成功,就会生成两个完全不同的.class文件,分别是outer.class和outer$inner.class。
嵌套类分为四种:静态成员类,非静态成员类(成员内部类),匿名类,局部类。
内部类:非静态成员类(成员内部类),匿名类,局部类。
1.静态内部类
1 public class Outer { 2 3 public static String name = "Joe"; 4 private String password = "0806"; 5 6 //静态内部类 7 public static class inner{ 8 public static void print1(){ 9 System.out.println(name); 10 //调用外部类的静态方法 11 outerPrint(); 12 } 13 public void print2(){ 14 System.out.println(name); 15 } 16 } 17 18 public static void outerPrint(){ 19 System.out.println("Outer static method!"); 20 } 21 22 public static void main(String[] args){ 23 //静态内部类的静态方法调用 24 Outer.inner.print1(); 25 //静态内部类的非静态方法调用 26 Outer.inner inner = new Outer.inner(); 27 inner.print2(); 28 } 29 }
输出结果:
Joe
Outer static method!
Joe
通过这个例子可以看出:
♥ 静态内部类中可以有静态方法,也可以有非静态方法;
♥ 静态内部类只能访问其外围类的静态成员和静态方法;
♥ 和普通的类一样,要访问静态内部类的静态方法,可以直接“.”出来,不需要一个实例;
♥ 要访问静态内部类的非静态方法,必须拿到一个静态内部类的实例对象;
♥ 实例化静态内部类:外围类.内部类 xxx = new 外围类.内部类();
可以把静态内部类看作普通的类,只是碰巧被声明在另一个类的内部而已;如果静态内部类被声明为私有的,那么它就只能在外围类的内部才可以访问。
非静态成员类(成员内部类)
成员内部类是最常见的内部类,就是在外部类的基础上按照一般定义类的方式定义类,举个例子:
1 public class Outer { 2 3 public static String name = "Joe"; 4 private String password = "0806"; 5 6 //私有成员内部类 7 private class PrivateInner{ 8 public void print1(){ 9 System.out.println("private " + name); 10 System.out.println("public " + password); 11 //调用外部类的静态方法 12 outerPrint(); 13 } 14 } 15 //公有的成员内部类 16 public class PublicInner{ 17 public void print2(){ 18 String password = "0810"; 19 System.out.println("public " + name); 20 System.out.println("public " + password); 21 //调用外部类的静态方法 22 outerPrint(); 23 } 24 } 25 public static void outerPrint(){ 26 System.out.println("Outer static method!"); 27 } 28 29 public static void main(String[] args){ 30 Outer outer = new Outer(); 31 Outer.outerPrint(); 32 //实例化私有成员内部类 33 Outer.PrivateInner privateInner = outer.new PrivateInner(); 34 privateInner.print1(); 35 //实例化公有成员内部类 36 Outer.PublicInner publicInner = outer.new PublicInner(); 37 publicInner.print2(); 38 } 39 }
输出结果:
Outer static method!
private Joe
public 0806
Outer static method!
public Joe
public 0810
Outer static method!
通过这个例子可以看出:
♥ 成员内部类是依附其外围类而存在的,如果要产生一个成员内部类,必须有一个其外围类的实例;
♥ 成员内部类不可以定义静态方法和静态属性;
♥ 声明为private的成员内部类,只对其外围类可见;声明为public的成员内部类,其他非外围类对其可见;
♥ 成员内部类可以访问外围类的私有属性,如果成员内部类的属性和其外围类的属性重名,则以成员内部类的属性值为准;
♥ 实例化成员内部类:外围类.内部类 xxx = 外围类.new 内部类();
匿名内部类
在多线程的模块中代码,大量使用了匿名内部类,如下:
1 public class Outer { 2 //匿名接口 3 interface Inner{ 4 int getNumber(); 5 } 6 //使用匿名接口 7 public Inner getInner(final int num,String str){ 8 return new Inner() { 9 @Override 10 public int getNumber() { 11 System.out.println(str); 12 return num; 13 } 14 }; /* 注意:分号不能省 */ 15 } 16 //测试 17 public static void main(String[] args){ 18 Outer outer = new Outer(); 19 Inner inner = outer.getInner(4,"nihao"); 20 System.out.println(inner.getNumber()); 21 } 22 }
输出结果:
nihao
4
通过这个例子可以看出:
❤ 匿名内部类没有修饰符;
❤ 当所在方法的形参需要被匿名内部类使用时,该形参必须为final,因为:内部类在编译时会生成一个独立的.class文件,改文件并不在它的外围类中,内部类将传过来的参数通过自己的构造器备份到了自己的内部,这样自己内部方法的调用实际上是自己的属性,而不是外围类方法的参数;简单理解就是:拷贝引用,为了避免引用值发生改变,例如被外围类的方法修改等,而导致内部类得到的值不一致,于是用final修饰让该引用不可变;
❤ 匿名内部类没有构造方法,因为它连名字都没有;
❤ new 匿名内部类;这个类必须先存在;
局部内部类
局部内部类:是指内部类定义在方法和作用域内。
看个例子:
1 public class Outer { 2 private void internalTracking(boolean b) { 3 if (b) { 4 //局部内部类 5 class TrackingSlip { 6 private String id; 7 TrackingSlip(String s) { 8 id = s; 9 } 10 String getSlip() { 11 return id; 12 } 13 } 14 TrackingSlip ts = new TrackingSlip("slip"); 15 String s = ts.getSlip(); 16 } 17 } 18 19 public void track() { 20 //调用方法(含有局部内部类) 21 internalTracking(true); 22 System.out.println("......."); 23 } 24 25 public static void main(String[] args) { 26 Outer p = new Outer(); 27 p.track(); 28 } 29 }
局部内部类也会像其他类一样编译,只是作用域不同而已,只有在该方法或者作用域内才能用,超出作用域或者方法就不可引用。
❤ 局部内部类没有访问修饰符;
❤ 局部内部类要访问外围类的对象或者变量,那么这个变量或者对象必须是final修饰的;
内部类的好处
❤ Java运行实现多个接口,但不允许继承多个类,使用内部类可以解决Java不允许多个继承的问题。在一个类的内部定义一个内部类,让这个内部类继承某个原有的类,而这个内部类又可以访问外围类的属性和方法,这样就相当于多个继承了;
❤ 有效的对外隐藏了自己,增加了自己的私密性;
❤ 使用内部类可以让类与类之间的联系更加紧密;
❤ 有些类知道只会在某个地方使用只使用一次,为这种类创建一个外部类显然没有必要,所以这种就写个内部类用用就可以了;