`

第十章 内部类

 
阅读更多
如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须像在下面这个例子中的一样:
OutClass o = new OutClass();
OutClass.InnerClass p = o.getInnerClass();


连接到外部类

内部类能访问外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权。

内部类自动拥有外围类所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。但是内部类的对象只有与外围类的对象相关联的情况下才能被创建。

使用 .this与 .new

如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this。
public class DotThis {
	void f() {
		System.out.println("DotThis.f()");
	}
	public class Inner {
		public DotThis outer() {
			return DotThis.this;
		}
	}
	public Inner inner() {
		return new Inner();
	}
	public static void main(String[] args) {
		DotThis dt = new DotThis();
		DotThis.Inner dti = dt.inner();
		dti.outer().f();
	}
}

有时你可能想要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法:
public class DotNew {
	public class Inner {}
	public static void main(String[] args) {
		DotNew dn = new DotNew();
		DotNew.Inner dni = dn.new Inner();
	}
}

先创建一个外部类对象,然后使用.new创建内部类。
在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的外部类对象上。

在方法和作用域内的内部类

可以在一个方法里面或者在任意的作用域内定义内部类。这么做有两个理由:
1. 如前所示,你事先了某类型的接口,于是可以创建并返回对其的引用。
2. 你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。

后面的例子中,先前的代码将被修改,以用来实现:

一个定义在方法中的类。
一个定义在作用域内的类,此作用域在方法的内部。
一个实现了接口的匿名类。
一个匿名类,它扩展了有非默认构造器的类。
一个匿名类,它执行字段初始化。
一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)。

匿名内部类
public class Parcel7 {
	public Contents contents() {
		return new Contents() {
			private int i = 11;
			public int value() {
				return i;
			}
		};
	}
	public static void main(String[] args) {
		Parcel7 p = new Parcel7();
		Contents c = p.contents();
	}
}

上面代码指的是:创建一个继承自Contents的匿名类的对象。Contents是父类啊!!
通过new表达式返回的引用被自动向上转型为对Contents的引用。上述的匿名内部类的语法是下属形式的简化形式:
public class Parcel7 {
	class Myclass implements Contents {
		private int i;
		public int value() {
			return i;
		}
	}
	public Contents contents() {
		return new Myclass();
	}
	public static void main(String[] args) {
		Parcel7 p = new Parcel7();
		Contents c = p.contents();
	}
}

如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。

匿名内部类与正规的集成相比有些限制,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备。而且如果是现实接口,也只能实现一个接口。

嵌套类

如果不需要内部类对象与其外围类对象之间有联系,那么就可以将内部类声明为static。这通常称为嵌套类。想要理解staitc应用于内部类时的含义,就必须记住,普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时,就不是这样了。嵌套类意味着:

1.要创建嵌套类的对象,并不需要其外围类的对象。
2.不能从嵌套类的对象中访问非静态的外围类对象。

嵌套类和普通内部类有一个区别。普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可以包含所有这些东西。

接口内部的类

正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分。你放到接口中的任何类都自动是public和static的、因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。你甚至可以在内部类中实现其外围接口:
public interface ClassInInterface {
	void howdy();
	class Test implements ClassInInerface {
		public void howdy() {
			System.out.println("Howdy");
		}
		public static void main(String[] args) {
			new Test().howdy();
		}
	}
}


如果你想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么使用接口内部的嵌套类会显得很方便。
看到上面的代码,我们就可以用这个方法,为每个类做一个测试main()方法。

从多层嵌套类中访问外部类的成员

一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外围类的所有成员

class MNA {
	private void f(){}
	class A {
		private void g() {}
		public class B {
			void h() {
				g();
				f();
			}
		}
	}
}
public class Parcel7 {
	public static void main(String[] args) {
		MNA mna = new MNA();
		MNA.A mnaa = mna.new A();
		MNA.A.B mnaab = mnaa.new B();
		mnaab.h();
	}
}

可以看到在MNA.A.B中,调用方法g()和f()不需要任何条件(即使它们是private的)。这个例子同时展示了如何从不同的类里创建多层嵌套的内部类对象的基本语法。“.new”语法能产生正确的作用域,所以不必在调用构造器时限定类名。

为什么需要内部类

一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。所以可以认为内部类提供了某种进入其外部类的窗口。

使用内部类最吸引人的地方就是:

每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

如果拥有的是抽象类或具体类,而不是接口,那就只能使用内部类才能实现多重继承了。
class D {}
abstract class E{}
class Z extends D {
	E makeE() {
		return new E() {}; //E括号后面有{}呢 是内部类注意!!!返回的是E的子类。
	}
}

public class MultiImplements {
	static void takesD(D d) {}
	static void takesE(E e) {}
	public static void main(String[] args) {
		Z z = new Z();
		takesD(z);
		takesE(z.makeE());
	}
}


上面的return new E() {};是一个内部类。
如果不需要解决多重继承的问题,那么自然可以用别的方式编码,而不需要使用内部类。但是
如果使用内部类,还可以获得其他一些特性:

1) 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
2) 在单个外围类中,可以让多个内部类以不同的方式实现一个接口,或继承同给一个类。
3) 创建内部类对象的时刻并不依赖与外围类对象的创建
4) 内部类并没有令人迷惑的is a关系;它就是一个独立的实体。


内部类的继承

    因为内部类的构造器必须连接到指向外围类对象的引用,所以在继承内部类的时候,事情会变得有点复杂。问题在于,那个指向外围类对象的秘密的引用必须被初始化,而在导出类中不再存在可连接的默认对象。代码如下:
class WithInner {
	class Inner{}
}

public class Inheritinner extends WithInner.Inner {
	Inheritinner(WithInner wi) {
		wi.super();
	}
	public static void main(String[] args) {
		WithInner wi = new WithInner();
		Inheritinner ii= new Inheritinner(wi);
	}
}


内部类可以覆盖吗

    如果创建了一个内部类,然后继承其外围类并重新定义此内部类时,会发生什么呢?也就是说,内部类可以被覆盖吗?这看起来是一个很有用的思想,但是“覆盖”内部类就好像它是外围类的一个方法,其实并不起什么作用,也就是内部类没有覆盖哦。
分享到:
评论

相关推荐

    数据结构(严蔚敏)第十章:内部排序

    严蔚敏教授的《数据结构》是一本经典的教材,其中第十章专门讲解了内部排序算法。内部排序,指的是数据在计算机内存中进行的排序过程,相对于外部排序,其处理的数据量相对较小,但要求快速、高效。 在这一章中,...

    第十章 类与对象

    ### 第十章 类与对象 —— C++ 重难点知识详解 #### 一、引言 C++ 是一种广泛应用于工业界的编程语言,它既继承了 C 语言的强大功能,又引入了面向对象编程(OOP)的概念。面向对象编程的核心在于类与对象的设计与...

    JavaScript第十章完整案例

    在这个"JavaScript第十章完整案例"中,我们将会探索北大青鸟课程体系中关于JavaScript的高级应用和实战项目,这将帮助我们理解如何将理论知识转化为实际操作。 在JavaScript的第十章,通常会涵盖诸如DOM操作、事件...

    第十章 内部排序.ppt

    第十章主要探讨的是内部排序,这是数据结构领域中一个核心的话题。内部排序指的是在计算机内存中完成的排序过程,适用于数据量相对较小的情况。本章的学习目标包括掌握各种排序算法的原理、特点、排序过程以及时间...

    万博内部教材第十章

    根据给定的文件信息,以下是对“万博内部教材第十章”的详细解读,主要涉及恶意代码的概念、起源、解决方法以及具体实例。 ### 恶意代码概述 恶意代码是指故意设计用于非法侵入计算机系统、破坏数据或干扰正常运行...

    c++primer plus第十章 代码

    《C++ Primer Plus》是C++编程领域里一本广受欢迎的教材,它的第十章主要讲解了C++中的类和对象,这是C++的核心概念之一。在这个章节中,你会接触到类的定义、对象的创建与使用、封装、继承、多态等关键知识点。现在...

    数据结构课件第十章内部排序.ppt

    数据结构中的内部排序是计算机科学中一种重要的概念,主要针对的是在内存中处理的数据集合,目的是将无序的记录序列调整为有序。本课件主要介绍了内部排序的多个方法及其特性。 1. **概述** - **排序定义**:排序...

    【数据结构课件】第十章 排序

    ### 数据结构第十章:排序 #### 一、概述 排序是一种基本的数据处理技术,它将一个数据元素的任意序列重新排列成一个按照关键字有序的序列。排序的目的在于提高数据的检索效率,使得查找操作能够更加高效地进行。...

    c++大学教程(第四版)第十章pdf

    综上所述,C++大学教程第四版第十章主要介绍了常对象与常成员函数、对象的组合、友元函数与类、this指针的使用、动态内存管理以及静态类成员等内容。这些知识点对于理解和掌握面向对象编程的基本概念和技术至关重要...

    严蔚敏版数据结构C语言版第十章原版ppt课件

    严蔚敏版《数据结构》是一本经典的教材,其中第十章主要探讨了内部排序算法,这是对大量数据进行排序时常用的一类方法。 内部排序指的是在整个排序过程中,数据完全在内存中进行处理,不需要借助外部存储设备。这一...

    第十章会计系统与内部控制.pptx

    会计系统与内部控制是企业管理的核心组成部分,特别是在信息技术高度发达的今天,它们的作用更加凸显。会计系统是企业收集、处理、存储和报告财务信息的关键工具,而内部控制则是保障会计信息准确、完整和安全的重要...

    基础会计第十章会计凭证.zip

    本资料"基础会计第十章会计凭证.zip"包含了对会计凭证的深入讲解,旨在帮助学习者理解和掌握会计凭证的原理与操作流程。在这个压缩包中,主要包含了一个名为"基础会计第十章会计凭证.pptx"的文件,它可能是一个详细...

    第九章第十章作业1

    第九章和第十章的作业1主要涉及磁性和材料科学的相关概念。下面将详细解释这些知识点。 9.2 磁性产生的根本原因在于原子中电子的运动产生电流,形成了电子自旋和轨道磁矩。在某些元素如Fe、Co、Ni中,由于内部强烈...

    C++程序设计教程:第十章 继承.ppt

    《C++程序设计教程:第十章 继承》 继承是面向对象编程中的核心概念,它允许一个类(称为派生类或子类)从另一个类(称为基类或父类)继承特性,从而实现代码的重用和扩展。本章主要介绍了C++中的继承结构、访问...

    Python基础第十章

    ### Python基础第十章知识点详解 #### 一、模块与客户端 **1. 模块化程序设计的概念** - **模块化程序设计**: 当程序变得庞大且包含多种可复用的功能时,通常会把这些功能组织成不同的模块。一个模块包含了相关...

    《第一行Android代码》课件:第十章 后台默默的劳动者-探究服务.pptx

    AsyncTask允许在后台线程执行任务,同时在UI线程更新结果,其内部也使用了Handler和Looper。使用AsyncTask时,需要定义三个泛型参数,分别代表输入参数、执行过程中的进度类型和最终结果类型。 服务的生命周期包括...

    自考审计学第十章.pptx

    以上是自考审计学第十章的主要知识点,涵盖了筹资与投资循环的特性、涉及的财务报表项目、业务活动、凭证记录、内部控制测试以及审计方法。理解和掌握这些知识点对于理解企业资金流动和风险管理至关重要。

    第十章-传输层

    ### 第十章 传输层 #### 10.1 传输层基础 ##### 10.1.1 划分传输层的必要性 在计算机网络的层次结构中,传输层占据了一个非常特殊的位置。一方面,它作为面向通信子网的最高层,与下三层共同构建了网络通信所需的...

Global site tag (gtag.js) - Google Analytics