《疯狂Java讲义》(十五)---- 内部类

  如果外部类成员变量/内部类成员变量与内部类方法的局部变量同名,则可通过使用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);
            }
        };
    }
}
原文地址:https://www.cnblogs.com/IvySue/p/6323583.html