国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

Java內(nèi)部類

2019-11-14 22:36:47
字體:
供稿:網(wǎng)友
java內(nèi)部類作者:禪樓望月(http://m.survivalescaperooms.com/yaoyinglong)1.什么是內(nèi)部類

簡單的說就是在一個(gè)類、接口或者方法的內(nèi)部創(chuàng)建另一個(gè)類。這樣理解的話創(chuàng)建內(nèi)部類的方法就很明確了。

package com.gissky.innerClass;public class Path {    public class Start{        public Start(String start){            this.start=start;        }        PRivate String start;        public String getStart() {            return start;        }    }    public class End{        public End(String end){            this.end=end;        }        private String end;        public String getEnd() {            return end;        }    }}
2.內(nèi)部類的實(shí)例化2.1 在外部類的非靜態(tài)方法內(nèi)部實(shí)例化,這個(gè)很簡單,和我們平時(shí)做的一樣。
public Start start(String start){    return new Start(start);}public End end(String end){    return new End(end);}
2.2 在外部類的非靜態(tài)方法外部的任意位置創(chuàng)建內(nèi)部類對象的時(shí)候,必須具體指明這個(gè)對象的類型,即:OuterClassName.InnerClassName,并且必須在有外部類對象的前提下進(jìn)行,使用類似:外圍類對象.new 內(nèi)部類();這樣的語法。
public static void main(String[] args){    Path path=new Path();    Path.Start start=path.new Start("my home");    Path.End end=path.new End("fu zhou");    path.Go(start, end);}
3. 內(nèi)部類有一個(gè)指向外部類的對象的引用

內(nèi)部類擁有其外部類的所有元素的訪問權(quán)。這是如何做到的呢?修改一下上面的程序:

public class Path {    private double startTime;    private double endTime;    public class Start{        public Start(String start){            startTime=new Date().getTime();            this.start=start;        }        private String start;        public String getStart() {            return start;        }    }    public class End{        public End(String end){            this.end=end;            endTime =new Date().getTime();        }        private String end;        public String getEnd() {            return end;        }    }        public void Go(Start start,End end){        System.out.println("start to end");        System.out.println(endTime-startTime);    }    public Start start(String start){        return new Start(start);    }    public End end(String end){        return new End(end);    }}

這是編譯器已經(jīng)幫我們生成了3個(gè).class文件:

image

前兩個(gè)便是編譯器生成的內(nèi)部類的.class文件,奇怪的是它們是以其外部類開頭再加上$和自己類的名字。我們用javap反編譯工具查看一下:

image

由此我們便可以知道,內(nèi)部類中訪問外部類的成員變量是通過一個(gè)調(diào)用外部類的一個(gè)靜態(tài)方法進(jìn)行的,該靜態(tài)方法須傳入一個(gè)外圍類的引用。

到這里應(yīng)該明白2.2中提到的“在外部類的非靜態(tài)方法外部的任意位置創(chuàng)建內(nèi)部類對象的時(shí)候,必須具體指明這個(gè)對象的類型,即:OuterClassName.InnerClassName,并且必須在有外部類對象的前提下進(jìn)行”的原因了吧。那是因?yàn)椋瑑?nèi)部類要連接到創(chuàng)建它的外部類對象上。

這樣做不是存在安全風(fēng)險(xiǎn)嗎?這種擔(dān)心是很有道理的。任何人都可以通過調(diào)用access$0方法很容易地讀取到私有域beep。當(dāng)然,access$0不是Java的合法方法名。但熟悉類文件結(jié)構(gòu)的黑客可以使用十六進(jìn)制編輯器輕松地創(chuàng)建一個(gè)用虛擬機(jī)指令調(diào)用那個(gè)方法的類文件。由于隱秘地訪問方法需要擁有包可見性,所以攻擊代碼需要與被攻擊類放在同一個(gè)包中。

總而言之,如果內(nèi)部類訪問了私有數(shù)據(jù)域,就有可能通過附加在外圍類所在包中的其他類訪問它們,但做這些事情需要高超的技巧和極大的決心。程序員不可能無意之中就獲得對類的訪問權(quán)限,而必須刻意地構(gòu)建或修改類文件才有可能達(dá)到這個(gè)目的。

4. 靜態(tài)內(nèi)部類

首先靜態(tài)內(nèi)部類沒有像普通內(nèi)部類那么多的限制了,它就不需要對外部類對象的引用。

有時(shí)候,使用內(nèi)部類只是為了把一個(gè)類隱藏在另外一個(gè)類的內(nèi)部,并不需要內(nèi)部類引用外圍類對象。為此,可以將內(nèi)部類聲明為static,以便取消產(chǎn)生的引用。

注釋:在內(nèi)部類不需要訪問外圍類對象的時(shí)候,應(yīng)該使用靜態(tài)內(nèi)部類。有些程序員用嵌套類(nested class)表示靜態(tài)內(nèi)部類。

注釋:聲明在接口中的內(nèi)部類自動(dòng)成為static和public。

5. 內(nèi)部類與向上轉(zhuǎn)型
public interface Fly {    public void fly();}
public class Animal {    private class Bird implements Fly{        @Override        public void fly() {            System.out.println("Bird.flu()");        }        }        public Fly Bfly(){        return new Bird();    }    public static void main(String[] args) {        Animal animal=new Animal();        Fly fly=animal.Bfly();        fly.fly();    }}

由上述代碼可知,我們無法將Fly接口向下轉(zhuǎn)型,因?yàn)槲覀儫o法知道內(nèi)部類Bird的名字(它是private)。因此private內(nèi)部類可以完全阻止任何依賴于類型的編碼。客戶端不能訪問到任何新加在內(nèi)部類中的接口,所以擴(kuò)展接口是沒有價(jià)值的(阻止了is-like-a形式的出現(xiàn))。并且由于內(nèi)部類是private的,因此它對于客戶端來說是完全不可見的,并且不可用。所得到的知識指向基類或接口的引用,方便的隱藏了實(shí)現(xiàn)細(xì)節(jié)。

6. 局部內(nèi)部類

即,定義在方法和作用域內(nèi)的內(nèi)部類。使用理由:在你的方法或作用域內(nèi)由于某種原因要使用一個(gè)類來輔助你的程序,但是你又不想這個(gè)類是公用的。

如,這樣一個(gè)需求:我進(jìn)行一個(gè)評價(jià)工作,我選取了指標(biāo),然后根據(jù)不同的指標(biāo)讓用戶選擇不同的模型來計(jì)算該指標(biāo)的評價(jià)值。這樣一來,我就需要記錄:指標(biāo)名稱、模型名稱、模型參數(shù)。然后通過反射來計(jì)算。實(shí)際工作中我這樣設(shè)計(jì):

public InfModel Execute(InfModel infModel, String measure, Users user) {        //region 內(nèi)部類--用于構(gòu)造各個(gè)指標(biāo)所使用的模型及參數(shù)        class Model{            public Method execute;            public Object intance;            public String modelParam;                        /**構(gòu)造器             * @param execute                模型執(zhí)行的方法接口             * @param intance                模型實(shí)例             * @param modelParam             構(gòu)造模型所需參數(shù)             */            public Model(Method execute,Object intance, String modelParam){                this.modelParam=modelParam;                this.execute=execute;                this.intance=intance;            }        }        //endregion        //后續(xù)工作}

局部類不能用public或private訪問說明符進(jìn)行聲明。它的作用域被限定在聲明這個(gè)局部類的塊中。

局部類有一個(gè)優(yōu)勢,即對外部世界可以完全地隱藏起來。除Execute方法之外,沒有任何方法知道Model類的存在。

7.匿名內(nèi)部類
public class AnonymousInnerClass {    public Destination destination(final String dest){        return new Destination() {            @Override            public String readLabel() {                return dest;            }        };    }    public static void main(String[] args){        AnonymousInnerClass aic=new AnonymousInnerClass();        System.out.println(aic.destination("天涯海角").readLabel());    }}

由上面的代碼可以看出,匿名內(nèi)部類也就是沒有類名的一個(gè)內(nèi)部類。因此不要向匿名內(nèi)部類中添加其基類中沒有的接口(因?yàn)榧由弦彩前准?,外面是訪問不到的)。但是為了實(shí)現(xiàn)的需要可以添加一些私有的成員。同時(shí)我們也注意到,內(nèi)部類內(nèi)部希望使用一個(gè)在其外部定的對象時(shí),編譯器則要求其參數(shù)應(yīng)用必須是final的。

為什么這個(gè)參數(shù)必須為final的呢?為此我們仔細(xì)地考查一下控制流程。

  1. 調(diào)用destination方法;
  2. 調(diào)用new Destination() 創(chuàng)造內(nèi)部類;
  3. destination方法結(jié)束,此時(shí),destination方法的dest參數(shù)已經(jīng)不存在了。
  4. 然后,在以后的某個(gè)地方Destination調(diào)用readLabel方法,return dest。

這時(shí)在內(nèi)部類中產(chǎn)生了“閉包”,閉包將使得dest脫離了它所在的方法繼續(xù)存在,這樣在readLabel方法中就可以任意的修改dest了,但是外部類對此卻全然不知。因此,dest必須是final的。

其實(shí)為了能夠讓readLabel方法工作,Destination類(這里是一個(gè)匿名內(nèi)部類,編譯器給它取的名字為AnonymousInnerClass$1.class)在dest域釋放之前將dest域在自己的構(gòu)造器中進(jìn)行備份。

image

上面的例子對于接口或者一個(gè)還有無參構(gòu)造器的類來說是可行的。但是當(dāng)一個(gè)類的構(gòu)造器有參數(shù)的時(shí)候該怎么辦呢?很簡單,就像我們new一個(gè)有參構(gòu)造器的類一樣來構(gòu)造即可:

public abstract class Base {    {        System.out.println("Base instane initializer");    }    public Base(int i){        System.out.println("Base constructor, i="+i);    }    public abstract void f();}
public class AnonymousInnerClass {    public static Base getBase(int i){        return new Base(i) {            {                System.out.println("Inside instane initializer");            }            @Override            public void f() {                System.out.println("In AnonymousInnerClass f()");                        }        };    }    public static void main(String[] args){        Base base=getBase(5);        base.f();    }}

我們發(fā)現(xiàn)這里的變量i沒有要求必須是final的,這是為什么呢?因?yàn)?,這是變量i不是在內(nèi)部類內(nèi)部使用,而是被傳遞給了其基類的構(gòu)造函數(shù),它并不會(huì)在匿名內(nèi)部類中被直接使用。(?'ω')?注:要不要加final就是看局部內(nèi)部類的外圍方法結(jié)束后,其參數(shù)是不是還要被局部內(nèi)部類使用,如果還要被使用,則要加final否則就不用加了。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 杭州市| 乐安县| 台湾省| 托里县| 淮安市| 鄂尔多斯市| 文登市| 庄浪县| 台安县| 上杭县| 沈丘县| 沅陵县| 白朗县| 汶上县| 界首市| 和硕县| 增城市| 蒲城县| 太谷县| 麟游县| 巩义市| 乐亭县| 太仓市| 班戈县| 陵水| 怀来县| 万载县| 深圳市| 新乡县| 林州市| 铁力市| 乐东| 民和| 兴业县| 无棣县| 玛曲县| 溆浦县| 溆浦县| 吉水县| 长岭县| 忻州市|