1、当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地(从实现某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样得。)这是因为此内部类——某个接口的实现——对于其他人来说能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便地隐藏实现细节。
interface Destination{
String readLabel();
}
interface Contents{
int value();
}
class Parce1{
private class PContents implements Contents{
private int i = 2012;
public int value() {
return i;
}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String label){
this.label = label;
}
public String readLabel() {
return label;
}
}
public Destinationdest(String label){
return new PDestination(label);
}
public Contents cont(){
return new PContents();
}
}
public class TestParcel{
public static void main(String[] args){
Parce1 p = new Parce1();
Contents c = p.cont();
System.out.println(c.value());
Destination d = p.dest("Cannel_2020");
System.out.println(d.readLabel());
}
}
运行结果:
1).PContent是private的,所以除了Parcel,没有人能访问它。
2).Pdestination是protected,所以只有Parcel及其子类、还有与Parcel用包的类能访问。
3).这意味着,如果客户端程序员想了解或访问这些成员,那是要受限制的。
4).实际上,甚至不能向下转型成private内部类(或protected内部类,除非是继承自它的子类),因为不能访问其名字。
5).所以通过类似如上的方式,可以完全阻止任何依赖类型的编码,并且完全隐藏了实现的细节。
6).此外,从客户端程序员的角度来看,由于不能访问(为什么?)任何新增加的、原本不属于公共接口的方法,所以扩展接口是没有价值的。这也给Java编译器提供了生成更高效代码的机会。
7).以上是内部类的典型用途。
2、在一个方法或者任意的作用域内定义内部类的两个理由:
1).如前所示,你实现了某个类型的接口,于是可以创建并返回对其的引用。。
2).你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。
3、局部内部类:在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类。方法的执行完毕,并不意味该局部内部类就不可用了。另外,局部内部类不能有访问说明符。
4、匿名内部类:
public Contentscont(){
return new Contents(){
private int i = 2012;
public int value(){
return i;
}
};
}
其上是下述形式的简化形式:
public Contents cont(){
class MyContents implements Contents{
private int i = 2012;
public int value(){
return i;
}
}
return new MyContents();
}
若匿名内部类需要一个有参数的构造器:
class Wrapping{
int i = 0;
Wrapping(int i){
this.i = i;
}
public int value() {
return i;
}
}
public class Parcel{
public Wrapping wrap(int i){
return new Wrapping(i){
public int value(){
return super.value()*10;
}
};
}
public static void main(String[] args){
Wrapping w = new Parcel().wrap(2012);
System.out.println(w.value());
}
}
5、匿名内部类没有命名的构造器,但通过实例初始化,能够达到为一个构造器的效果。
abstract class Base{
public Base(int i){
System.out.println("基类的构造函数内, i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor{
public static Base getBase(int i){
return new Base(i){
{
System.out.println("实例初始化器内");
}
public void f(){
System.out.println("在匿名内部类里的f()");
}
};
}
public static void main(String[] args){
Base base = getBase(2012);
base.f();
}
}
运行结果:
6、匿名内部类中使用一个在外部定义的对象,那么编译器会要求其参数引用是final的。
7、Java的内部类,拥有其外围类的所有元素的访问权。(这与C++的嵌套类的设计非常不同,在C++中只是单纯的名字隐藏机制与外围对象没有联系,也没有隐含的访问权。)
这是如何做到的呢?
当外围类的对象创建了一个内部类的对象时,此内部类对象必定会保存一个指向那个外围类对象的引用。在你访问外围类的成员的时候,就是那个“隐藏的”引用来选择外围类的成员。(构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到这个引用就会报错。)
8、嵌套类:如果不需要内部类对象与其外围类对象之间的联系,那么可以将内部类声明为static。这通常称为嵌套类。
1).要创建嵌套类的对象,并不需要其外围类的对象。
2).不能从嵌套类的对象中访问非静态外围对象。
9、普通内部类与嵌套类的区别:普通内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可以包含所有这些东西。
10、普通内部类(非static)可以通过一个特殊的this引用可以链接到其外围类对象。嵌套类就没有这个特殊的this引用,这使得它类似一个static方法。
11、内部类的继承存在的问题:那个指向外围类对象的“秘密的”引用必须被初始化,而在导出类中不再存在可连接的缺省对象。例子如下:
class Outter{
Outter(){
System.out.println("Outter()");
}
class Inner{
Inner(){
System.out.println("Inner()");
}
}
}
public class InheritInner extends Outter.Inner{
InheritInner(Outter outter){
outter.super();
System.out.println("InheritInner()");
}
public static void main(String[] args){
Outter outter = new Outter();
InheritInner inheritInner = new InheritInner(outter);
}
}
虽然是继承内部类,但是当生产一个构造器时,缺省的构造器并不算好,而且不能只是传递一个指向外围类对象的引用,必须在构造器内使用如下语法:
outter.super();
这样才提供了必要的引用,然后程序才能编译通过。若缺省上面语句,会提示“由于某些中间构造函数调用,没有任何类型 Outter 的外层实例可用”的错误。
12、内部类的覆盖,比较俩个例子:
1).
class Outter{
private Inner inner;
Outter(){
System.out.println("基类Outter()");
inner = new Inner();
}
protected class Inner{
Inner(){
System.out.println("基类的内部类Inner()");
}
}
}
public class InheritInner extends Outter{
public class Inner{
public Inner(){
System.out.println("InheritInner重新定义的内部类Inner()");
}
}
public static void main(String[] args){
new InheritInner();
}
}
运行结果:
2).
class Outter{
private Inner inner;
Outter(){
System.out.println("Outter()");
inner = new Inner();
}
public void insertInner(Inner inner){
this.inner = inner;
}
public void outterFunc(){
inner.func();
}
protected class Inner{
Inner(){
System.out.println("Outter.Inner()");
}
public void func(){
System.out.println("Outter.Inner().func()");
}
}
}
public class InheritInner extends Outter{
public InheritInner(){
System.out.println("InheritInner()");
//下面语句先Outter.Inner(),再是InheritInner.Inner();
Inner inner = new Inner();
insertInner(inner);
}
public class Inner extends Outter.Inner{
public Inner(){
System.out.println("InheritInner.Inner()");
}
public void func(){
System.out.println("InheritInner.Inner().func()");
}
}
public static void main(String[] args){
Outter outter = new InheritInner();
outter.outterFunc();//动态绑定
}
}
运行结果:
下接《Java编程思想》之为什么需要内部类?
以上内容整理自《Java编程思想》,若有遗漏,请您不吝指出!