Java内部类

什么是内部类

将一个类的定义放在另一个类的内部,就称之为内部类

创建内部类

public class Parcel1 {
    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 Destination to(String s){
        return new Destination(s);
    }
    public Contents contents(){
        return new Contents();
    }
    public void ship(String dest){
        Contents c = new Contents();
        Destination d = new Destination(dest);
        System.out.println(d.readLabel());
    }
    public static void main(String args[]){
        Parcel1 p = new Parcel1();
        p.ship("Tasmania");
    }
}

可以使外部类有一个方法,该方法返回一个指向内部类的引用,就像在to()和contents()方法

连接到外部类

内部类拥有其外围类的所有元素的访问权;
内部类的对象可以访问其外为对象的所有成员

.this与.new

  • 1. .this可以生成对外部类的对象的引用
public class DotThis{
    void f(){System.out.println("DoThis.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().f();//利用outer函数调用外部类对象
    }
}
  • 2. .new告知某些其他对象,去创建其某个内部类的对象;
public class DotNew{
    public class Inner{}
    public static void main(String args[]){
        DotNew dn = new DotNew();
        DotNew.Inner dni = dn.new Inner();//使用.new创建内部类对象
    }
}

内部类的向上转型

将内部类向上转型为其基类,尤其是转型为一个接口时;内部类就有了用武之地;从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上是一样的;

  • 创建以下接口
public interface Destination{
    String readLabel();
}

public interface Contents{
    int value();
}

class Parcel{
    private class PContents implements Contents{
        private int i = 11;
        public int value(){return i;}
    }
    protected class PDestination implements Destination{
        private String label;
        private PDestination(String whereTo){
            label = whereTo;
        }
        public String readLabel(){return label;}
    }
    public Destination destination(String s){
        return new PDestination(s);
    }
    public Contents contents(){
        return new PContents();
    }
}

public class TestParcel{
    public static void main(String args[]){
        Parcel p = new Parcel();
        Contents c = p.contents();
        Destination d = p.destination("Tasmania");
    }
}

在方法和作用域内的内部类

可以在一个方法或者一个作用域内部定义内部类;
有两个理由这么做:
1.实现了某个类型的接口,于是可以创建并返回对其引用
2.要解决一个问题,于是创建一个类来辅助解决方案,但又不希望这个类是公用的

  • 可以这么做:
    1.一个定义在方法中的类
    2.一个定义在作用域内的类,此作用域在方法的内部
    3.一个实现了接口的匿名类
    4.一个匿名类,扩展了有非默认构造器的类
    5.一个匿名类,执行了字段的初始化
    6.一个匿名类,通过实例初始化实现构造(匿名类不可能有构造器)

  • 1.方法中的类

public class Parcel{
    public Destination destination(String s){
        class PDestination implements Destination{
            private String label;
            private PEestination(String whereTo){
                label = whereTo;
            }
            public String readLabel(){return label;}
        }
        return new PDestination(s);
    }

    public static void main(String args[]){
        Parcel p = new Parcel();
        Destination d = p.destination("Tasmania");
    }
}
  • 2.嵌入作用域中的内部类
public class Parcel{
    private void internalTracking(boolean b){
        if(b){
            class TrackingSlip{
                private String id;
                TrackingSlip(String s){
                    id = s;
                }
                String getSlip(){return id;}
            }
            TrackingSlip ts = new TrackingSlip("slip");
            String s = ts.getSlip();
        }
    }

    public void track(){internalTracking(true);}

    public static void main(String args[]){
        Parcel p = new Parcel();
        p.track();
    }
}

匿名内部类

没有名字的类;作为实现了某个接口或基类的对象

public class Parcel{
    public Contents contents(){
        return new Contents(){//匿名类
            private int i = 11;
            public int value(){return i;}
        };
    }

    public static void main(String args[]){
        Parcel p = new Parcel();
        Contents c = p.contents();
    }
}
  • 注意点:
    1.若基类需要一个带有参数的构造器;则给匿名类一个参数:
public class Parcel{
    public Wrapping wrapping(int x){
        return new Wrapping(x){
        //这个参数是提供给基类构造器的,匿名类中不能使用
            public int value(){
                return super.value()*47;
            }
        };
    }
    public static void main(String args[]){
        Parcel p = new Parcel();
        Wrapping w = p.wrapping(10);
    }
}

Wrapping基类如下:

public class Wrapping{
    private int i;
    public Wrapping(int x){i = x;}
    public int value(){return i;}
}

2.若希望匿名类可以使用一个定义在外部的对象,则需要将该参数声明为final;//代码太多懒得写了……

工厂方法

interface Service{
    void method1();
    void metiod2();
}

interface ServiceFactory{
    Service getService();
}

class Implementation1 implements Servie{
    private Implementation1(){}
    public void method1(){
        ...
    }
    public void method2(){
        ...
    }
    public static ServiceFactory factory = new ServiceFactory(){
        publc Service getService(){
            return new Implementation1();
        }
    };

}

class Implementation2 implements Servie{
    private Implementation1(){}
    public void method1(){
        ...
    }
    public void method2(){
        ...
    }
    public static ServiceFactory factory = new ServiceFactory(){
        publc Service getService(){
            return new Implementation2();
        }
    };
    
}

public class Factories{
    public static void serviceConsumer(ServiceFactory fact){
        Service s = fact.getService();
        s.method1();
        s.method2();
    }

    public static void main(String args[]){
        serviceConsumer(Implemention1.factory);
        serviceConsumer(Implemention2.factory);
    }
}

嵌套类

将内部类声明为static;由此,内部类对象与外部类对象之间没有了联系

It means:
1.要创建嵌套类的对象,不需要其外部类的对象
2.不能从嵌套类的对象中访问非静态的外部类对象

普通的内部类的字段和方法只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段;也不能包含嵌套类

但是嵌套类就可以包含这些

public class Parcel{
    private static class ParcelContents implements Contents{
        private int i = 11;
        public int value(return i;)
    }
    protected static class ParcelDestination implements Destination{
        private String label;
        private ParceDestination(String whereTo){
            label = whereTo;
        }
        public String readLabel(){return label;}
        public static void f(){
            static int x = 10;
            static class AnotherLevel{
                public static void f(){}
                static int x = 10;
            }
        }
        public static Destination destination(String s){
            return new ParcelContents();
        }
        public static Contents contents(){
            return new ParcelContents();
        }

        public static void main(String args[]){
            Contents c = contents();
            Destination d = destination("Tasmania");
        }
    }
}

接口内部的类

用于进行测试

从多层嵌套类中访问外部类的成员

一个内部类无论被嵌套多少层,其依旧可以透明的访问所有它嵌入的外围类的所有成员


class MNA{
    private void f(){}
    class A{
        private void g(){}
        public class B{
            void h(){
                g();
                f();
            }
        }
    }   
}

public class MultiNestingAccess{
    public static void main(String args[]){
        MNA mna = new MNA();
        MNA.A mnaa = mna.new A();
        MNA.A.B mnaab = mnaa.new B();
        mnaab.h();
    }
}

闭包和回调

package closure;

interface Incrementable{
    void increment();
}
class MyIncrement{
    public void increment(){System.out.println("Other operation");}
    static void f(MyIncrement mi){mi.increment();}
}

class Callee1 implements Incrementable{
    private int i = 0;
    public void increment(){
        i++;
        System.out.println(i);
    }
}
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();
    }
}

输出:
Other operation
1
1
2
Other operation
2
Other operation
3

内部类与控制框架

内部类的继承

eg:

class WithInner{
    class Inner{}
}

public class InheritInner extends WithInner.Inner{
    InheritInner(WithInner wi){
        wi.super();//必须使用此句
    }
    public static void main(String args[]){
        WithInner wi = new WithInner();
        InheritInner ii  = new InheritInner(wi);
    }
}

内部类可以被覆盖吗

不能被覆盖的情况

class Egg{
    private Yolk y;
    protected class Yolk{
        public Yolk(){
            ...
        }
    }
    public Egg(){
        ...
        y = new Yolk();
    }
}

public class BigEgg extends Egg{
    public class Yolk{
        pubic Yolk(){...}
    }
    public static void main(String args[]){
        new BigEgg();
    }   
}

能被覆盖的情况

必须使用extends

class Egg{
    private Yolk y;
    protected class Yolk{
        public Yolk(){
            ...
        }
    }
    public Egg(){
        ...
        y = new Yolk();
    }
}

public class BigEgg extends Egg{
    public class Yolk extends Egg.Yolk{
        pubic Yolk(){...}
    }
    public static void main(String args[]){
        new BigEgg();
    }   
}

局部内部类与匿名类的区别

一个有名字一个没有名字

内部类标识符

Xxx&Xxx.java


资料:《Thking in java》

你可能感兴趣的:(Java内部类)