Java内部类详解(二)
局部内部类、成员内部类、匿名内部类、静态内部类。
局部内部类:是指内部类定义在方法或代码块内的类。
1.1 与局部变量一样,不能用public, protected, private和static修饰。
1.2 只能访问外部类的方法或代码块中定义为final类型的局部变量。
1.3 只能在方法或代码块中使用,即只能在方法或代码块当中生成局部内部类的实例并且调用其方法,并不对外界透明。
例子:
package com.learnjava.innerclass;class LocalInner{ int a = 1; public void doSomething() { int b = 2; final int c = 3; // 定义一个局部内部类 class Inner3 { public void test() { System.out.println("Hello World"); System.out.println(a); // 不可以访问非final的局部变量 // error: Cannot refer to a non-final variable b inside an inner // class defined in a different method // System.out.println(b); // 可以访问final变量 System.out.println(c); } } // 创建局部内部类的实例并调用方法 new Inner3().test(); }}public class LocalInnerClassTest{ public static void main(String[] args) { // 创建外部类对象 LocalInner inner = new LocalInner(); // 调用外部类的方法 inner.doSomething(); }}成员内部类:定义在外部类方法之外的类,即外部类的成员。
2.1 可以直接使用外部类的所有成员和方法,不论是静态的,还是非静态的,即使是private的也可以访问。
可直接使用Outer.this表示外部类对象。
2.2 外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取,而不能通过inner.this。例如:
public class Outer {//private Inner inner = new Inner();//private String a = inner.b;//private String a = inner.getB();private String a = new Inner().b;private class Inner {private String b = "11";public String getB() {return b + "22";}}public String getA() {return a;}public static void main(String[] args) {Outer outer = new Outer();System.out.println(outer.getA());}}2.3 其他类要直接创建内部类,必须首先创建外部类,且受访问级别的限制。
Inner inner = (new Outer()).new Inner()
2.4 成员内部类不能含有static的变量和方法(除非定义为static final)。因为成员内部类需要先创建了外部类,才能创建它自己的,了解这一点,就可以明白更多事情,在此省略更多的细节了。
例子:
package com.learnjava.innerclass;class MemberInner{ private int d = 1; private int a = 2; // 定义一个成员内部类 public class Inner2 { private int a = 8; public void doSomething() { // 直接访问外部类对象 System.out.println(d); System.out.println(a);// 直接访问a,则访问的是内部类里的a // 如何访问到外部类里的a呢? System.out.println(MemberInner.this.a); } }}public class MemberInnerClassTest{ public static void main(String[] args) { // 创建成员内部类的对象 // 需要先创建外部类的实例 MemberInner.Inner2 inner = new MemberInner().new Inner2(); inner.doSomething(); }}3.1 就是没有名字的局部内部类。
3.2 与局部内部类不同的是,匿名内部类的类必须是预先定义好的已存在的类或接口。
3.3 匿名内部类隐式地继承了一个父类或者实现了一个接口。
3.4 因为没名字,因而默认只有无参数的构造函数,如果需要参数的,则需要该类有带参数的构造函数。例如:
public class Outer {public static void main(String[] args) {Outer outer = new Outer();Inner inner = outer.getInner("Inner", "gz");System.out.println(inner.getName());}public Inner getInner(final String name, String city) {// 注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final。return new Inner(name, city) {private String nameStr = name;public String getName() {return nameStr;}};}}abstract class Inner {Inner(String name, String city) {System.out.println(city);}abstract String getName();}例子:
package com.learnjava.innerclass;import java.util.Date;public class AnonymouseInnerClass{ @SuppressWarnings("deprecation") public String getDate(Date date) { return date.toLocaleString(); } public static void main(String[] args) { AnonymouseInnerClass test = new AnonymouseInnerClass(); // 打印日期: String str = test.getDate(new Date()); System.out.println(str); System.out.println("----------------"); // 使用匿名内部类 String str2 = test.getDate(new Date() { });// 使用了花括号,但是不填入内容,执行结果和上面的完全一致 // 生成了一个继承了Date类的子类的对象 System.out.println(str2); System.out.println("----------------"); // 使用匿名内部类,并且重写父类中的方法 String str3 = test.getDate(new Date() { // 重写父类中的方法 @Override @Deprecated public String toLocaleString() { return "Hello: " + super.toLocaleString(); } }); System.out.println(str3); }}4.1 就是静态的成员内部类。定义时加上static。
4.2 不能和外部类有相同的名字。
4.3 只可以访问外部类的静态成员和静态方法,包括私有的。
4.4 可以直接引用Outer.Inner,即不需要创建外部类。
Outer.Inner inner = new Outer.Inner();
package com.learnjava.innerclass;class StaticInner{ private static int a = 4; // 静态内部类 public static class Inner { public void test() { // 静态内部类可以访问外部类的静态成员 // 并且它只能访问静态的 System.out.println(a); } }}public class StaticInnerClassTest{ public static void main(String[] args) { StaticInner.Inner inner = new StaticInner.Inner(); inner.test(); }}