zoukankan      html  css  js  c++  java
  • 《疯狂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);
                }
            };
        }
    }
  • 相关阅读:
    【洛谷】P2880 [USACO07JAN]平衡的阵容Balanced Lineup(st表)
    【洛谷】P1052 过河(状压dp)
    【洛谷】P1541 乌龟棋(四维背包dp)
    【BZOJ】4721: [Noip2016]蚯蚓 / 【洛谷】P2827 蚯蚓(单调队列)
    【洛谷】P1064 金明的预算方案(dp)
    【洛谷】P3908 异或之和(异或)
    【洛谷】P2434 [SDOI2005]区间(暴力)
    【洛谷】P2694 接金币(排序)
    【BZOJ】1012: [JSOI2008]最大数maxnumber /【洛谷】1198(线段树)
    【游记】noip2017酱油记
  • 原文地址:https://www.cnblogs.com/IvySue/p/6323583.html
Copyright © 2011-2022 走看看