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》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Java 内部类 分四种:成员内部类、局部内部类、静态内部类和匿名内部类。 1、成员内部类: 即作为外部类的一个成...
    ikaroskun阅读 1,182评论 0 13
  • 一、介绍 内部类是指在一个外部类的内部再定义一个类。类名不需要和文件夹相同。内部类可以是静态static的,也可用...
    一只好奇的茂阅读 940评论 4 21
  • [toc] 内部类 内部类作为外部类的成员,可以使用人已访问控制符修饰。 外部类的上一级程序单元是包,所以只有两个...
    卡路fly阅读 290评论 0 2
  • 很久没你的消息 我装作毫不在意 提示音毫无预兆的响起 迫不及待地点开 满心欢喜 语气热...
    兔八哥的泡芙阅读 322评论 0 0
  • 从毕业到现在,从事外贸行业有七八年,回顾这八年,我总是在迷茫中轮回,不知道未来该如何定位,缺少自信,也害怕走出舒适...
    琴语言言阅读 244评论 3 0