Java入门-内部类


非静态内部类

public class Cow {
    private double weight;

    public Cow() {
    }

    public Cow(double weight) {
        this.weight = weight;
    }
    // 定义一个非静态内部类
    private class CowLeg {
        private double length;
        private String color;

        public CowLeg() {}
        public CowLeg(double length, String color) {
            this.length = length;
            this.color = color;
        }
        public double getLength() {
            return this.length;
        }
        public void setLength(double length) {
            this.length = length;
        }
        public String getColor() {
            return this.color;
        }
        public void setColor(String color) {
            this.color = color;
        }
        public void info() {
            System.out.println("当前牛腿的颜色是 " + this.color + ", 长 " + this.length);
            // 直接访问外部类的 private 修饰的成员变量
            System.out.println("该牛腿所属的奶牛重: " + weight);
        }
    }

    public void test() {
        CowLeg cl = new CowLeg(1.12, "黑白相间");
        cl.info();
    }
    public static void main(String[] args) {
        Cow cow = new Cow(378.9);
        cow.test();
    }
}

在非静态内部类里可以直接访问外部类的 private 成员,这是因为在非静态内部类对象里,保存了一个它所寄生的外部类对象的引用。如下图:

如果外部类成员变量、内部类成员变量与内部类里方法的局部变量名同名

  • 直接访问局部变量

  • this,访问内部类实例的变量

  • 外部类类名.this.varName 访问外部类实例变量

外部类不能直接访问非静态内部类的成员,无论非静态内部类的成员是什么修饰符修饰的。只能显示创建非静态内部类对象来访问其实例成员。

静态内部类

如果用 static 修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。因此也叫做类内部类。即静态内部类是外部类的一个静态成员。

静态内部类可以包含静态成员,也可以包含非静态成员。

静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。

外部类依然不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。


在外部类以外的地方访问内部类(包括静态和非静态两种),则内部类不能使用 private 修饰,private 修饰的内部类只能在外部类内部使用。对于使用其他访问修饰符的内部类,按照访问修饰符范围访问。

在外部类之外使用非静态内部类

由于非静态内部类的对象必须寄生在外部类的对象里,因此在创建非静态内部类对象之前,必须先创建其外部类对象。

示例代码,如下:

public 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 Msg");
        /*
        上面代码可以改为如下三行代码

        使用 OutterClass.InnerClass 的形式定义内部类变量
        Out.In in;
        创建外部类实例,非静态内部类实例将寄生在该实例中
        Out out = new Out();
        通过外部类实例和new来调用内部类构造器创建非静态内部类实例
        in = out.new In("Test Msg");
        */
    }
}

下面定义了一个子类继承了 Out 类的非静态内部类 In 类

public class SubClass extends Out.In{
    // 显示定义 SubClass 的构造器
    public SubClass(Out out){
        out.super("hello");
    }
}

上面的代码可能看起来很怪,其实很正常:非静态内部类 In 类的构造器必须使用外部类对象来调用,代码中 super 代表调用 In 类的构造器,而 out 则代表外部类对象。

如果需要创建 SubClass 对象时,必须创建一个 Out 对象。因为 SubClass 是非静态内部类 In 的子类,非静态内部类 In 对象里必须有一个对 Out 对象的引用,其子类 SubClass 对象里也应该持有对 Out 对象的引用。当创建 SubClass 对象时传给该构造器的 Out 对象,就是 SubClass 对象里 Out 对应引用所指向的对象。

结合上面两段代码,非静态内部类 In 对象和 SubClass 对象都必须持有指向 Outer 对象的引用,区别是创建两种对象时传入 Out 对象的方式不同:当创建非静态内部类 In 类的对象时,必须通过 Outer 对象来调用 new 关键字;当创建 SubClass 类的对象时,必须使用 Outer 对象作为调用者来调用 In 类的构造器

在外部类之外使用静态内部类

因为静态内部类是外部类类相关的,因此创建静态内部类对象时无需创建外部类对象。

public class CreateStaticInnerInstance {
    public static void main(String[] args) {
        StaticOut.StaticIn in = new StaticOut.StaticIn();
        /* 上面的代码可改为如下两行代码
        使用 OuterClass.InnerClass 的形式定义内部类变量
        StaticOut.StaticIn in;
        通过 new 调用内部类构造器创建静态内部类实例
        in = new StaticOut.StaticIn();
        */
    }
}

因为调用静态内部类的构造器时不需要使用外部类对象,所以创建静态内部类的子类也比较简单。下面代码为静态静态内部类 StaticIn 定义了一个空的子类

public class StaticSubClass extends StaticOut.StaticIn {}

文章作者: Tianny
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Tianny !
评论
 上一篇
Java入门-匿名内部类 Java入门-匿名内部类
匿名内部类适合创建只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名类不能重复使用。 匿名类是用来创建接口或者抽象类的实例的。 匿名内部类不能定义构造器。因为匿名内部类没有类名,所有无法定义构造器。但匿名
2020-04-02
下一篇 
Java入门-抽象类 Java入门-抽象类
设计思想抽象类是模板模式的设计模式体现。抽象类是从多个具体类中抽象出来的父类,具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类为其子类的模板,避免子类设计的随意性 使用 抽象类使用 abstract 修饰。 抽象
2020-04-02
  目录