<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 0,  comments - 17,  trackbacks - 0
    對(duì)于這個(gè)系列里的問(wèn)題,每個(gè)學(xué)Java的人都應(yīng)該搞懂。當(dāng)然,如果只是學(xué)Java玩玩就無(wú)所謂了。如果你認(rèn)為自己已經(jīng)超越初學(xué)者了,卻不很懂這些問(wèn)題,請(qǐng)將你自己重歸初學(xué)者行列。內(nèi)容均來(lái)自于CSDN的經(jīng)典老貼。

    問(wèn)題一:我聲明了什么!

    String s = "Hello world!";

    許多人都做過(guò)這樣的事情,但是,我們到底聲明了什么?回答通常是:一個(gè)String,內(nèi)容是“Hello world!”。這樣模糊的回答通常是概念不清的根源。如果要準(zhǔn)確的回答,一半的人大概會(huì)回答錯(cuò)誤。
    這 個(gè)語(yǔ)句聲明的是一個(gè)指向?qū)ο蟮囊茫麨?#8220;s”,可以指向類(lèi)型為String的任何對(duì)象,目前指向"Hello world!"這個(gè)String類(lèi)型的對(duì)象。這就是真正發(fā)生的事情。我們并沒(méi)有聲明一個(gè)String對(duì)象,我們只是聲明了一個(gè)只能指向String對(duì)象的 引用變量。所以,如果在剛才那句語(yǔ)句后面,如果再運(yùn)行一句:

    String string = s;

    我們是聲明了另外一個(gè)只能指向String對(duì)象的引用,名為string,并沒(méi)有第二個(gè)對(duì)象產(chǎn)生,string還是指向原來(lái)那個(gè)對(duì)象,也就是,和s指向同一個(gè)對(duì)象。

    問(wèn)題二:"=="和equals方法究竟有什么區(qū)別?

    ==操作符專(zhuān)門(mén)用來(lái)比較變量的值是否相等。比較好理解的一點(diǎn)是:
    int a=10;
    int b=10;
    則a==b將是true。
    但不好理解的地方是:
    String a=new String("foo");
    String b=new String("foo");
    則a==b將返回false。

    根 據(jù)前一帖說(shuō)過(guò),對(duì)象變量其實(shí)是一個(gè)引用,它們的值是指向?qū)ο笏诘膬?nèi)存地址,而不是對(duì)象本身。a和b都使用了new操作符,意味著將在內(nèi)存中產(chǎn)生兩個(gè)內(nèi)容 為"foo"的字符串,既然是“兩個(gè)”,它們自然位于不同的內(nèi)存地址。a和b的值其實(shí)是兩個(gè)不同的內(nèi)存地址的值,所以使用"=="操作符,結(jié)果會(huì)是 false。誠(chéng)然,a和b所指的對(duì)象,它們的內(nèi)容都是"foo",應(yīng)該是“相等”,但是==操作符并不涉及到對(duì)象內(nèi)容的比較。
    對(duì)象內(nèi)容的比較,正是equals方法做的事。

    看一下Object對(duì)象的equals方法是如何實(shí)現(xiàn)的:
    boolean equals(Object o){

    return this==o;

    }
    Object 對(duì)象默認(rèn)使用了==操作符。所以如果你自創(chuàng)的類(lèi)沒(méi)有覆蓋equals方法,那你的類(lèi)使用equals和使用==會(huì)得到同樣的結(jié)果。同樣也可以看出, Object的equals方法沒(méi)有達(dá)到equals方法應(yīng)該達(dá)到的目標(biāo):比較兩個(gè)對(duì)象內(nèi)容是否相等。因?yàn)榇鸢笐?yīng)該由類(lèi)的創(chuàng)建者決定,所以O(shè)bject把 這個(gè)任務(wù)留給了類(lèi)的創(chuàng)建者。

    看一下一個(gè)極端的類(lèi):
    Class Monster{
    private String content;
    ...
    boolean equals(Object another){ return true;}

    }
    我覆蓋了equals方法。這個(gè)實(shí)現(xiàn)會(huì)導(dǎo)致無(wú)論Monster實(shí)例內(nèi)容如何,它們之間的比較永遠(yuǎn)返回true。

    所 以當(dāng)你是用equals方法判斷對(duì)象的內(nèi)容是否相等,請(qǐng)不要想當(dāng)然。因?yàn)榭赡苣阏J(rèn)為相等,而這個(gè)類(lèi)的作者不這樣認(rèn)為,而類(lèi)的equals方法的實(shí)現(xiàn)是由他 掌握的。如果你需要使用equals方法,或者使用任何基于散列碼的集合(HashSet,HashMap,HashTable),請(qǐng)察看一下java doc以確認(rèn)這個(gè)類(lèi)的equals邏輯是如何實(shí)現(xiàn)的。

    問(wèn)題三:String到底變了沒(méi)有?

    沒(méi)有。因?yàn)镾tring被設(shè)計(jì)成不可變(immutable)類(lèi),所以它的所有對(duì)象都是不可變對(duì)象。請(qǐng)看下列代碼:

    String s = "Hello";
    s = s + " world!";

    s 所指向的對(duì)象是否改變了呢?從本系列第一篇的結(jié)論很容易導(dǎo)出這個(gè)結(jié)論。我們來(lái)看看發(fā)生了什么事情。在這段代碼中,s原先指向一個(gè)String對(duì)象,內(nèi)容是 "Hello",然后我們對(duì)s進(jìn)行了+操作,那么s所指向的那個(gè)對(duì)象是否發(fā)生了改變呢?答案是沒(méi)有。這時(shí),s不指向原來(lái)那個(gè)對(duì)象了,而指向了另一個(gè) String對(duì)象,內(nèi)容為"Hello world!",原來(lái)那個(gè)對(duì)象還存在于內(nèi)存之中,只是s這個(gè)引用變量不再指向它了。
    通過(guò)上面的說(shuō)明, 我們很容易導(dǎo)出另一個(gè)結(jié)論,如果經(jīng)常對(duì)字符串進(jìn)行各種各樣的修改,或者說(shuō),不可預(yù)見(jiàn)的修改,那么使用String來(lái)代表字符串的話(huà)會(huì)引起很大的內(nèi)存開(kāi)銷(xiāo)。 因?yàn)镾tring對(duì)象建立之后不能再改變,所以對(duì)于每一個(gè)不同的字符串,都需要一個(gè)String對(duì)象來(lái)表示。這時(shí),應(yīng)該考慮使用StringBuffer 類(lèi),它允許修改,而不是每個(gè)不同的字符串都要生成一個(gè)新的對(duì)象。并且,這兩種類(lèi)的對(duì)象轉(zhuǎn)換十分容易。
    同時(shí),我們還可以知道,如果要使用內(nèi)容相同的字符串,不必每次都new一個(gè)String。例如我們要在構(gòu)造器中對(duì)一個(gè)名叫s的String引用變量進(jìn)行初始化,把它設(shè)置為初始值,應(yīng)當(dāng)這樣做:
    public class Demo {
    private String s;
    ...
    public Demo {
    s = "Initial Value";
    }
    ...
    }
    而非
    s = new String("Initial Value");
    后 者每次都會(huì)調(diào)用構(gòu)造器,生成新對(duì)象,性能低下且內(nèi)存開(kāi)銷(xiāo)大,并且沒(méi)有意義,因?yàn)镾tring對(duì)象不可改變,所以對(duì)于內(nèi)容相同的字符串,只要一個(gè) String對(duì)象來(lái)表示就可以了。也就說(shuō),多次調(diào)用上面的構(gòu)造器創(chuàng)建多個(gè)對(duì)象,他們的String類(lèi)型屬性s都指向同一個(gè)對(duì)象。
    上面的結(jié)論還基于這樣一個(gè)事實(shí):對(duì)于字符串常量,如果內(nèi)容相同,Java認(rèn)為它們代表同一個(gè)String對(duì)象。而用關(guān)鍵字new調(diào)用構(gòu)造器,總是會(huì)創(chuàng)建一個(gè)新的對(duì)象,無(wú)論內(nèi)容是否相同。
    至 于為什么要把String類(lèi)設(shè)計(jì)成不可變類(lèi),是它的用途決定的。其實(shí)不只String,很多Java標(biāo)準(zhǔn)類(lèi)庫(kù)中的類(lèi)都是不可變的。在開(kāi)發(fā)一個(gè)系統(tǒng)的時(shí)候, 我們有時(shí)候也需要設(shè)計(jì)不可變類(lèi),來(lái)傳遞一組相關(guān)的值,這也是面向?qū)ο笏枷氲捏w現(xiàn)。不可變類(lèi)有一些優(yōu)點(diǎn),比如因?yàn)樗膶?duì)象是只讀的,所以多線(xiàn)程并發(fā)訪(fǎng)問(wèn)也不 會(huì)有任何問(wèn)題。當(dāng)然也有一些缺點(diǎn),比如每個(gè)不同的狀態(tài)都要一個(gè)對(duì)象來(lái)代表,可能會(huì)造成性能上的問(wèn)題。所以Java標(biāo)準(zhǔn)類(lèi)庫(kù)還提供了一個(gè)可變版本,即 StringBuffer。

    問(wèn)題四:final關(guān)鍵字到底修飾了什么?

    final使得被修飾的變量"不變",但是由于對(duì)象型變量的本質(zhì)是“引用”,使得“不變”也有了兩種含義:引用本身的不變,和引用指向的對(duì)象不變。

    引用本身的不變:
    final StringBuffer a=new StringBuffer("immutable");
    final StringBuffer b=new StringBuffer("not immutable");
    a=b;//編譯期錯(cuò)誤

    引用指向的對(duì)象不變:
    final StringBuffer a=new StringBuffer("immutable");
    a.append(" broken!"); //編譯通過(guò)

    可 見(jiàn),final只對(duì)引用的“值”(也即它所指向的那個(gè)對(duì)象的內(nèi)存地址)有效,它迫使引用只能指向初始指向的那個(gè)對(duì)象,改變它的指向會(huì)導(dǎo)致編譯期錯(cuò)誤。至于 它所指向的對(duì)象的變化,final是不負(fù)責(zé)的。這很類(lèi)似==操作符:==操作符只負(fù)責(zé)引用的“值”相等,至于這個(gè)地址所指向的對(duì)象內(nèi)容是否相等,==操作 符是不管的。

    理解final問(wèn)題有很重要的含義。許多程序漏洞都基于此----final只能保證引用永遠(yuǎn)指向固定對(duì)象,不能保證那 個(gè)對(duì)象的狀態(tài)不變。在多線(xiàn)程的操作中,一個(gè)對(duì)象會(huì)被多個(gè)線(xiàn)程共享或修改,一個(gè)線(xiàn)程對(duì)對(duì)象無(wú)意識(shí)的修改可能會(huì)導(dǎo)致另一個(gè)使用此對(duì)象的線(xiàn)程崩潰。一個(gè)錯(cuò)誤的解 決方法就是在此對(duì)象新建的時(shí)候把它聲明為final,意圖使得它“永遠(yuǎn)不變”。其實(shí)那是徒勞的。

    問(wèn)題五:到底要怎么樣初始化!

    本問(wèn)題討論變量的初始化,所以先來(lái)看一下Java中有哪些種類(lèi)的變量。
    1. 類(lèi)的屬性,或者叫值域
    2. 方法里的局部變量
    3. 方法的參數(shù)

    對(duì)于第一種變量,Java虛擬機(jī)會(huì)自動(dòng)進(jìn)行初始化。如果給出了初始值,則初始化為該初始值。如果沒(méi)有給出,則把它初始化為該類(lèi)型變量的默認(rèn)初始值。

    int類(lèi)型變量默認(rèn)初始值為0
    float類(lèi)型變量默認(rèn)初始值為0.0f
    double類(lèi)型變量默認(rèn)初始值為0.0
    boolean類(lèi)型變量默認(rèn)初始值為false
    char類(lèi)型變量默認(rèn)初始值為0(ASCII碼)
    long類(lèi)型變量默認(rèn)初始值為0
    所有對(duì)象引用類(lèi)型變量默認(rèn)初始值為null,即不指向任何對(duì)象。注意數(shù)組本身也是對(duì)象,所以沒(méi)有初始化的數(shù)組引用在自動(dòng)初始化后其值也是null。

    對(duì) 于兩種不同的類(lèi)屬性,static屬性與instance屬性,初始化的時(shí)機(jī)是不同的。instance屬性在創(chuàng)建實(shí)例的時(shí)候初始化,static屬性在 類(lèi)加載,也就是第一次用到這個(gè)類(lèi)的時(shí)候初始化,對(duì)于后來(lái)的實(shí)例的創(chuàng)建,不再次進(jìn)行初始化。這個(gè)問(wèn)題會(huì)在以后的系列中進(jìn)行詳細(xì)討論。

    對(duì) 于第二種變量,必須明確地進(jìn)行初始化。如果再?zèng)]有初始化之前就試圖使用它,編譯器會(huì)抗議。如果初始化的語(yǔ)句在try塊中或if塊中,也必須要讓它在第一次 使用前一定能夠得到賦值。也就是說(shuō),把初始化語(yǔ)句放在只有if塊的條件判斷語(yǔ)句中編譯器也會(huì)抗議,因?yàn)閳?zhí)行的時(shí)候可能不符合if后面的判斷條件,如此一來(lái) 初始化語(yǔ)句就不會(huì)被執(zhí)行了,這就違反了局部變量使用前必須初始化的規(guī)定。但如果在else塊中也有初始化語(yǔ)句,就可以通過(guò)編譯,因?yàn)闊o(wú)論如何,總有至少一 條初始化語(yǔ)句會(huì)被執(zhí)行,不會(huì)發(fā)生使用前未被初始化的事情。對(duì)于try-catch也是一樣,如果只有在try塊里才有初始化語(yǔ)句,編譯部通過(guò)。如果在 catch或finally里也有,則可以通過(guò)編譯。總之,要保證局部變量在使用之前一定被初始化了。所以,一個(gè)好的做法是在聲明他們的時(shí)候就初始化他 們,如果不知道要出事化成什么值好,就用上面的默認(rèn)值吧!

    其實(shí)第三種變量和第二種本質(zhì)上是一樣的,都是方法中的局部變量。只不過(guò)作為參數(shù),肯定是被初始化過(guò)的,傳入的值就是初始值,所以不需要初始化。

    問(wèn)題六:instanceof是什么東東?

    instanceof是Java的一個(gè)二元操作符,和==,>,<是同一類(lèi)東東。由于它是由字母組成的,所以也是Java的保留關(guān)鍵字。它的作用是測(cè)試它左邊的對(duì)象是否是它右邊的類(lèi)的實(shí)例,返回boolean類(lèi)型的數(shù)據(jù)。舉個(gè)例子:

    String s = "I AM an Object!";
    boolean isObject = s instanceof Object;

    我們聲明了一個(gè)String對(duì)象引用,指向一個(gè)String對(duì)象,然后用instancof來(lái)測(cè)試它所指向的對(duì)象是否是Object類(lèi)的一個(gè)實(shí)例,顯然,這是真的,所以返回true,也就是isObject的值為T(mén)rue。
    instanceof有一些用處。比如我們寫(xiě)了一個(gè)處理賬單的系統(tǒng),其中有這樣三個(gè)類(lèi):

    public class Bill {//省略細(xì)節(jié)}
    public class PhoneBill extends Bill {//省略細(xì)節(jié)}
    public class GasBill extends Bill {//省略細(xì)節(jié)}

    在處理程序里有一個(gè)方法,接受一個(gè)Bill類(lèi)型的對(duì)象,計(jì)算金額。假設(shè)兩種賬單計(jì)算方法不同,而傳入的Bill對(duì)象可能是兩種中的任何一種,所以要用instanceof來(lái)判斷:

    public double calculate(Bill bill) {
    if (bill instanceof PhoneBill) {
    //計(jì)算電話(huà)賬單
    }
    if (bill instanceof GasBill) {
    //計(jì)算燃?xì)赓~單
    }
    ...
    }
    這樣就可以用一個(gè)方法處理兩種子類(lèi)。

    然而,這種做法通常被認(rèn)為是沒(méi)有好好利用面向?qū)ο笾械亩鄳B(tài)性。其實(shí)上面的功能要求用方法重載完全可以實(shí)現(xiàn),這是面向?qū)ο笞兂蓱?yīng)有的做法,避免回到結(jié)構(gòu)化編程模式。只要提供兩個(gè)名字和返回值都相同,接受參數(shù)類(lèi)型不同的方法就可以了:

    public double calculate(PhoneBill bill) {
    //計(jì)算電話(huà)賬單
    }

    public double calculate(GasBill bill) {
    //計(jì)算燃?xì)赓~單
    }

    所以,使用instanceof在絕大多數(shù)情況下并不是推薦的做法,應(yīng)當(dāng)好好利用多態(tài)。
    posted on 2007-12-17 16:13 xyz 閱讀(198) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): 網(wǎng)絡(luò)文摘

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    留言簿

    隨筆檔案(1)

    文章分類(lèi)(44)

    文章檔案(46)

    收藏夾(1)

    Adobe

    AOP

    API

    appServer

    BI

    c

    • c-free
    • codeblocks
    • codelite
    • CodeLite IDE 是一個(gè)強(qiáng)大的開(kāi)源,跨平臺(tái)的 C/C++整合開(kāi)發(fā)環(huán)境. 支持包括 Windows、Linux 和 Mac 系統(tǒng)下運(yùn)行
    • codelite官網(wǎng)
    • dev-c++
    • Dev-C++是一個(gè)C&C++開(kāi)發(fā)工具,它是一款自由軟件,遵守GPL協(xié)議。
    • GCC
    • GCC 原名為 GNU C 語(yǔ)言編譯器(GNU C Compiler),因?yàn)樗局荒芴幚?C語(yǔ)言。GCC 很快地?cái)U(kuò)展,變得可處理 C++。之后也變得可處理 Fortran、Pascal、Objective-C、Java, 以及 Ada 與其他語(yǔ)言。

    Cache

    CMS

    DB

    eclipse

    FreeMarker

    hibernate

    html5

    ibatis

    java

    jquery

    js

    json

    Linux

    Log

    mail server

    mobile

    mysql

    oauth

    openID

    other

    PHP

    portal

    report

    Scheduler

    schema

    Security

    SOA

    spring

    struts

    UI原型設(shè)計(jì)

    w3c

    Wap

    webservice

    xml

    供應(yīng)鏈管理

    博客鏈接

    好網(wǎng)站

    工作流

    開(kāi)源網(wǎng)

    招聘

    插件下載

    操作系統(tǒng)

    構(gòu)建可伸縮的系統(tǒng)

    構(gòu)建工具

    測(cè)試

    • IETest
    • IE官網(wǎng)
    • OpenSTA
    • Siege
    • Siege是一個(gè)壓力測(cè)試和評(píng)測(cè)工具,設(shè)計(jì)用于WEB開(kāi)發(fā)這評(píng)估應(yīng)用在壓力下的承受能力

    游戲

    源碼托管

    經(jīng)營(yíng)

    資源

    金融/財(cái)務(wù)

    搜索

    •  

    最新評(píng)論

    主站蜘蛛池模板: 国产精品亚洲片在线观看不卡| 久久亚洲精品成人| 亚洲综合精品一二三区在线| 亚洲日韩国产二区无码| 韩国免费a级作爱片无码| 100000免费啪啪18免进| 狠狠色婷婷狠狠狠亚洲综合| 亚洲性色高清完整版在线观看| 香港一级毛片免费看| 国产精品久久久久久久久免费| 亚洲国产V高清在线观看| 亚洲性一级理论片在线观看| 91av免费在线视频| 四虎永久在线精品免费网址| 亚洲人成人网站色www| 亚洲欧洲AV无码专区| 无码一区二区三区免费| 国产jizzjizz视频全部免费| 亚洲最大的视频网站| 好湿好大好紧好爽免费视频| 亚洲欧洲免费无码| 亚洲AV乱码一区二区三区林ゆな| 久久亚洲中文字幕无码| 18女人毛片水真多免费| 中文字幕一精品亚洲无线一区| 亚洲欧洲精品成人久久曰| 亚洲黄色片免费看| 亚洲中文字幕在线第六区| 亚洲国产精品精华液| 国产四虎免费精品视频| 国产亚洲综合网曝门系列| 黄色毛片免费在线观看| 在线免费视频一区| 亚洲午夜电影在线观看高清| 午夜视频免费在线观看| 国产成人精品亚洲精品| 色偷偷亚洲男人天堂| 成人性生交大片免费看无遮挡 | 成年人网站免费视频| 亚洲国产成人一区二区精品区| 日本永久免费a∨在线视频|