從Android到Java(二)

Java基礎(chǔ)知識填坑繼續(xù)。

Java 集合與泛型

數(shù)組 VS ArrayList

數(shù)組大概是我們學(xué)習(xí)任何語言時接觸到的第一個集合碑韵。

        String[] strs = new String[10];
        strs[0] = "a";
        strs[1] = "b";

        List<String> lists = new ArrayList<>();

數(shù)組也是對象;相較于普通的數(shù)組作瞄,ArrayList在創(chuàng)建時不必指定大小,會在進(jìn)行增刪操作時動態(tài)的調(diào)整自己的大小桐愉。

數(shù)組與List相互轉(zhuǎn)換
        //數(shù)組轉(zhuǎn)換為List
        lists = Arrays.asList(strs);
        //List 轉(zhuǎn) 數(shù)組
        strs =  lists.toArray(strs);

將集合中的對象進(jìn)行排序

使用Collections.sort()方法對集合中的對象進(jìn)行排序的兩種方式财破。

  • 該對象實(shí)現(xiàn)了Comparable接口,明確指定了排序方式从诲。
public class Student implements Comparable<Student>{
    private String name;
    private int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

    @Override
    public int compareTo(Student student) {
        //按照name(字符串值)從小到大排序
        return name.compareTo(student.name);
    }
}

這樣左痢,由Student對象構(gòu)成的集合就可以使用Collections.sort()方法進(jìn)行排序了。

        List<Student> students = new ArrayList<>();
        for(int i=0;i<10;i++) {
            Student student = new Student(i + "-name", i);
            students.add(student);
        }
        Collections.sort(students);
  • 實(shí)現(xiàn)Comparator接口系洛,動態(tài)定義排序方式俊性。
    private static class ComprareByName implements Comparator<Student> {
        @Override
        public int compare(Student student, Student t1) {
            //按name 從大到小進(jìn)行排序
            return t1.getName().compareTo(student.getName());
        }
    }

這樣就可以使用重載的sort方法進(jìn)行排序

        Collections.sort(students,new ComprareByName());

Comparator的compare實(shí)現(xiàn)方式會覆蓋集合元素中默認(rèn)的實(shí)現(xiàn),也就說雖然Student內(nèi)部是從小到大排序描扯,但會被這里ComprareByName的實(shí)現(xiàn)所覆蓋定页。

為了使集合有序,我們也可以使用TreeSet绽诚。

TreeSet 以有序的狀態(tài)存儲元素典徊,并防止重復(fù)杭煎。

因此,為了正確的使用TreeSet 需要注意以下兩點(diǎn):

  • 同上面第一點(diǎn)宫峦,加入到TreeSet集合中對象(元素)必須實(shí)現(xiàn)了Comparable接口岔帽。
  • 使用重載,用Comparator參數(shù)的構(gòu)造函數(shù)來創(chuàng)建TreeSet导绷。
        TreeSet<Student> mStudents = new TreeSet<>(new ComprareByName());

集合分類

  • Collections
    • List 索引位置明確的集合
    • Set 不允許重復(fù)元素的集合
  • Map 使用成對key和value的集合

以上三種集合的類圖如下:

Java 集合框架簡圖

從中可以看到我們常用的一些類犀勒,如ArrayList,HashMap 等妥曲。

如何檢查對象的重復(fù)性贾费?如何判定兩個對象相等?

        Student a = new Student("a", 1);
        Student b = new Student("b", 2);
        Student c = a;
        Student d = new Student("b", 2);

        System.err.println("a.hashCode()="+a.hashCode());
        System.err.println("b.hashCode()="+b.hashCode());
        System.err.println("c.hashCode()="+c.hashCode());
        System.err.println("d.hashCode()="+d.hashCode());

輸出

a.hashCode()=1118140819
b.hashCode()=1975012498
c.hashCode()=1118140819
d.hashCode()=1808253012


通過打印a,b,c,d 四個對象的hashcode 值檐盟,可以看到引用變量a和c 指向的是堆上的同一個對象褂萧,因此他們的hash值必然是相等的。引用對象b和d雖然創(chuàng)建的對象內(nèi)容是一致的葵萎,但他們?nèi)稳皇欠謩e指向兩個不同的對象导犹,因此hash值也是不同的。

下面我們用equals 方法比較一下這四個對象

        System.out.println("a.equals(b) " + a.equals(b));
        System.out.println("a.equals(c) " + a.equals(c));
        System.out.println("b.equals(d) " + b.equals(d));

輸出

a.equals(b) false
a.equals(c) true
b.equals(d) false

結(jié)果很明顯羡忘,因?yàn)镺bject的equals 默認(rèn)執(zhí)行的是對象引用是否相等的比較谎痢,因此b.equals(d)的結(jié)果為false。

    public boolean equals(Object obj) {
        return (this == obj);
    }

但是卷雕,從我們創(chuàng)建對象的代碼可以得知节猿,b和d 這兩個對象內(nèi)容是一樣的;因此漫雕,這兩個對象就應(yīng)該是同一個滨嘱,他們應(yīng)該是相等的;因此浸间,我們可以覆蓋默認(rèn)的hashCode()和equals()方法太雨。

public class Student implements Comparable<Student>{
    private String name;
    private int id;


    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        Student mStudent= (Student) o;
        return getName().equals(mStudent.getName());
    }

    public String getName() {
        return name;
    }
}

現(xiàn)在再次測試,就可以看到b.equals(d)的結(jié)果為true了魁蒜。

因此躺彬,我們可以得出以下結(jié)論:

  1. 如果兩個對象相等,則hashcode值必須相等
  2. 兩個對象的hashcode值相等梅惯,他們也不一定是相等的宪拥。(當(dāng)然,這種幾率應(yīng)該很邢臣酢)
  3. equals()默認(rèn)執(zhí)行的是== 比較她君,也就是說會去測試兩個引用是否對堆上同一個對象引用;因此葫哗,對于我們自己創(chuàng)建的對象缔刹,應(yīng)該同時覆蓋equals()方法和hashCode()方法球涛,規(guī)范檢測對象一致性的標(biāo)準(zhǔn)。

泛型

使用泛型可以構(gòu)建出類型更加安全的集合校镐,讓問題盡可能的在編譯期就被發(fā)現(xiàn)亿扁,而不是等到了執(zhí)行期才冒出來

public class ArrayList<E> extends AbstractList<E> implements List<E>

以常用的ArrayList為例,使用泛型后代表以后所有對ArrayList的操作鸟廓,添加从祝,刪除或返回的對象類型都是E,不能是其他類型引谜。

        List<Student> students = new ArrayList<>();
        for(int i=0;i<10;i++) {
            Student student = new Student(i + "-name", i);
            students.add(student);
        }

students 中添加的元素只能是Student類型的牍陌,不能是其他;同時從students結(jié)合中獲取到的對象也一定是Student類型员咽。

從泛型的角度看毒涧,extends和implements是等價的,都表示當(dāng)前類是一個……贝室。對ArrayList來說契讲,他既是一個AbstractList,也是List滑频。

當(dāng)泛型遇到多態(tài)

現(xiàn)在有Student的子類:SeniorStudent和CollegeStudent怀泊。

    private static void printStudents(List<Student> students) {
        for (Student mStudent : students) {
            System.out.println(mStudent.getName());
        }
        //面對這樣的情況,這個方法只能接受List<Student>類型的參數(shù)
        students.add(new SeniorStudent("hacker", 999));
    }

    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        //因?yàn)榉盒臀笈浚琇ist現(xiàn)在可以接受所有Student類型的對象
        students.add(new Student("mike",001));
        students.add(new CollegeStudent("lucy",002));
        students.add(new SeniorStudent("tom", 003));
        //
        printStudents(students);

        List<CollegeStudent> colleges = new ArrayList<>();
        colleges.add(new CollegeStudent("a", 100));
        colleges.add(new CollegeStudent("b", 101));
        colleges.add(new CollegeStudent("c", 102));
        //這樣做是不行的
        printStudents(colleges);

    }

在上面的代碼中,printStudents(List<Student> students)务傲,我們可以這樣

printStudents(ArrayList<Student>)

但卻不能這樣

printStudents(List<CollegeStudent>)

在泛型方法中凉当,參數(shù)中的集合可以是多態(tài),但集合中的對象不能是多態(tài)售葡。其中的道理我們通過printStudents 方法中最后一行語句很容易理解看杭。因?yàn)槟悴荒鼙WC使用集合的方法,會對集合做怎樣的操作挟伙。為了保證集合的安全性楼雹,這是很好的做法。

但是尖阔,這樣不就喪失了多態(tài)的意義嗎贮缅?如果不能用子類作為集合的類型,那難道要為每一個Student的子類型介却,單獨(dú)寫一個printStudents()方法嗎谴供? 其實(shí)不必,只要做如下改動即可:

    private static void printStudents(List<? extends Student> students) {
        for (Student mStudent : students) {
            System.out.println(mStudent.getName());
        }
        //當(dāng)使用通配符聲明后齿坷,將不能再向集合中添加元素桂肌,因此以下語句非法
        students.add(new SeniorStudent("hacker", 999));
    }

這種情況雖然從語法角度看似合理数焊,但編譯器會幫我們做限制,限制再次修改集合中的元素

這樣printStudents(List<CollegeStudent>)就變得合法了崎场。

當(dāng)然佩耳,為了更容易理解,也可以這樣聲明:

    private static <T extends Student> void printStudents(List<T> students) {
        for (Student mStudent : students) {
            System.out.println(mStudent.getName());
        }
        //當(dāng)使用通配符聲明后谭跨,將不能再向集合中添加元素干厚,因此以下語句非法
        students.add(new SeniorStudent("hacker", 999));
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饺蚊,隨后出現(xiàn)的幾起案子萍诱,更是在濱河造成了極大的恐慌,老刑警劉巖污呼,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裕坊,死亡現(xiàn)場離奇詭異,居然都是意外死亡燕酷,警方通過查閱死者的電腦和手機(jī)籍凝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苗缩,“玉大人饵蒂,你說我怎么就攤上這事〗囱龋” “怎么了退盯?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泻肯。 經(jīng)常有香客問我渊迁,道長,這世上最難降的妖魔是什么灶挟? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任琉朽,我火速辦了婚禮,結(jié)果婚禮上稚铣,老公的妹妹穿的比我還像新娘箱叁。我一直安慰自己,他們只是感情好惕医,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布耕漱。 她就那樣靜靜地躺著,像睡著了一般抬伺。 火紅的嫁衣襯著肌膚如雪孤个。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天沛简,我揣著相機(jī)與錄音齐鲤,去河邊找鬼斥废。 笑死,一個胖子當(dāng)著我的面吹牛给郊,可吹牛的內(nèi)容都是我干的牡肉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼淆九,長吁一口氣:“原來是場噩夢啊……” “哼统锤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炭庙,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤饲窿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后焕蹄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逾雄,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年腻脏,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸦泳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡永品,死狀恐怖做鹰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鼎姐,我是刑警寧澤钾麸,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站炕桨,受9級特大地震影響饭尝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谋作,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乎芳。 院中可真熱鬧遵蚜,春花似錦、人聲如沸奈惑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肴甸。三九已至寂殉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間原在,已是汗流浹背友扰。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工彤叉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人村怪。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓秽浇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親甚负。 傳聞我的和親對象是個殘疾皇子柬焕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法梭域,類相關(guān)的語法斑举,內(nèi)部類的語法,繼承相關(guān)的語法病涨,異常的語法富玷,線程的語...
    子非魚_t_閱讀 31,663評論 18 399
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,164評論 0 16
  • (一)Java部分 1没宾、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,114評論 0 62
  • 第十天 權(quán)限修飾符 public protected default private 同一類 true true ...
    炙冰閱讀 544評論 0 1
  • 帶寶寶到店里來凌彬,隔壁有個小丫頭,和寶寶差不多大循衰,年齡相仿铲敛,應(yīng)該可以一起愉快地玩耍。 小丫頭剛進(jìn)店門会钝,看見我閨女手里...
    李慧英_c3a3閱讀 527評論 5 6