Java中的静态内部类和非静态内部类

参考:Oracle官方文档Nested Classes

引言

Java语法中允许一个类嵌套在另一个类中,我们把嵌套在其他类中的类称为内部类。而内部类又分为两种,静态内部类(static nested classes)和非静态内部类(inner classes)。
例如这样的关系:

//外部类
class OuterClass {

    //静态内部类
    static class StaticNestedClass {
        ...
    }

    //非静态内部类
    class InnerClass {
        ...
    }
}

内部类是外部类的一个成员。
非静态内部类可以直接调用外部类的其他成员。
而静态内部类不可以直接调用外部类的其他成员。

为什么要使用内部类

1.如果一个类A只为另一个类B服务,那把A嵌套在B中,就相当于B的一个服务类,代码可读性更高,方便维护。

2.如果一个类A要调用另一个类B,但B又不想被其他类所引用就要申明为private,那把A嵌套在B中,就可以同时满足前面的两个要求了,代码的封装性更好了。

静态内部类

静态内部类可以直接调用外部类的静态成员(静态成员变量和静态方法),但是不能直接调用外部类的非静态成员。

静态内部类的使用

1.直接通过类名调用

OuterClass.StaticNestedClass

2.创建实例

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

其实我们可以把静态内部类看成和外部类平级的一个类,我们在调用静态内部类时甚至都不用初始化外部类。

如下是一个外部类People和嵌套在其中的静态内部Man。

public class People {

    static String hi = "I'm People";

    static {
        System.out.println("People的static代码块");
    }

    People() {
        System.out.println("People的构造方法");
    }

    static class Man {

        static String hello = "I'm Man";

        static {
            System.out.println("Man的static代码块");
        }

        Man() {
            System.out.println("Man的构造方法");
        }
    }
}

调用代码:

    public static void main(String[] args) {
        People.Man man = new People.Man();
    }

运行结果:

Man的static代码块
Man的构造方法

显然在创建静态内部类实例的时候,外部类根本就没有被初始化。

非静态内部类

只有创建了外部类的实例才能使用非静态内部类,所以非静态内部类不允许存在静态成员。
然后根据外部类的实例就可以创建非静态内部类实例,并且非静态内部类实例持有了外部类的引用。

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

等价于:

OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

同名变量的覆盖问题

来看一个覆盖测试:

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
        }
    }

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

测试结果:

x = 23
this.x = 1
ShadowTest.this.x = 0

通过以上结果显然可以知道:
如果内部类的局部变量和内部类的成员变量以及外部类的成员变量重名为x。
那么内部类的局部变量就是x
内部类的成员变量用this.x表示,
外部类的成员变量用外部类名.x表示。

序列化的问题

Oracle官方强烈不建议序列化非静态内部类,包括局部内部类和匿名内部类,因为Java编译器为了编译内部类和一些其他东西,采用了虚拟构建方法。虚拟构建方法使Java编译器实现了Java新特性而不用修改Java虚拟机。但是Java编译器实现的不同会导致虚拟构建方法的不同,这就意味着你在一个JRE中序列化了一个内部类,在另一个JRE中反序列化它时会遇到兼容性问题。

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值