嵌套类

https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html 

 

嵌套类

java允许使用者在一个类里定义另外一个类,这样的类称之为嵌套类,比如像这样

class OuterClass{
   ...
   class  NestedClass{
        ...
   }
}

 嵌套类可以分为两种:静态的和非静态的。被声明为静态的嵌套类称之为静态嵌套类(static nested classes),非静态的嵌套类称之为内部类(inner classes)

嵌套类是外部类的成员,其中内部类能够使用外部类的所有成员(包括方法和属性,包括私有)。静态嵌套类不能使用外部类的成员。

 

为什么要用嵌套类呢?

使用嵌套类主要有这三个理由:

1.如果一个类A只被另一个类B使用,那就可以将A写成B的内部类,这样逻辑上把他们打包成组,也让类所在包结构更合理化

2.假设有两个逻辑上同等级的类A和B,当B需要访问A的私有成员时,就要嵌套

3.将一些小型的类嵌套在使用它们的顶级类中,使代码的可读性和可维护性更强

 

静态嵌套类

静态嵌套类跟外部类的关系就像静态方法跟静态属性一样,比如静态嵌套类是private的话,其他类就不能用。另外就像类的静态方法一样,静态嵌套类不能直接涉及定义在外部类的实例变量和实例方法,只能通过对象引用来使用它们。

静态嵌套类跟它的外部类实例成员的关系,就像其他顶级类(非嵌套类)一样。实际上,把一个类写成静态嵌套类只能因为package方便

如果说静态内部类跟一般类有什么区别的话就两点:

1.使用时必须带上外部类,比如在实例化的时候

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

 2.使用外部的静态成员时,语法上可以不带外部类

 

内部类

就跟实例方法和实例属性一样,内部类能够直接使用外部类对象的属性和方法。同时因为内部类是跟一个实例关联的,它不能定义任何静态成员。(个人认为,这样规定并不是因为不能实现,估计因为当初设计者为了是内部类更像一个成员变量)

内部类实例只能存在于一个外部类实例,并且能直接获取外部类实例的成员

要实例化一个内部类,必须先实例化一个外部类,然后用一下语法来实例化内部类

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

 还有两种特殊的内部类:本地类和匿名类 后面介绍

 

嵌套类机制实现

嵌套类的实现并不是通过修改jvm机制或指令,它的实现是通过编译器特殊编译实现的,相当于是语法糖。每一个嵌套类都会单独生成一个class文件,这个class类名一般是外部类名+$+内部类名,这个生成的类除了有本来的属性跟方法外,还有一个类型为外部类的final属性以及一个参数为外部类的构造方法。内部类调用外部类的变量方法,其实就是调用这个final属性的变量跟方法。而实例化一个内部类就是将那个outerObject作为参数调用内部类的构造方法,实例化一个静态嵌套类就是已null为参数调用构造方法。

 

遮蔽(Shadowing)

如果在一个特定作用域(比如内部类或一个方法中)声明了一个类型(比如成员变量或参数名),而这个申明跟它的外部作用域有相同的名称,那么内部这个声明遮蔽外部作用域的声明。那就不能直接用这个变量的名称去调用被遮蔽的声明。比如

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的成员变量、内部类FirstLevel的成员变量和methodInFirstLevel方法的参数。方法参数x遮蔽了FirstLevel的成员变量,因此在方法中使用变量x的时候,它引用的是方法参数。要引用内部类FirstLevel的成员变量,可以使用关键字this来代表外部作用域。要引用更外部做用域的成员变量需要带上该变量所属的类名

 

序列化

非常不建议序列化包括本地方法、匿名方法在内的内部类。为什么呢,如上面讲的内部类生效是因为java编译器单独为它生产一个class文件,而且他的构造方法是合成的。这个合成的方式虚拟机是不管的,由各家编译器去实现,当然就会有差异性,那么在序列化再反序列化的时候就容易出问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值