如果外部类成员变量/内部类成员变量与内部类方法的局部变量同名,则可通过使用this和外部类类名.this作为限定区分。
eg.
public class DiscernVariable { private String prop = "OuterClass.Feild"; private class InClass { private String prop = "InnerClass.Feild"; public void info() { String prop = "InnerClass.Variable"; System.out.println(DiscernVariable.this.prop); System.out.println(this.prop); System.out.println(prop); } } public void test() { InClass in = new InClass(); in.info(); } public static void main(String[] args) { new DiscernVariable().test(); } }
Output:
OuterClass.Feild
InnerClass.Feild
InnerClass.Variable
非静态内部类的成员可以访问外部类的private成员,但反过来就不成立了。非静态内部类的成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类的成员,则必须显式创建非静态内部类对象来调用访问其实例成员。
非静态内部类不允许有静态成员。
提问:非静态内部类对象和外部类对象的关系是怎么样的?
回答:非静态内部类对象必须寄存在外部类对象里,而外部类对象则不一定有非静态内部类对象寄存其中。简单地说,如果存在一个非静态内部类对象,则一定存在一个被它寄存的外部类对象。但外部类对象存在时,外部类对象里不一定寄存了非静态内部类对象。因此外部类对象访问非静态内部类成员时,可能非静态普通内部类对象根本不存在!而非静态内部类对象访问外部类成员时,外部类对象一定存在。
- 在外部类以外使用非静态内部类
在外部类以外的地方定义内部类变量的语法格式:
OuterClass.InnerClass varName;
在外部类以外的地方创建非静态内部类实例的语法:
OuterClass.new InnerClass();
class Out { class In { public In(String msg) { System.out.println(msg); } } } public class CreateInnerInstance { public static void main(String[] args) { Out.In in = new Out().new In("test message"); } }
当创建一个子类时,子类构造器总会调用父类的构造器,因此在创建非静态内部类的子类时,必须保证让子类构造器可以调用非静态内部类的构造器,调用非静态内部类的构造器时,必须存在一个外部类对象。
eg.
class Out { class In { public In(String msg) { System.out.println(msg); } } } public class SubClass extends Out.In { public SubClass(Out out) { out.super("Hello"); } }
非静态内部类In类的构造器必须使用外部类对象来调用,代码中super代表调用In类的构造器,而out则代表外部类对象。
- 在外部类以外使用静态内部类
class StaticOut { static class StaticIn { public StaticIn() { System.out.println("Static innerClass constructor"); } } } public class CreateStaticInnerInstance { public static void main(String[] args) { StaticOut.StaticIn staticIn = new StaticOut.StaticIn(); } }
从上面代码可以看出,不管是静态内部类还是非静态内部类,他们声明变量的语法完全一样。区别只是在创建内部类对象时,静态内部类只需使用外部类即可调用构造器,而非静态内部类必须使用外部类对象来调用构造器。
创建静态内部类的子类:
public class StaticSubClass extends StaticOut.staticIn()
当定义一个静态内部类时,其外部类非常像一个包空间。
- 局部内部类
public class LocalInnerClass { public static void main(String[] args) { class InnerBase { int a; } class InnerSub extends InnerBase { int b; } InnerSub is = new InnerSub(); is.a = 5; is.b = 6; System.out.println(is.a + ":" + is.b); } }
编译后生成 LocalInnerClass.class, LocalInnerClass$1InnerBase.class和LocalInnerClass$1InnerSub.class.多了一个数字的原因是同一个类里不可能有两个同名的成员内部类,但同一个类里有可能有两个以上同名的局部内部类(处于不同的方法中)。
- 匿名内部类
匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。
匿名内部类不能使抽象类,且不能定义构造器,但可以定义实例初始化块。
interface Product { public double getPrice(); public String getName(); } public class AnonymousTest { public void test(Product p) { System.out.println("name:" + p.getName() + ", price:" + p.getPrice()); } public static void main(String[] args) { AnonymousTest ta = new AnonymousTest(); ta.test(new Product() { public double getPrice() { return 567.8; } public String getName() { return "AGP"; } }); } }
如果匿名内部类需要访问外部类的局部变量,则必须使用final修饰符来修饰外部类的局部变量,否则系统会报错。
interface A { void test(); } public class ATest { public static void main(String[] args) { final int age = 0; A a = new A() { public void test() { System.out.println(age); } }; } }