详解 java 内部类

来源:互联网 发布:手机生日蜡烛软件 编辑:程序博客网 时间:2024/04/28 12:50



定义 :将一个类的定义放在另一个类中 .

 

首先说如何创建一个内部类的实例: 从外部类的非静态方法之外的人一位置创建某个内部类的对象,那么必须像在main()方法中那样,具体的致命这个对象的类型:

OuterClassName.InnerClassName

外部类可以访问内部类中的信息那是没什么疑问的,可是内部类也可以访问外部类的信息,包括私有信息,当生成一个内部类的对象时,此对象与制造它的外围对象(enclosing object)

之间就有了一种联系,所以它能 访问其外围对象的所有成员,而不需要特殊条件。    实现机制:当某个外围类的对象创建了一个内部类对象时,此对象会秘密持有一个对外围对象的引用。

下面给出一个例子

package com.meran.thinkingInJava.innerClass;public class Test1 {private String label="合肥";class Destination{private String label;    Destination(String whereTo){    label=whereTo;    }    String readFatherLabel(){    return Test1.this.label;//父类.this相当于 父类中的this    }    String readLabel(){    return label;    }}public Destination getDest(String label){return new Destination(label);}public void ship(String dest){        Destination dest1=new Destination(dest);        System.out.println(dest1.label);}static class Context{private String label="静态内部类不需要内部类对外部类对象的引用";public String getLabel(){return label;};}public static void main(String [] args){Test1 test=new Test1();test.ship("北京");Test1 test1=new Test1();Test1.Destination dest=test1.getDest("上海");Destination dest1=test1.getDest("南京");System.out.println(dest.readLabel());System.out.println(dest1.readFatherLabel());    Destination dest2=test1.new Destination("哈尔滨");//直接创建内部类对象。    Context c=new Context();    System.out.println(c.getLabel());}}


 

北京上海合肥静态内部类不需要内部类对外部类对象的引用


 

如上面结果所写, 静态内部类的创建不需要内部类对外部对象的引用。

 

 

下面来说下

.this .new

.this  父类对象实例。this 相当于当前父类对象的引用     父类对象实例。new 用于创建内部类。   当类为静态内部类(嵌套类)的时候,不需要.new方法不需要对父类对象的引用。

 

 

内部类与向上转型。

当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地(从实现了某个几口的对象,得到对此接口的引用)这是因为内部类-----某接口实现-------能够完全不可见并且不可用。所得的只是指向接口的引用,可以很方便的隐藏实现。

 

 

 

下面一段代码

package com.meran.thinkingInJava.innerClass;/* * 可以看出 destination 方法返回的一个向Destination类型的上转型 */abstract class  Destination{abstract  String readLabel();}class Context {private String label;public Context(String s){   System.out.println("调用Context构造方法");this.label=s;}public void printLabel(){  System.out.print("父类printLabel被调用打印父类中label");    System.out.println(label);}}public class Test2 {     public Context context(String label,final String _label1){     return new Context(label){     String label1;     {        System.out.println("子类实例化函数被调用");     label1=_label1;     }                                    public void printLabel(){                       System.out.println("子类printLabel被调用 打印子类中label1"+label1);          super.printLabel();     }     };     }public Destination destination(final String dest,final float price){return new Destination(){        private int cost;        //小括号中代码是对象初始化代码          {            cost=Math.round(price);            if(cost>100)            System.out.println("over budget!");         }        private String label=dest;        public String readLabel(){return label;}};}public static void main(String []args){Test2 t=new Test2();Destination d=t.destination("Tasmania",101.395F);System.out.println(d.readLabel());Context c=t.context("小明的爸爸", "小明");c.printLabel();}                                       }


 

over budget!Tasmania调用Context构造方法子类实例化函数被调用子类printLabel被调用 打印子类中label1小明父类printLabel被调用打印父类中label小明的爸爸


 

Test2中public Context context(String label,final String _label1)方法  返回的是Context 类型的引用,这句话的意思相当于,创建一个继承自Context的匿名类对象。这个类的作用于今夏怒public Context context(String label,final String _label1) 方法内部。 注意这个方法的两个参数, 第一个参数没加 final ,因为它是要被 Context类调用的, 而 _label1这个变量则是被我们的匿名内部类访问的,所以它要被设置为final类型。 在匿名内部类中无法定义构造器,----_-----!!!!!!因为我们连类名都不知道,所以只能调用父类构造器,或者使用实例初始化块,这段代码的作用就相当于构造器。

 

 

嵌套类:如果不需要内部类对象与其外部类对象之间有联系,可以把它声明为static类型,就通常称为嵌套类。

潜逃类意味着:1.要创建嵌套类的类的对象,并不需要其外围类的对象 2.不能从嵌套类的对象访问非静态的外围类对象

 

 

 

1。接口内部的类

正常情况下不可以在接口中放任何代码,接口中热不和类都是static 和public的,因为类是static的 只是相当于把潜逃类放到了接口的命名空间中,这样坐可以创建公共代码,为不同接口的实现所共用。

 

 

利用内部类实现多重继承

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

接口解决的 “多重继承问题”

 

interface A{};interface B{};public class x implements A,B{];public class x implements A{B getB{//匿名内部类实现return new B():}}
//实现多继承
class D{}abstract F{}class Z extends D{E makeE(){return new E(){};}}

 

 

闭包与回调

闭包(closure)是一个可调用的对象。它记录了一些信息,这些信息来自创建它的作用域(内部类是面向对象的闭包),因为它不但了解外部类信息,还包含一个对外部类的引用,可以调用外部类中的所有字段和方法。

package com.meran.thinkingInJava.innerClass;interface Incrementable{void increment();}class Callee1 implements Incrementable{private int i=0; public void increment(){i++;System.out.println(i);}}class MyIncrement{public void increment(){ System.out.println("Another method");}static void f(MyIncrement mi){mi.increment();};}class Callee2 extends MyIncrement{private int i=0;public void increment(){super.increment();i++;System.out.println(i);}private class Closure implements Incrementable{public void increment(){Callee2.this.increment();}}Incrementable getCallbackReference(){return new Closure();}}class Caller{private Incrementable callbackReference;    Caller(Incrementable cbh){callbackReference=cbh;}    void go(){callbackReference.increment();}}public class CallBacks {public static void main(String [] args){Callee1 c1=new Callee1();Callee2 c2=new Callee2();MyIncrement.f(c2);Caller caller1=new Caller(c1);Caller caller2=new Caller(c2.getCallbackReference());caller1.go();caller1.go();caller2.go();caller2.go();}}


 

Another method112Another method2Another method3


这个例子掩饰了外围类实现接口与内部类实现接口间的区别。 Callee2 继承自MyIncrement 后者已经有了一个increment() 方法,并且与incrementable 接口完全不相关。如果Calle2继承了MyIncrement ,就不能为了Incrementable 用途而覆盖 increment()s覆盖increment 方法,于是只能使用内部类独立实现increment。当创建了一个内部类的时候并没有在外围类的接口中添加东西,也没有修改外围接口。

 

内部类Closure 实现了Incrementable ,以提供一个”钩子“(hook)-------而且是一个安全的钩子。无论谁获得 Incrementable 都只能使用 increment()方法。

 

Caller 的构造器需要一个Incrementable的引用类型作为参数,然后再以后的某个时刻,Caller对象可以使用此引用回调Callee类

 

内部类的继承: java 编程思想212.

内部类可以被覆盖么??: 详见213页。