Java:内部类的创建与使用

1 内部类的简介

1.1 内部类的定义

可以将一个类的定义放在另一个类的定义的内部,这就是内部类。

1.2 内部类的功能

  • 1 组织逻辑相关的类
  • 2 实现一种代码隐藏机制
  • 3 与外围类通信

1.3 内部类的优缺点

优点:Java 的内部类是非常有用的特性,在实现多重继承上,Java 的内部类给予我们更大的操作空间,比起同是面向对象语言的 C++,内部类在实现与理解上更为简单。
注意:C++ 没有内部类特性,但它依旧可以实现多重继承;java 的内部类与 C++ 的嵌套类是非常不同的。

缺点:难以把握使用内部类的需求;实现它难以做到优雅、清晰。

1.4 内部类使用的注意事项

对于使用内部类,我们必须在 coding 前深思熟虑,“%80 的程序功能都是由 %20 的代码实现的”,内部类属于比较深奥复杂的特性,在许多功能的实现上,我们可以使用更简单的特性去实现。
内部类的使用应该是在设计阶段考虑的问题,使用它之前应该给予足够的理由。

2 内部类的创建与使用

2.1 一个简单内部类的创建实例

下面创建了一个包含内部类的类:(内部类可以拥有自己的成员与方法)

public class Test {
	// 代码段1
	class Inner {
		private int n = 810;
		public void readValue() { System.out.println(n); }
	}
	// 代码段2
	public void useInner() {
		Inner i = new Inner();
		i.readValue();
	}
	// 测试
	public static void main(String[] args) {
		// 测试代码段1
		Test t = new Test();
		Test.Inner ti = t.new Inner();
		ti.readValue();
		// 测试代码段2
		new Test().useInner();
	}
} /* Output:
810
810
*/

解析
代码段 1:注意在测试代码段 1 时,我们先创建了一个外围类对象(前提内部类是非 static 的,这种情况要另行讨论),而不是直接用Test.Inner ti = new Test.Inner();或者Test.Inner ti = new Inner();(注意:用这两种方法会直接报错)。这是因为内部类有一个非常重要的隐藏特点:内部类的对象需要隐形地连接其外围类对象
我们都知道:内部类拥有对其外围类所有成员的访问权,所以内部类一定要能联系到外围类的对象实体,这样才能访问相应的值,以避内部类在访问逻辑上出错。

代码段2:在外围类的方法中创建内部类对象时,可以直接使用Inner i = new Inner();这种格式,这是因为外围类拥有其内部类的访问权(内部类的内部对于外围类来说是不可视的,这与作用域有关),注意:此处我们虽然没有创建外围类对象,但是在测试代码段 2 时,我们用的是new Test().useInner();,所以最终在实际生成内部类对象时还是创建了外围类对象。

注意:内部类对象的创建必须借助外围类对象,无论什么情况。

2.2 创建有关内部类的常用方法

通常关于内部类,我们会在外围类中创建一个返回内部类对象引用的方法,这有便于内部类的设计与使用。

public class Test {
	class Inner {
		private int n = 810;
		public void readValue() { System.out.println(n); }
	}
	// 返回内部类引用的方法
	public Inner getInner() {
		return new Inner();
	}
	// 测试
	public static void main(String[] args) {
		Test t = new Test();
		Test.Inner ti = t.getInner(); // 使用返回内部类对象引用的方法来创建内部类对象
		ti.readValue();
	}
} /* Output
810
*/

注意

  • 1 上述方法的功能也可以通过 .new 来实现。
  • 2 内部类对象依旧需要与外围类对象“连接”。

2.3 使用 .new 来创建内部类对象

.new 语法对于创建内部类对象是极为方便的,与常用的返回内部类对象引用的方法一样,它们都需要与外围类对象相关联,示例如下:

public class Test {
	class Inner {
		private int n = 810;
		public void readValue() { System.out.println(n); }
	}
	// 测试
	public static void main(String[] args) {
		Test t = new Test();
		Test.Inner ti = t.new Inner();	// 使用 .new 创建内部类对象
		ti.readValue();
	}
} /* Output
810
*/

我们不会用OuterClassReference.new OuterClassName.InnerClassName()来创建内部类对象(这种方式会直接报错),这是因为从逻辑上我们已经得到了外围类的对象引用 OuterClassReference,它可以访问内部类名称,所以OuterClassName 是多余的,使用OuterClassReference.new InnerClassName()即可。

2.4 使用 .this 生成外围类对象引用

我们时常在外部生成内部类对象,可是我们如何在内部类中生成外围类对象呢?解决方案是使用 .this 语法。示例如下:

public class Outer {
	void show() { print("Outer.show()"); }
	public class Inner {
		public Outer getOuter() {
			return Outer.this; // 使用 .this 在内部类中创建外围类对象
		}
	}
	public Inner getInner() { return new Inner(); }
	public static void main(String[] args) {
		Outer t = new Outer();
		Outer.Inner ti = t.getInner();
		ti.getOuter().show();
	}
}/* Output
Outer.show()
*/

解析:我们通过调用内部类对象的方法 Outer() 得到了外围类对象的引用,从而调用外围类对象的方法
注意:这个通过 .this 返回的外围类对象引用是可以被显式得到的,可以创建一个外围类引用来指向这个对象。

3 总结

  • 1 创建内部类的对象前,必须创建其所属外围类的的对象,使两者隐形相连,简单点说,就是内部类对象的创建需要借助外围类对象。
  • 2 内部类拥有外围类所有成员的访问权。
  • 3 使用内部类前需要有足够的理由并提前设计。

4 备注

更多细节可以看 Bruce Eckel 所著的《Java 编程思想》,本博文多为该书的学习心得,欢迎大家一起探讨。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中可以使用匿名内部类创建实现某个接口或继承某个类的对象。匿名内部类的语法格式为:new 父类构造器或接口() { 匿名内部类的类体 }。下面是一个例子: ```java public class AnonymousInnerClassExample { interface HelloWorld { void greet(); void greetSomeone(String someone); } public void sayHello() { class EnglishGreeting implements HelloWorld { String name = "world"; public void greet() { greetSomeone("world"); } public void greetSomeone(String someone) { name = someone; System.out.println("Hello " + name); } } HelloWorld englishGreeting = new EnglishGreeting(); HelloWorld frenchGreeting = new HelloWorld() { String name = "tout le monde"; public void greet() { greetSomeone("tout le monde"); } public void greetSomeone(String someone) { name = someone; System.out.println("Salut " + name); } }; HelloWorld spanishGreeting = new HelloWorld() { String name = "mundo"; public void greet() { greetSomeone("mundo"); } public void greetSomeone(String someone) { name = someone; System.out.println("Hola, " + name); } }; englishGreeting.greet(); frenchGreeting.greetSomeone("Fred"); spanishGreeting.greet(); } public static void main(String[] args) { AnonymousInnerClassExample myApp = new AnonymousInnerClassExample(); myApp.sayHello(); } } ``` 在上面的例子中,我们定义了一个接口HelloWorld,然后使用匿名内部类来实现这个接口。我们创建了三个HelloWorld对象,分别是EnglishGreeting、frenchGreeting和spanishGreeting。其中,EnglishGreeting是一个普通的内部类,而frenchGreeting和spanishGreeting是匿名内部类。我们可以看到,使用匿名内部类可以简化代码,并且不需要单独定义一个类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值