java炒冷饭系列10 内部类 使用.this与.new和向上转型

来源:互联网 发布:tap建站 编辑:程序博客网 时间:2024/06/05 18:57

使用.this与.new

如果你需要生成对外部类对象的引用,可以使用外部类的名字后紧跟加点和this(OutClass.this)。这样产生的引用自动地具有正确的类型,这一点在编译期就被知晓并受到检查,因此没有任何运行时开销。下面的示例展示了如何使用.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();    }}

我在这里在补充一点,OuterClass.this 还可以用来引用外部类同名的属性和方法

public class Outer {    private String name = "jianglei";    public void method(){        System.out.println("Outer.method()");    }    public class Inner{        private String name = "Deng yi";        public void method(){            System.out.println("Inner.method()");        }        public void test(){            System.out.println(name);            System.out.println(Outer.this.name);            method();            Outer.this.method();        }    }    public Inner getInner(){        return new Inner();    }    public static void main(String[] args) {        Outer.Inner inner = new Outer().getInner();        inner.test();    }}//输出Deng yijiangleiInner.method()Outer.method()

有时你可能想告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法,就像下面这样:

public class DotNew {    public class Inner{}    public static void main(String[] args) {        DotNew dn = new DotNew();        DotNew.Inner dni = dn.new Inner();    }}

要想直接创建内部类的对象,你不能按照你想象的方式,去引用外部类的名字DotNew,而是必须使用外部类的对象来创建该内部类对象,就像在上面的程序中所看到的那样。这也解决了内部类名字作用域的问题,因此你不必声明(实际上你不能声明)db.new DotNew.Inner()

在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的外部类对象上。但是,如果你创建的是嵌套类(静态内部类),那么它就不需要对外部类对象的引用。
下面你可以看到将.new应用于Parcel的示例:

public class Parcel3 {    class Contents{        private int i = 11;        public int value(){            return i;        }    }    class Destination{        private String label;        Destination(String whereTo){            label = whereTo;        }        String readLabel(){            return label;        }    }    public static void main(String[] args) {        Parcel3 p = new Parcel3();        Parcel3.Contents contents = p.new Contents();        Parcel3.Destination d = p.new Destination("Tasmania");    }}

内部类与向上转型

当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。(从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的。)这是因为此内部类--某个接口的实现--能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便地隐藏实现细节。
我们可以创建前一个示例的接口:

public interface Contents {    int value();}
public interface Destination {    String readLabel();}

现在ContentsDestination表示客户端程序员可用的接口。(记住,接口的所有成员自动被设置为public的。)
当取得了一个指向基类或接口的引用时,甚至可能无法找出它确切的类型,看下面的例子:

public class Parcel4 {    private class PContents implements Contents{        @Override        public int value() {            return 0;        }    }    protected class PDestination implements Destination{        private String label;        private PDestination(String whereTo) {            label = whereTo;        }        @Override        public String readLabel() {            return label;        }    }    public Destination destination(String s) {        return new PDestination(s);    }    public Contents contents() {        return new PContents();    }}class TestParcel{    public static void main(String[] args) {        Parcel4 p = new Parcel4();        Contents c = p.contents();        Destination d = p.destination("Tasmania");        //! Parcel4.PContents pc = p.new PContents();    }}

Parcel4中增加了一些新的东西:内部类PContentsprivate,所以除了Parcel4,没有人能访问它。PDestinationprotected,所以只有Parcel4及其子类,还有与Parcel4同一个包中的类(因为protected也给予了包访问权)能访问PDestination,其他类都不能访问PDestination。这意味着,如果客户端程序员想了解或访问这些成员,那是要受到限制的。实际上,甚至不能向下转型成private内部类(或protected内部类,除非是继承它的子类),因为不能访问其名字,就像在TestParcel类中看到的那样。于是,private内部类给类的设计者提供了一种途径,通过这种方式可以完全阻止任何依赖于类型的编码,并且完全隐藏了实现的细节。此外,从客户端程序员的角度来看,由于不能访问任何新增加的,原本不属于公共接口的方法,所以扩展接口是没有价值的。这也给Java编译器提供了生成更高效代码的机会

参考文献

《Java编程思想》10.3使用this与new
《Java编程思想》10.4内部类与向上转型

原创粉丝点击