内部类(Inner class)
将相关的类组织在一起,从而降低了命名空间的混乱。
一个内部类可以定义在另一个类里,也可以定义在函数里,甚至可以作为一个表达式的一部分。
内部类中不能定义静态成员。(静态成员不是对象的特征,只是为了找一个容身之所,所以需要放到一个类中而已,无需放到内部类中)
java中的内部类分为四种:
静态内部类static inner class(static nested class)
成员内部类member inner class
局部内部类local inner class
匿名内部类 anonymous inner class
静态内部类static inner class
最简单的内部类形式。
定义时加上static关键字
不能和外部类有相同的名字
被编译成一个完全独立的 .class文件,名称为OuterClass$InnerClass.class的形式。
只可以访问外部类的静态成员和静态方法,包括私有静态成员和方法。
生成静态内部类对象的方式为:
OuterClass.InnerClass inner=new OuterClass.InnerClass();
1 静态内部类使用测试 2 3 package com.learnjava.innerclass; 4 5 class StaticInner 6 { 7 private static int a = 4; 8 9 // 静态内部类 10 public static class Inner 11 { 12 public void test() 13 { 14 // 静态内部类可以访问外部类的静态成员 15 // 并且它只能访问静态的 16 System.out.println(a); 17 } 18 19 } 20 } 21 22 public class StaticInnerClassTest 23 { 24 25 public static void main(String[] args) 26 { 27 StaticInner.Inner inner = new StaticInner.Inner(); 28 inner.test(); 29 } 30 }
成员内部类member inner class
成员内部类也是定义在另一个类中,但是定义时不用static修饰。
成员内部类和静态内部类可以类比为非静态的成员变量和静态的成员变量。
成员内部类就像一个实例变量。
它可以访问它的外部类的所有成员变量和方法,不管是静态的还是非静态的都可以。
在外部类里面创建成员内部类的实例:
this.new InnerClass();
在外部类之外创建内部类的实例:
(new OuterClass()).new InnerClass();
在内部类里访问外部类的成员:
OuterClass.this.member
1 成员内部类使用测试 2 3 package com.learnjava.innerclass; 4 5 class MemberInner 6 { 7 private int d = 1; 8 private int a = 2; 9 10 // 定义一个成员内部类 11 public class Inner2 12 { 13 private int a = 8; 14 15 public void doSomething() 16 { 17 // 直接访问外部类对象 18 System.out.println(d); 19 System.out.println(a);// 直接访问a,则访问的是内部类里的a 20 21 // 如何访问到外部类里的a呢? 22 System.out.println(MemberInner.this.a); 23 } 24 25 } 26 27 } 28 29 public class MemberInnerClassTest 30 { 31 32 public static void main(String[] args) 33 { 34 35 // 创建成员内部类的对象 36 // 需要先创建外部类的实例 37 MemberInner.Inner2 inner = new MemberInner().new Inner2(); 38 39 inner.doSomething(); 40 } 41 }
局部内部类Local Inner Class
局部内部类定义在方法中,比方法的范围还小。是内部类中最少用到的一种类型。
像局部变量一样,不能被public,protected,private和static修饰。
只能访问方法定义中的final类型的局部变量。
局部内部类在方法中定义,所以只能在方法中使用,即只能在方法当中生成局部内部类的实例并且调用其方法。
1 局部内部类使用测试 2 3 package com.learnjava.innerclass; 4 5 class LocalInner 6 { 7 int a = 1; 8 9 public void doSomething() 10 { 11 int b = 2; 12 final int c = 3; 13 // 定义一个局部内部类 14 class Inner3 15 { 16 public void test() 17 { 18 System.out.println("Hello World"); 19 System.out.println(a); 20 21 // 不可以访问非final的局部变量 22 // error: Cannot refer to a non-final variable b inside an inner 23 // class defined in a different method 24 // System.out.println(b); 25 26 // 可以访问final变量 27 System.out.println(c); 28 } 29 } 30 31 // 创建局部内部类的实例并调用方法 32 new Inner3().test(); 33 } 34 } 35 36 public class LocalInnerClassTest 37 { 38 public static void main(String[] args) 39 { 40 // 创建外部类对象 41 LocalInner inner = new LocalInner(); 42 // 调用外部类的方法 43 inner.doSomething(); 44 } 45 46 }
匿名内部类Anonymous Inner Class
匿名内部类就是没有名字的局部内部类,不使用关键字class,extends,implements,没有构造方法。
匿名内部类隐式地继承了一个父类或者实现了一个接口。
匿名内部类使用的比较多,通常是作为一个方法参数。
1 匿名内部类使用测试 2 3 package com.learnjava.innerclass; 4 5 import java.util.Date; 6 7 public class AnonymouseInnerClass 8 { 9 10 @SuppressWarnings("deprecation") 11 public String getDate(Date date) 12 { 13 return date.toLocaleString(); 14 15 } 16 17 public static void main(String[] args) 18 { 19 AnonymouseInnerClass test = new AnonymouseInnerClass(); 20 21 // 打印日期: 22 String str = test.getDate(new Date()); 23 System.out.println(str); 24 System.out.println("----------------"); 25 26 // 使用匿名内部类 27 String str2 = test.getDate(new Date() 28 { 29 });// 使用了花括号,但是不填入内容,执行结果和上面的完全一致 30 // 生成了一个继承了Date类的子类的对象 31 System.out.println(str2); 32 System.out.println("----------------"); 33 34 // 使用匿名内部类,并且重写父类中的方法 35 String str3 = test.getDate(new Date() 36 { 37 38 // 重写父类中的方法 39 @Override 40 @Deprecated 41 public String toLocaleString() 42 { 43 return "Hello: " + super.toLocaleString(); 44 } 45 46 }); 47 48 System.out.println(str3); 49 } 50 }
生成的 .class文件中,匿名内部类会生成OuterClass$1.class文件,数字根据是第几个匿名内部类而类推。