3.4、嵌套类

这篇Java教程基于JDK1.8。教程中的示例和实践不会使用未来发行版中的优化建议。
嵌套类

Java编程语言允许你在其他类里面定义类。这样一个类我们叫做嵌套类:

class OuterClass{
	···
	class NestedClass{
		···
	}
}

术语:嵌套类一般被分为两类:静态和非静态。通过static声明的嵌套类叫做静态内部类,非静态嵌套类叫做内部类。


class OuterClass{
	···
	static class StaticNestedClass{
		···
	}
	class InnerClass{
		···
	}
}

嵌套类是其封闭类的成员。非静态嵌套类(内部类)可以访问封闭类的成员,及时它们被声明为private。静态嵌套类无法访问封闭类中的其他成员。作为OuterClass类的成员,嵌套类可以声明为private,protected,package-private,public。

为什么使用嵌套类?

使用嵌套类的原因主要有以下几点:

  • 它是一种逻辑上对只在一个地方使用的类进行分组的方法:如果一个类只对另外一个类有用,从逻辑上来说可以把它们放在一起。嵌套这样的“Helper类”使它们的包更加流线型。
  • 它增强了封装:考虑两个顶级类,A和B,B需要访问A中声明为private的成员。通过在类A中隐藏类B,A的成员可以声明为private并且B可以访问它。加上,类B自身也对外部世界隐藏了。
  • 它可以产生更易于阅读和维护的代码:在顶层类中嵌套一些小类也让其与使用它的地方更近。
静态嵌套类

如同类方法和类变量,静态嵌套类关联它的外部类。与静态方法一样,静态嵌套类不能直接访问封闭类中的实例变量和方法:你只能通过对象引用来使用它。

使用封闭类名来访问静态嵌套类:

OuterClass.StaticNestedClass

比如,要创建一个静态嵌套类的对象,可以这样来做:

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
内部类

如同实例变量和方法,内部类关联的是封闭类的对象,它可以直接访问封闭类对象的变量和方法。因为内部类关联的是对象,它自己不能定义任何静态成员。
内部类对象存在于外部类的对象中,考虑如下的类:

class OuterClass{
	···
	class InnerClass{
		···
	}
}

InnerClass 类的实例仅仅只能存在于OuterClass的实例中,并且可以直接访问封闭类对象的字段和方法。

为了实例化一个InnerClass,你必须首先实例化一个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 s1 = new ShadowTest();
		ShadowTest.FirstLevel f1 = s1.new FirstLevel();
		f1.methodInFirstLevel(23);
	}
}

输出如下:

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

这个示例定义了三个名为x的变量:ShadowTest类的成员变量,FirstLevel类的成员变量,methodInFirstLevel方法的参数。变量x定义为methodInFirstLevel方法的一个参数,它对内部类FirstLevel的变量施加阴影。因此,当在methodInFirstLevel方法中使用变量x,它是指方法参数。为了引用FirstLevel类的成员变量,在封闭类范围内使用this关键字

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

为了在封闭类之外的范围里引用成员变量。比如下面的语句表示从methodInFirstLevel方法中访问ShadowTest的成员变量

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

强烈反对序列化嵌套类,包括本地类和匿名类。Java编译器会对内部类执行合成构造;这些类、方法、字段和其他构造在源代码中没有对应的构造。合成构造使Java编译器能够实现新的Java语言特性,而无需更改JVM。然而,在不同的Java编译器实现中,合成构造可能会有所不同,这意味着.class文件在不同的实现中也可能有所不同。因此,如果你序列化一个内部类,然后使用不同的JRE实现反序列化它,那么可能会有兼容性问题。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值