JAVA(十六)--内部类

来源:互联网 发布:mac储存位置更改 编辑:程序博客网 时间:2024/05/29 19:47
  1. .this 和 .new
    如果在内部类中需要返回外部类的引用,那么可以用外部类类名,加上.this。
    如果要使用内部类,又不想使用方法来返回引用,那就要用到外部类类名.new
public class Outer{    public class Inner{        public Outer outer(){            return Outer.this; //返回外部类引用            }        }    public static void main(String[] args){        Outer o=new Outer();        Inner i=Outer.new Inner();        }}

我们不可能在没有外部类的情况下实例化内部类的对象,因为内部类依靠外部类而存在(要new一个内部类,必须使用.new )
然而,如果我们用nested class(静态内部类),跟其他静态方法, 属性一样,那就不需要外部类了。
2. 内部类的权限:外部类只有两个权限,public 或 package。而内部类则还可以是protected(同一个package里和子类的可以访问,protected有package的权限)和private(只有其外部类能够访问)。private内部类给了设计者一个完全隐藏实现的细节的方法。客户程序员不能获晓内部类的情况。
3. 匿名内部类
即没有名字的内部类,隐式继承。用return new className(){//};的格式

public class Parcel7{    //contents方法中结合了返回类引用跟类的构造    //注意分号,跟方法后面加分号一样    public Contents contents(){        return new Contentes(){            private int i=11;            public int value(){return i;}        };    }    public static void main(String[] args){        Parcel7 p=new Parcel7();        Contents c=p.contents();    }}

该匿名内部类的意思是创建一个继承自Contents的匿名类对象。上面的代码是下面的简写。

public class Parcel7a{    class MyContents implements Contents{        private int i=11;        public int value(){return i;}    }    public Contents contents(){        return new MyContents();    }    public static void main(String[] args){        Parcel7a p=new Parcel7a();        Contents c=p.contents();    }}

如果我们定义了一个匿名内部类,想使用定义在内部类外的对象,编译器要求该对象(参数)的引用为final。
注意:这跟传参数进去是不同的。见代码:

public class Parcel9{    //传参到内部类    //需要有Wrapping这个类    public Wrapping wrapping(int x){        return new Wrapping(x){            public int value(){                return super.value()*47;            }        };    }    //只传参到产生内部类的方法    //需要Destination这个类    public Destination destination(final String dest){        return new Destination(){            private String label=dest;            public String readLabel(){                return label;            }        };    }}public static void main(String[] args){    Parcel9 p=new Parcel9();    Destination d=p.destination("Tasmania");}

如果我们需要想构造器那样的操作,但因为匿名内部类没有名字,不能像以前普通类那样。不过使用instance initialization就可以在效果上实现构造函数了。其实就是用一个块

abstract class Base{    public Base(int i){        //do something    }}public Base getBase(int i){//不要忘了匿名内部类是继承的,Base需要参数    return new Base(int i){        {            System.out.println("Inside Instance Initialization");        }        public void f(){            System.out.println("f");        }    };}

4.Nested Class/静态内部类
如果我们不需要在外部类跟内部类间有联系,那么就可以将内部类设为static。普通内部类对象总是隐式的含有外部类对象的引用。但对于nested class,我们不需要先创建外部类来创建内部类。但是我们也不能通过nested class对象来获取非静态的外部类的成员。

public class DotNew {        //非静态i 无法被Inner获取        //private int i=0;        private static int i=0;        static class Inner{            void f(){                System.out.println(i);            }        }    public static void main(String[] args){        Inner ic=new Inner();        ic.f();    }}

因为接口里的所有东西都是public和static的,所以我们可以在接口内放Nested Class。当我们想要所有的实现同一接口的接口或类都有某一相同点的操作时,我们就可以将类放在接口中。
5. Multiply nested class
类可以多重嵌套,注意new时候的语法

public class DotNew {    DotNew(){        System.out.println("Depth0");    }        class Depth1{            Depth1(){                System.out.println("Depth1");            }            class Depth2{                Depth2(){                    System.out.println("Depth2");                }            }        }    public static void main(String[] args){        DotNew d=new DotNew();        DotNew.Depth1 d1=d.new Depth1();//说明是DotNew的Depth1        DotNew.Depth1.Depth2 d2=d1.new Depth2();//说明是DotNew的Depth1的Depth2    }}

6.为什么用内部类
首先用内部类可以解决多继承的问题,当然接口也可以。但是内部类的话实现方法略有不同。

class D{}abstract class E{}class Z extends D{    E makesE(){        return new E(){        };    }}public class MultiImplemention{    static void takesD(D d){}    public static void main(String[] args){        Z z=new Z();        z.makesE();    }}

注意:
1.内部类可以有多个实例,每个实例的状态跟外部类都是相互独立的,是个独立的实体。
2.因为匿名内部类是属于返回的类(称为Father)的子类。所以要通过Father的引用来访问内部类的方法,Father中必须有相应的方法,可以将Father作为抽象类。
3.内部类可以作为一次性使用的东西。

class D{    int d=0;}abstract class Z{    int z=1000;    abstract void print();}class E extends D{    E(){        System.out.println("D"+d);    }    Z makeZ(){        return new Z(){            {                System.out.println("Z"+z);            }            void print(){                System.out.println("Z"+z);            }        };    }}public class DotNew {    public static void main(String[] args){        E e=new E();        Z z1=e.makeZ();        Z z2=e.makeZ();        z1.z++; //注意的第一点        z2.z--;        z1.print();        z2.print();    }}/*output:D0Z1000Z1000Z1001Z999*/

7.内部类的继承
单独继承内部类要有作用域的说明 基类.基类的内部类

class WithInner{    class Inner{}}public class InheritInner extends WithInner.Inner{//要有构造函数,参数为基类,还要调用基类.super();    InheritInner(WithInner wi){        wi.super();    }    public static void main(String[] args){        WithInner wi=new WithInner();        InheritInner ii=new InheritInner(wi);    }}

8.内部类的重写
内部类不能通过简单的像方法一样同名,重写。

class Egg{    private Yolk y;    protected class Yolk{        public Yold(){            System.out.println("Egg.Yolk()");        }    }    public Egg(){        System.out.println("New Egg()");        y=new Yolk();    }}public class BigEgg extends Egg{    public class Yolk{        public Yolk(){            System.out.println("BigEgg.Yolk()");        }    }    public static void main(String[] args){        new BigEgg();    }}/*outputNew Egg()Egg.Yolk()*/

由上面代码看出并没有重写覆盖到。其实两个内部类是独立的个体,各自在各自的命名空间里。如果需要重写,则需要显示的继承要重写的内部类

class Egg2{    protected class Yolk{        public Yolk(){            System.out.println("Egg2.Yolk()");        }        public void f(){            System.out.println("Egg2.Yolk.f()");        }    private Yolk y=new Yolk();    public Egg2(){        System.out.println("New Egg2()");    }    public void insertYolk(Yolk yy){        y=yy;    }}public class BigEgg2 extends Egg2{//显式继承Egg2.Yolk,但要先继承Egg2    public class Yolk extends Egg2.Yolk{        public Yolk(){            System.out.println("BigEgg2.Yolk()");        }        public void f(){            System.out.println("BigEgg2.Yolk.f()");        }    }    public BigEgg2(){        insertYolk(new Yolk());    }    public static void main(String[] args){        Egg2 e2=new BigEgg2();        e2.g();    }}/*output:Egg2.Yolk()New Egg2()Egg2.Yolk()BigEgg2.Yolk()BigEgg2.Yolk.f()*/      

注意:从输出我们可以回忆一下初始化的顺序:父类的静态,子类的静态,父类的非静态,父类的构造,子类的非静态,子类的构造

  1. Local inner classes
    即写在方法里面的类,有点像匿名内部类
Interface Counter{    int next();}public class LocalInnerClass{    Counter getCounter1(final String name){        class LocalCounter implements Counter{            public LocalCounter(){                System.out.println("LocalCounter");            }            public int next(){                System.out.print(name);                return count++;            }        }        return new LocalCounter();    }    Counter getCounter2(final String name){        return new Counter(){            {                System.out.println("AnnoymousCounter");            }            public int next(){                System.out.println(name);                return count++;            }        };    }    public static void main(){        LocalInnerClass lic=new LocalInnerClass();        Counter c1=lic.getCounter("Local inner");        Counter c2=lic.getCounter2("Annoymous inner");        System.out.println(c1.next()+" "+c2.next());    }}/*output略*/

可见local inner class跟匿名内部类很像。但是localinnerclass有名字。但是local inner class的名字在所在块(方法)的外部也并不可见(即你不能在外部
LocalClass lc=new LocalClass();)。所以使用local还是annoymous的判断可以是1.需要用到构造函数2.需要制造多于一个的对象

0 0
原创粉丝点击