java遗珠之嵌套类

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lastsweetop/article/details/82668369

使用内部类的原因

1.合乎只在一个地方备用的逻辑: 如果一个类仅仅被一个别的类使用,那么把这个类嵌入到使用它的类中非常符合逻辑,嵌套这样的帮助类是的package变得简洁。

2.有益于封装:
如果两个类A和B,如果B需要访问A定义为private的成员,那么B嵌套到A类中,即使A的成员是private的B也可以访问,另外B类也可以被隐藏起来,不被外部访问。

3.可读性好且易于维护
在顶级类中在使用它们的地方嵌套很多小的类利于可读和维护

静态内部类

像类变量和类方法一样,静态内部类通过它的封闭类来调用。并且像类方法一样,静态内部类不能直接访问定义在外部类的实例变量和实例方法,只能通过外部类的对象引用才可以使用它们。

静态内部类使用外部类或者其他类的实例成员,需要像其他顶级类一样使用它们。静态内部类的行为看起来像是一个顶级类一样,只是仅仅因为包装便利的关系,才将它嵌套到另一个顶级类内部。

静态内部类需要使用它的包装类来访问。

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

内部类

像实例变量和实例方法一样,内部类需要通过它的封闭类的实例来调用,并且它可以直接访问对象的方法和字段,因为内部类是通过外部类的实例关联,因此它不能定义静态的成员。

内部类的实例要依托于它的外包类的实例存在

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

要实例化内部类必须实例化外部类,然后在外部类实例的基础上创建内部类:

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的变量,ShadowTest类的成员变量x,内部类FirstLevel类的成员变量x,和methodInFirstLevel方法的参数x。methodInFirstLevel方法的参数x隐匿了内部类FirstLevel类的成员变量x,因此你在methodInFirstLevel方法中使用x时使用的是方法参数的x,为了使用内部类FirstLevel的成员变量x,你需要this关键字来指明是内部类FirstLevel类的成员变量x:

 System.out.println("this.x = " + this.x);

为了使用更大范围的成员变量,你需要通过指定类名的方式,在此例子中,你在methodInFirstLevel中使用ShadowTest类的成员变量你需要如下做:

System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

序列化

强烈建议不需要序列化内部类,包括本地类和匿名类。因为编译器编译某些构造器是比如内部类,会创建合成构造,由类,方法,字段和其他与源码不对应的构造器组成。合成构造可以在不更改jvm的前提下实现新的java特性,但是合成构造在不同的编译器下的实现也不通,也就是说生成的.class文件都是不同,因此序列化内部类后,由不同的JRE反序列化时就会出现问题。

展开阅读全文

没有更多推荐了,返回首页