《 Thinking in Java 》第十章 内部类
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了《 Thinking in Java 》第十章 内部类,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5448字,纯文字阅读大概需要8分钟。
内容图文
![《 Thinking in Java 》第十章 内部类](/upload/InfoBanner/zyjiaocheng/856/4dbc0d63926c4a6394d136209e3bb4cc.jpg)
可以将一个类的定义放在另一个类的定义内部,这就是内部类
- 内部类与组合是完全不同的概念。
- 内部类看起来像是一种代码隐藏机制,但是它还了解外围类,并能与之通信;
- 更优雅!!!
创建内部类
很简单——把类的定义置于外围类的里面:
public class A {
class InnerA {
}
public InnerA getInnerA() {
return new InnerA();
}
}
与使用普通类的方法,没什么不同,很典型的一个情况如上,外部类有一个方法,返回一个指向内部类的引用。
注意:如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须想这样来具体的指明这个对象的类型:
//OuterClassName.InnerClassName
public static void main(String[] args) {
A.InnerA a = new A().getInnerA();
}
链接到外部类
当生成一个内部类的对象时,次对象与制造它的外围对象之间就有了一种联系,所有它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权。
这种能力是如何做到的:当某个外围类的对象创建了一个内部类对象时,次内部类对象必定会秘密的捕获一个指向那个外围类对象的引用。然后,在访问此外围类的成员时,就是用那个引用来选择外围类的成员。但是要注意,只有内部类的对象与其外围类的对象相关联的情况下才能被创建(也就是说 ,内部类是非 static 类时)。构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到就会报错。
使用 .this 与 .new
如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和 this 。这样产生的引用自动地具有正确的类型,这一点在编译器就被知晓并受到检查,因此没有任何运行时开销。
public class A {
class B {
A getA() {
return A.this;
}
}
}
如果想直接创建内部类对象,就需要使用外部类的对象来创建内部类对象。而不能声明 a.new A.b() ;
class A {
// .......
public static void main(String[] args ) {
A a = new A();
A.B b = a.new B();
}
}
在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的内部类对象上。但是,如果创建的是嵌套类(静态内部类),那么他就不需要对外部类对象的引用。
内部类与向上转型
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。(从实现了某个接口的对象,得到对此对象的引用,与向上转型为这个对象的基类,实质上效果是一样的。)这是因为此内部类——某个接口的实现——能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便地隐藏实现细节。
简单地说明这种实现
- 创建公共接口 A 。
- 在某一个类 B 中添加一个 private(或 protected )的 A 接口的实现类 AImpl 。
- 在外部类提供一个 public 接口来返回一个 A 的引用。
优点:
- 除了 A 这个外围类,其它的类都不能访问或修改 AImpl。
- 通过公共接口取得的 A 的引用,由于无法访问到 B 中实现的 AImpl 名字,所以无法向下转型( 或protected 内部类,除非是继承自它的子类)。
在方法和作用域内的内部类
为什么要在一个方法里面或者在任意的作用域内定义内部类,理由有二:
- 实现了某类型的接口,于是可以创建并返回对其的引用。
- 希望创建一个不是公共可用的类来解决你的复杂的问题。
以下是一些可以放内部类的位置
- 一个定义在方法中的类。
- 一个定义在作用域中的类,次作用域在方法的内部。
- 一个实现了接口的匿名类。
- 一个匿名类,扩展了有非默认构造器的类。
- 一个匿名类,它执行字段初始化。
- 一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)。
一、展示在方法的作用域内创建一个完整的类。称作局部内部类
public class D {
public A getA() {
class AImpl implements A {
//......
}
return new AImpl();
}
//.......
}
AImpl 类是方法的一部分,而不是 D 的一部分,,所以,在方法之外不能访问 AImpl 。虽然 AImpl 在方法中,但这并不意味方法执行完毕, AImpl 这个对象就不能用了。
在同一子类目下的任意类中对某个内部类使用类标识符 AImpl ,这并不会有命名冲突。
二、展示在任意作用域内嵌入一个内部类:
public class A {
private void f(boolean b) {
if( b ) {
class B {
String getSlip() {
return "1";
}
//....
}
B b = new B();
String str = b.getSlip();
}
}
}
虽然这个类是放在 if 语句中,但是并不意味着创建需要条件,它其实与别的类一起编译过了。但是,在定义这个类的作用域之外,它是不可用的;初次之外,它与普通的类一样。
匿名内部类
public class B {
public A newA() {
return new A() {
private int i = 11;
};
}
//.....
}
newA() 方法将返回值的生成与表示这个返回值的类的定义结合在一起。另外这个类是匿名的。
表示的是:创建一个继承自 A 的匿名类的对象。通过 new 表达式返回的引用被自动向上转型为对 A 的引用。
在这个匿名类中,使用了默认的构造器来生成 A 。下面展示,如果基类需要带参构造器该怎么办:(注意这里区别于匿名类需要带参构造器)
public class B {
public A newA(int x) {
return new A(x) {
private int i = 11;
public int value() {
return super.value();
}
};
}
//.....
}
只需要简单地传递合适的参数给基类的构造器即可。
如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是 final 的。
如果需要构造器的行为,因为匿名类中不可能有命名构造器(因为它根本没有名字!),但通过实例初始化,就能够达到为匿名累不累创建一个构造器的效果,like this:
abstract class Base {
public Base(int i) {
//......
}
}
public class A {
public static Vase getBase(int i) {
return new Base(i) {
{
public void f() {};
//.....
}
};
}
在这个例子中,不要求变量 i 一定是 final 的。因为 i 被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。
如果在匿名类内部使用,则要求传入的参数是 final 的。
当然它收到了限制——不能重载实例初始化方式,所以仅有一个这样的构造器。
匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备,而且如果是实现接口,也只能实现一个接口。
嵌套类
如果不需要内部类对象与其外围类之间有联系,那么可以将内部类声明为 static 。这通常成为嵌套类。
普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象,然而,当内部类是 static 的时,就不是这样
- 要创建嵌套类的对象,并不需要其外围类的对象。
- 不能从嵌套类的对象中访问非静态的外围类对象。
还有一个区别就是,普通的内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有 static 数据和 static 字段,也不能包含嵌套类。但是嵌套类可以包含所有这些东西。
接口内部的类
内容总结
以上是互联网集市为您收集整理的《 Thinking in Java 》第十章 内部类全部内容,希望文章能够帮你解决《 Thinking in Java 》第十章 内部类所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。