黑马程序员-Java的内部类

本文深入探讨了Java中内部类的概念及应用,包括其封装优势、访问权限特点,以及非静态内部类与静态内部类的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 ----------------------ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

大部分时候,我们把类定义成一个独立的程序单元。在某些情况下,我们把一个类放在另一个类的内部定义,这个定义在其他类的内部就被称为内部类,包含内部类的类也被称为外部类。内部类主要有如下作用。

1、内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类,假设需要创建Cow类,Cow类需要组合一个CowLeg对象,CowLeg类只有在Cow类里才有效,离开了Cow类之后没有任何意义。在这种情况下,就可把CowLeg定义成Cow的内部类,不允许其他类访问CowLeg。

2、内部类成员可以直接访问外部累的私有数据,因为内部类被当成外部类成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。

3、匿名内部类适合用于创建那些仅需要一次使用的类。

非静态内部类非常简单,看如下代码:

public class Cow {
	private double weight;

	// 外部类的两个重载的构造器
	public Cow() {
	}

	public Cow(double weight) {
		this.weight = weight;
	}

	// 定义一个非静态内部类
	private class CowLeg {
		// 非静态内部类的连个Field
		private double length;
		private String color;

		// 非静态内部类的两个重载的构造器
		public CowLeg() {
		}

		public CowLeg(double length, String color) {
			this.length = length;
			this.color = color;
		}

		public void setLength(double length) {
			this.length = length;
		}

		public double getLength() {
			return this.length;
		}

		public void setColor(String color) {
			this.color = color;
		}

		public String getColor() {
			return this.color;
		}

		public void info() {
			System.out.println("当前牛腿颜色是:" + color + " 高" + length);
			// 直接访问外部类的private修饰的Field
			System.out.println("本牛腿所在奶牛重:" + weight);
		}
	}

	public void test() {
		CowLeg cl = new CowLeg(1.12, "黑白相间");
	}

	public static void main(String[] args) {
		Cow cow = new Cow(378.9);
		cow.test();
	}
}
外部类Cow里面包含了一个test方法,该方法里创建了一个CowLeg对象,并调用该对象的info方法。不难发现,在外部类里面使用非静态内部类是,与平时使用的普通类并没有太大的区别。

非静态内部类的成员可以很方便的访问外部类的private成员,但是反过来就不成立了,非静态内部类的成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类的成员,则必须显式创建非静态内部类对象来调用访问其实例成员。下面的程序示范了这个规则。

public class Outer {
	private int outProp = 9;
	class Inner{
		private int inProp = 5;
		public void acessOuterProp(){
			//非静态内部类可以直接访问外部类的成员
			System.out.println("外部类的outProp值:" + outProp);
		}
	}
	public void accessInnerProp(){
		//外部类不能直接访问非静态内部类的实例Field
		//下面的代码出现编译错误
		//System.out.println("内部类的inProp值:" + inProp);
		//如需访问内部类的实例Field,则必须显式创建内部类对象
		System.out.println("内部类的inProp值" + new Inner().inProp);	
	}
	public static void main(String[] args) {
		//执行下面代码,只创建了外部类对象,还未创建内部类对象
		Outer outer = new Outer();
		outer.accessInnerProp();
	}
}
外部类不允许访问非静态内部类的实例成员还有一个原因,上面程序main方法中创建了一个外部类对象,并调用外部类对象的accessInnerProp方法,此时非静态内部类对象根本不存在,如果允许accessInnerProp方法访问非静态内部类对象,将肯定引起错误。

非静态内部类对象必须寄存在外部类对象里,而外部类对象则不一定有非静态内部类对象寄存在其中。如果存在一个非静态内部类对象,则一定存在一个被它寄存的外部类对象。但外部类对象存在时,外部类对象里不一定寄存了非静态内部类对象。因此外部类对象访问非静态内部类成员时,可能非静态普通内部类对象根本不存在!而非晶态内部类对象访问外部类成员时,外部类对象一定存在。

以下代码片段会引发编译错误:

public class StaticTest {
	//定义一个非静态内部类,是一个空类
	private class In{}
	//外部类的静态方法
    public static void main(String[] args) {
		//下面代码引发编译异常,因为静态成员(main方法)
    	//无法访问非静态成员(In类)
    	new In();
	}
}	
总之,不允许在外部类的静态成员中直接使用非静态内部类。

Java不允许在非静态内部类里定义静态成员。下面程序示范了非晶态内部类里包含静态成员将引发编译错误

public class InnerNoStatic {

	private class InnerClass {
		/*
		 * 下面三个静态声明都会引起如下的编译错误: 非静态内部类不能有静态声明
		 */
		static {
			System.out.println("静态代码块");
		}
		private static int InProp;

		private static void test() {
		}
	}
}
非静态内部类里不能有静态方法、静态Field、静态初始化块,所以上面三个静态声明都会引发错误。

静态内部类:

如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。因此使用static修饰的内部类被称为静态内部类。静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。

<pre name="code" class="java">public class StaticInnerClassTest {
	private int propl = 5;
	private static int prop2 = 9;

	static class StaticInnerClass {
		// 静态内部类里可以包含静态成员
		private static int age;

		public void accessOuterProp() {
			// 下面代码出现错误
			// 静态内部类无法访问外部类的实例成员
			System.out.println(propl);
			// 下面代码正常
			System.out.println(prop2);
		}
	}
}
 


静态内部类是外部类的类相关,而不是外部类的对象相关的。也就是说,静态内部类对像不是寄存在外部类对象里的,而是寄存在外部类的类本身中。当静态内部类对象存在时,并不存在一个被他寄存的外部类对象,静态内部类对象只有外部类的类引用,没有持有外部类对象的引用。如果允许静态内部类的实例方法访问外部类的实例成员,但找不到被寄存的外部类对象,这将引起错误。 

静态内部类是外部类的一个静态成员,因此外部类的静态方法、静态初始化块中可以使用静态内部类来定义变量、创建对象等。外部类依然不能直接访问静态内部类成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。下面程序示范了这条规则:

public class AccessStaticInnerClass {
	static class StaticInnerClass {
		private static int prop1 = 5;
		private int prop2 = 9;
	}

	public void accessInnerProp() {
		// System.out.println(prop1);
		// 上面代码出现错误,应改为如下形式
		// 通过类名访问静态内部类的类成员
		System.out.println(StaticInnerClass.prop1);
		// System.out.println(prop2);
		// 上面代码出现错误,应改为如下形式
		// 通过上面的实例访问静态内部类的实例成员
		System.out.println(new StaticInnerClass().prop2);
	}
}

 ---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值