Java基礎(chǔ)知識總結(jié)(上)

Java中的數(shù)據(jù)類型

Java的數(shù)據(jù)類型分為兩大類:基本類型和引用類型

  • 引用類型:引用類型指向一個對象鞠抑,不是原始值软能,指向?qū)ο蟮淖兞糠Q為引用變量。Java中除了基本類型绽淘,其他都是引用類型企量,如類(String類)测萎、接口、數(shù)組届巩、枚舉硅瞧、注解等。將引用存放棧中恕汇,實際存放值在堆內(nèi)存腕唧。

  • 基本數(shù)據(jù)類型(也稱值類型):整型(byte/short/int/long)、浮點型(float/double)瘾英、字符型(char占兩個字節(jié))與布爾型(boolean占一個字節(jié))枣接。直接在棧中存儲數(shù)值。編程語言內(nèi)置的最小粒度的數(shù)據(jù)類型缺谴,共有四大類八種基本數(shù)據(jù)類型但惶。具體如下表:

標識符和關(guān)鍵字的區(qū)別是什么?Java關(guān)鍵字湿蛔?

在我們編寫程序的時候膀曾,需要大量地為程序、類煌集、變量妓肢、方法等取名字,于是就有了標識符苫纤,簡單來說,標識符就是一個名字纲缓。但是有一些標識符卷拘,Java 語言已經(jīng)賦予了其特殊的含義,只能用于特定的地方祝高,這種特殊的標識符就是關(guān)鍵字栗弟。因此,關(guān)鍵字是被賦予特殊含義的標識符工闺。比如乍赫,在我們的日常生活中 瓣蛀,“警察局”這個名字已經(jīng)被賦予了特殊的含義,所以如果你開一家店雷厂,店的名字不能叫“警察局”惋增,“警察局”就是我們?nèi)粘I钪械年P(guān)鍵字。

Java中的關(guān)鍵字:

自動拆裝箱改鲫、發(fā)生與實現(xiàn)诈皿?

每個基本數(shù)據(jù)類型都對應(yīng)一個包裝類,除了 int 和 char 對應(yīng) Integer 和 Character 外像棘,其余基本數(shù)據(jù)類型的包裝類都是首字母大寫即可稽亏,比較兩個包裝類數(shù)值要用 equals ,而不能用 == 缕题。

  • 自動裝箱: 將基本數(shù)據(jù)類型包裝為一個包裝類對象截歉,例如向一個泛型為 Integer 的集合添加 int 元素。
    • 使用基礎(chǔ)型類給引用類型變量賦值烟零;
    • 具體實現(xiàn):調(diào)用引用類型對應(yīng)的靜態(tài)方法valueOf瘪松,本質(zhì)是在該方法內(nèi)部調(diào)用構(gòu)造函數(shù)創(chuàng)建對象。

自動裝箱的緩存機制:為了節(jié)省內(nèi)存和提升性能瓶摆,Java給多個包裝類提供了緩存機制凉逛,可以在自動裝箱過程中,把一部分對象放到緩存中(引用常量池)群井,實現(xiàn)了對象的復(fù)用状飞。如Byte、Short书斜、Integer诬辈、Long、Character等都支持緩存荐吉。

  • 自動拆箱: 將一個包裝類對象轉(zhuǎn)換為一個基本數(shù)據(jù)類型焙糟,例如將一個包裝類對象賦值給一個基本數(shù)據(jù)類型的變量。
    • 當基礎(chǔ)類型與引用類型進行 “==样屠、+穿撮、-、×痪欲、÷” 運算時悦穿,會對引用類型進行自動拆箱;
    • 具體實現(xiàn):引用類型對象內(nèi)部包含對應(yīng)基本類型的成員變量业踢,自動拆箱時返回該成員變量即可栗柒;

switch支持哪些類型?

  • jdk1.6之前只支持int知举、char瞬沦、byte太伊、short這樣的整型的基本類型或?qū)?yīng)的包裝類型Integer、Character逛钻、Byte僚焦、Short常量,包裝類型最終也會經(jīng)過拆箱為基本類型绣的,本質(zhì)上還是只支持基本類型叠赐;JDK1.5開始支持enum,原理是給枚舉值進行了內(nèi)部的編號屡江,進行編號和枚舉值的映射芭概。
  • JDK1.7開始支持String,但不允許為null惩嘉,原理是借助 hashcode( ) 來實現(xiàn)罢洲。

注意:null的hashCode()沒有,hashmap是人為寫到0槽的文黎!

== 與 equals 區(qū)別

"=="對比的是棧中的內(nèi)容:

  • 基本數(shù)據(jù)類型比較的是變量值惹苗;
  • 引用類型比較的堆中內(nèi)存對象的地址。

equals 本質(zhì)上就是 ==耸峭,只不過 String 和 Integer 等重寫了 equals 方法桩蓉,把它變成了值(內(nèi)容)比較。

注:對于"=="中引用類型劳闹,除非是同一個new出來的對象院究,他們的比較后的結(jié)果為true,否則比較后結(jié)果為false本涕。因為每new一次业汰,都會重新開辟堆內(nèi)存空間。

String中重寫equals方法舉例:

public boolean equals(Object anObject) {
    // 1. 如果比較的兩個對象的首地址是相同的菩颖,那指的肯定是同一個對象
    if (this == anObject) {
        return true;
    }
    // 2. 兩個對象的首地址不相同,比較內(nèi)容是否相同
    // instanceof:判斷傳入的實參是否為String類型,因為形參類型是固定的(重寫的要求),所以需要判斷
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        // 判斷傳入對象長度是否相同
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                //實質(zhì)比較字符的ascii值样漆,即兩個字符串內(nèi)容的比較!
                if (v1[i] != v2[i])   
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

重寫思路:

  • 判斷兩個對象的內(nèi)存首地址
  • 判斷傳入形參的類型是否為String類型
  • 判斷傳入對象的長度
  • 判斷字符的ascii碼晦闰,即比較內(nèi)容

應(yīng)用案例分析:

String str1 = "Hello";      // 分配到常量池
String str2 = new String("Hello");   // 在堆中分配內(nèi)存
String str3 = str2;   // 引用傳遞

System.out.println(str1 == str2); // false放祟,比較兩者棧中的內(nèi)存地址,顯然不同
System.out.println(str1 == str3); // false
System.out.println(str2 == str3); // true

System.out.println(str1.equals(str2)); // true呻右,string重寫了equals方法舞竿,實際上對比的兩個字符串的內(nèi)容
System.out.println(str1.equals(str3)); // true
System.out.println(str2.equals(str3)); // true

注意:字符串/包裝類對象值的比較必須使用equals(),即對比內(nèi)容窿冯。比如下邊的Integer緩存-128~127的整型值,如果超過這個范圍确徙,就會在堆上創(chuàng)建對象醒串,不會復(fù)用已有的對象执桌。

int和Integer的區(qū)別(包裝類與基本類型的區(qū)別)

  • Integer是int的包裝類,int則是java的一種基本數(shù)據(jù)類型
  • Integer變量必須實例化后才能使用芜赌,而int變量不需要
  • Integer實際是對象的引用仰挣,當new一個Integer時,實際上是生成一個指針指向此對象缠沈;而int則是直接存儲數(shù)據(jù)值 膘壶。
  • Integer的默認值是null,int的默認值是0

Integer a= 127與 Integer b = 127相等嗎洲愤?(常量池緩存技術(shù))

寫在前:Java 基本類型的包裝類的大部分都實現(xiàn)了常量池技術(shù)颓芭。

Byte,Short,Integer,Long 這 4 種整型的包裝類默認創(chuàng)建了數(shù)值 [-128,127] 的相應(yīng)類型的緩存數(shù)據(jù)柬赐,Character 創(chuàng)建了數(shù)值在[0,127]范圍的緩存數(shù)據(jù)亡问,Boolean 直接返回 True Or False。

注意:一個字節(jié)有8位肛宋。最大正數(shù)二進制是0111 1111 = 64+32+16+8+4+2+1=127州藕;最小負數(shù)二進制是1000 0000→ 反碼:1111 1111→ 補碼: -{(1+2+4+8+16+32+64)+1} =-(127+1)=-128,整形的緩存范圍都是[-128酝陈,127]床玻。

對于對象引用類型:==比較的是對象的內(nèi)存地址,對于基本數(shù)據(jù)類型:==比較的是值沉帮。

Integer內(nèi)部有一個IntegerCache的內(nèi)部類锈死。對整型值在-128到127之間的對象進行緩存。緩存會在Integer類第一次使用的時候被初始化出來遇西,那么自動裝箱時不會new新的Integer對象馅精,而是直接引用常量池中的Integer對象(直接從緩存中取出),超過范圍 a1==b1的結(jié)果是false粱檀。

注:若數(shù)值超過緩存范圍洲敢,則需要在堆中創(chuàng)建新的對象!

public static void main(String[] args) {
    Integer a = new Integer(1);
    Integer b = 1;  // 將1自動裝箱成Integer類型茄蚯,實際是調(diào)用靜態(tài)方法valueOf()
    int c = 1;

    System.out.println(a == b);  // false,引用了不同對象
    System.out.println(a == c);  // true压彭,a自動拆箱與c比較
    System.out.println(b == c);  // true

    Integer a1 = 128;
    Integer b1 = 128;
    System.out.println(a1 == b1);  // false, 自動裝箱,new新的Integer對象

    Integer a2 = 127;
    Integer b2 = 127;
    System.out.println(a2 == b2);  // true渗常,字面值介于-128與127, 自動裝箱不會new新的Integer對象壮不,直接引用常量池中的對象
}

java有了基本類型,為什么還要設(shè)計對應(yīng)的引用類型皱碘?

  • 可以使用為該引用類型而編寫的方法
  • Java集合(map询一、set、list)等所有集合只能存放引用類型數(shù)據(jù),不能存放基本類型數(shù)據(jù)(容器中實際存放的是對象的引用)健蕊。
  • 引用類型對象存儲在堆上菱阵,可以控制其生命周期;而基本類型存儲在棧上缩功,會隨著代碼塊運行結(jié)束被回收
  • Java泛型使用類型擦除法實現(xiàn)晴及,基本類型無法實現(xiàn)泛型。

為什么會設(shè)置包裝類型嫡锌?

  • Java是一門面向?qū)ο蟮木幊陶Z言虑稼,但是Java中的基本數(shù)據(jù)類型卻不是面向?qū)ο蟮模⒉痪哂袑ο蟮男再|(zhì)势木,這在實際生活中存在很多的不便蛛倦。為了讓基本類型也具有對象的特征,就出現(xiàn)了包裝類型跟压,使得Java具有了對象的性質(zhì)胰蝠,并且為其添加了屬性和方法,豐富了基本類型的操作震蒋,方便涉及到對象的操作茸塞。
  • 比如,我們在使用集合類型時查剖,就一定要使用包裝類型钾虐,因為容器都是裝object的,基本數(shù)據(jù)類型顯然不適用笋庄。
  • 邏輯上來講效扫,java只有包裝類就夠了,為了運行速度直砂,需要用到基本數(shù)據(jù)類型菌仁。實際上,任何一門語言設(shè)計之初静暂,都會優(yōu)先考慮運行效率的問題济丘,所以二者同時存在是合乎情理的。

java泛型相關(guān)問題

在 jdk 1.5 之前沒有泛型的情況的下只能通過對類型 Object 的引用來實現(xiàn)參數(shù)的任意化洽蛀,其帶來的缺點是要做顯式強制類型轉(zhuǎn)換摹迷,而這種強制轉(zhuǎn)換編譯期是不做檢查的,容易把問題留到運行時郊供,會出現(xiàn)“java.lang.ClassCastException”異常峡碉。因此,導(dǎo)致此類錯誤編碼過程中不易發(fā)現(xiàn)驮审。

import java.util.ArrayList;
import java.util.List;

public class Test001 {

    public static void main(String[] args) {

        List list = new ArrayList();
        list.add("java");
        list.add("非泛型");
        list.add(100);

        // 泛型使用(jdk1.7實例化類型可以自動推斷)
        List<String> list1 = new ArrayList<>();
        list1.add("java");
        list1.add("泛型");
        // 想加入一個Integer類型的對象時會出現(xiàn)編譯錯誤
        //list1.add(100);

        for (int i = 0; i < list1.size(); i++) {
            String name1 = list1.get(i);
            System.out.println("name1:" + name1);
        }

        System.out.println();

        for (int i = 0; i < list.size(); i++) {
            // Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
//            String name = (String) list.get(i);
//            System.out.println("name:" + name);
        }

        // 泛型擦除(泛型只存在編譯階段鲫寄,成功編譯過后的class文件中是不包含任何泛型信息的)
        List<String> name = new ArrayList<String>();
        name.add("java");
        List<Integer> age = new ArrayList<Integer>(712);

        System.out.println("name class:" + name.getClass());
        System.out.println("age class:" + age.getClass());
        System.out.println(name.getClass() == age.getClass());

        List<Object> objectList = new ArrayList<>();
        List<String> stringList = new ArrayList<>();

        // compilation error incompatible types
        // objectList = stringList;
    }
}

在如上的編碼過程中吉执,我們發(fā)現(xiàn)主要存在兩個問題:

  • 當我們將一個對象放入集合中,集合不會記住此對象的類型塔拳,當再次從集合中取出此對象時鼠证,該對象的編譯類型變成了Object類型,但其運行時類型任然為其本身類型靠抑。
  • 因此,取出集合元素時需要人為的強制類型轉(zhuǎn)化到具體的目標類型适掰,且很容易出現(xiàn)“java.lang.ClassCastException”異常颂碧。

泛型是jdk1.5的新特性,泛型提供了編譯時類型安全檢測機制类浪,該機制允許程序員在編譯時檢測到非法的類型沃缘。泛型的本質(zhì)是參數(shù)化類型嫌蚤,也就是說所操的數(shù)據(jù)類型被指定為一個參數(shù)。這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中林螃,分別稱為泛型類、泛型接口典蝌、泛型方法雀哨。 Java語言引入泛型的好處是安全簡單。

好處

  • 類型安全眠蚂,編譯期檢查煞聪,不存在 ClassCastException。
  • 提升可讀性逝慧,編碼階段就顯式知道泛型集合昔脯、泛型方法等處理的對象類型。
  • 代碼重用笛臣,合并了同類型的處理代碼云稚。

泛型擦除是什么?介紹下常用的通配符

原理:泛型只存在于編譯階段沈堡,不存在與運行階段(編譯后的class文件不存在泛型的概念)静陈。例如定義 List<Object> 或 List<String>,在編譯后都會變成 List 踱蛀。

Java中List和原始類型List之間的區(qū)別?

  • 原始類型和帶參數(shù)類型< Object >之間的主要區(qū)別:在編譯時編譯器不會對原始類型進行類型安全檢查窿给,卻會對帶參數(shù)的類型進行檢查,通過使用Object作為類型率拒,可以告知編譯器該方法可以接受任何類型的對象崩泡,比如String或Integer。
  • 你可以把任何帶參數(shù)的類型傳遞原始類型List猬膨,但卻不能把List< String >傳遞給接受List< Object >方法角撞,因為會產(chǎn)生編譯錯誤呛伴。

定義一個泛型類型,會自動提供一個對應(yīng)原始類型谒所,類型變量會被擦除热康。如果沒有限定類型就會替換為 Object,如果有限定類型就會替換為第一個限定類型劣领,例如 <T extends A & B> 會使用 A 類型替換 T姐军。

常用的通配符為: T,E尖淘,K奕锌,V,村生?

(1)惊暴? 表示不確定的 java 類型
(2)T (type) 表示具體的一個 java 類型
(3)K V (key value) 分別代表 java 鍵值中的 Key Value
(4)E (element) 代表 Element

什么是泛型中的限定通配符和非限定通配符 ? List<? extends T>和List <? super T>之間有什么區(qū)別 ?

  • 限定通配符對類型進行了限制。有兩種限定通配符趁桃,一種是<? extends T>它通過確保類型必須是T的子類來設(shè)定類型的上界辽话,另一種是<? super T>它通過確保類型必須是T的父類來設(shè)定類型的下界。泛型類型必須用限定內(nèi)的類型來進行初始化卫病,否則會導(dǎo)致編譯錯誤油啤。
  • 另一方面<?>表示了非限定通配符,因為<?>可以用任意類型來替代忽肛。

總結(jié):extend用于設(shè)定類型的上界(必須是T的子類)村砂,super用于設(shè)定類型的下界(必須是T的父類)

編寫泛型方法并不困難,你需要用泛型類型來替代原始類型屹逛,比如使用T, E or K,V等被廣泛認可的類型占位符础废。泛型方法的例子請參閱Java集合類框架。

public V put(K key, V value) {
    return cache.put(key, value);
}

Array事實上并不支持泛型罕模,這也是為什么Joshua Bloch在Effective Java一書中建議使用List來代替Array评腺,因為List可以提供編譯期的類型安全保證,而Array卻不能淑掌。

淺談String str = "" 和 new String()的區(qū)別

兩者看似都是創(chuàng)建了一個字符串對象蒿讥,但在內(nèi)存中確是各有各的想法。

  • String str1= “abc”抛腕; 在編譯期芋绸,JVM會去常量池來查找是否存在“abc”,如果不存在担敌,就在常量池中開辟一個空間來存儲“abc”摔敛;如果存在,就不用新開辟空間全封。然后在棧內(nèi)存中開辟一個名字為str1的空間马昙,來存儲“abc”在常量池中的地址值桃犬。
  • String str2 = new String("abc") ; 在編譯階段JVM先去常量池中查找是否存在“abc”,如果不存在行楞,則在常量池中開辟一個空間存儲“abc”攒暇。在運行時期,通過String類的構(gòu)造器(intern()方法)在堆內(nèi)存中new了一個空間子房,然后將String池中的“abc”復(fù)制一份存放到該堆空間中形用,在棧中開辟名字為str2的空間,存放堆中new出來的這個String對象的地址值池颈。

也就是說尾序,前者在初始化的時候可能創(chuàng)建了一個對象,也可能一個對象也沒有創(chuàng)建躯砰;后者因為new關(guān)鍵字,至少在內(nèi)存中創(chuàng)建了一個對象携丁,也有可能是兩個對象琢歇。

什么是字符串常量池(String Pool)?

  • 字符串常量池位于堆內(nèi)存中(java8之前在方法區(qū)梦鉴,java8之后被放到堆內(nèi)存)李茫,專門用來存儲字符串常量,可以提高內(nèi)存的使用率肥橙,避免開辟多塊空間存儲相同的字符串魄宏;
  • 在創(chuàng)建字符串時(new String()),JVM 會首先檢查字符串常量池存筏,如果該字符串已經(jīng)存在池中宠互,則返回它的引用,如果不存在椭坚,則實例化一個字符串通過 String 的 intern() 方法放到池中予跌,并返回其引用

ps:池化(如Java線程池善茎、連接池與內(nèi)存池等)的優(yōu)點:

  • 降低資源消耗:通過池化技術(shù)重復(fù)利用已經(jīng)創(chuàng)建的資源券册,提高內(nèi)存的使用率
  • 提高響應(yīng)速度:如果字符串已經(jīng)存在直接返回它的引用,如果沒有池化的字符串則是通過String的intern()方法放入池中垂涯,然后再返回它的引用烁焙。
  • 便于資源的管理。

String a = "a" + new String("b")創(chuàng)建了幾個對象耕赘?

  • 常量和常量拼接仍是常量骄蝇,結(jié)果在常量池,只要有變量參與拼接結(jié)果就是變量鞠苟,存在堆乞榨。
  • 使用字面量時只創(chuàng)建一個常量池中的常量秽之。
  • 使用 new 時如果常量池中,如果有吃既,直接讓引用指向常量池的對象考榨;沒有該值就會在常量池中新創(chuàng)建,再在堆中創(chuàng)建一個對象鹦倚,引用常量池中常量河质。
  • 因此 String a = "a" + new String("b") 會創(chuàng)建三個或者四個對象,常量池中的 a 和 b震叙,堆中的 b(常量池中存在掀鹅,則無需創(chuàng)建) 和堆中的 ab。

字符串拼接有哪幾種方式媒楼?

  • 直接用 + 乐尊,底層用 StringBuilder 實現(xiàn)。只適用小數(shù)量划址。如果頻繁(或者在循環(huán)體中)的使用 + 拼接扔嵌,相當于不斷創(chuàng)建新的 StringBuilder 對象(sppend進行拼接)再轉(zhuǎn)換成 String 對象(toString進行拼接),效率極差夺颤,內(nèi)存消耗大痢缎。
  • 使用 String 的 concat 方法,該方法中使用 Arrays.copyOf 創(chuàng)建一個新的字符數(shù)組 buf 并將當前字符串 value 數(shù)組的值拷貝到 buf 中世澜,buf 長度 = 當前字符串長度 + 拼接字符串長度独旷。之后調(diào)用 getChars 方法使用 System.arraycopy 將拼接字符串的值也拷貝到 buf 數(shù)組,最后用 buf 作為構(gòu)造參數(shù) new 一個新的 String 對象返回寥裂。效率稍高于直接使用 +嵌洼。
public String concat(String str) {
   int otherLen = str.length();
   if (otherLen == 0) {
       return this;
   }
   int len = value.length;
   char buf[] = Arrays.copyOf(value, len + otherLen);
   str.getChars(buf, len);
   return new String(buf, true);
}
  • 使用 StringBuilder 或 StringBuffer,兩者的 append 方法都繼承自 AbstractStringBuilder抚恒,該方法首先使用 Arrays.copyOf 確定新的字符數(shù)組容量咱台,再調(diào)用 getChars 方法使用 System.arraycopy 將新的值追加到數(shù)組中。StringBuilder 是 JDK5 引入的俭驮,效率高但線程不安全回溺。StringBuffer 使用 synchronized 保證線程安全。
public synchronized StringBuffer append(String str) {
   toStringCache = null;
   super.append(str);
   return this;
}
  • StringUtils中提供的join方法混萝,最主要的功能是:將數(shù)組或集合以某拼接符拼接到一起形成新的字符串遗遵,并且,Java8中的String類中也提供了一個靜態(tài)的join方法逸嘀,用法和StringUtils.join類似车要。底層也是通過StringBuilder進行拼接。

String 常用的方法崭倘?

  • 判斷功能
    boolean equals(Object obj):比較字符串的內(nèi)容是否相同,區(qū)分大小寫a A
    boolean equalsIgnoreCase(String str):比較字符串的內(nèi)容是否相同,忽略大小寫 a A
    boolean contains(String str):判斷大字符串中是否包含小字符串
    boolean startsWith(String str):判斷字符串是否以某個指定的字符串開頭
    boolean endsWith(String str):判斷字符串是否以某個指定的字符串結(jié)尾
    boolean isEmpty():判斷字符串是否為空翼岁。

  • 獲取功能
    int length():獲取字符串的長度类垫。
    char charAt(int index):獲取指定索引位置的字符
    int indexOf(String str):返回指定字符串在此字符串中第一次出現(xiàn)處的索引。
    int indexOf(int ch,int fromIndex):返回指定字符在此字符串中從指定位置后第一次出現(xiàn)處的索引琅坡。
    int indexOf(String str,int fromIndex):返回指定字符串在此字符串中從指定位置后第一次出現(xiàn)處的索引悉患。
    String substring(int start):從指定位置開始截取字符串,默認到末尾。
    String substring(int start,int end):從指定位置開始到指定位置結(jié)束截取字符串榆俺。

  • 轉(zhuǎn)換功能
    byte[] getBytes():把字符串轉(zhuǎn)換為字節(jié)數(shù)組售躁。
    char[] toCharArray():把字符串轉(zhuǎn)換為字符數(shù)組。
    static String valueOf(char[] chs):把字符數(shù)組轉(zhuǎn)成字符串茴晋。
    static String valueOf(int i):把int類型的數(shù)據(jù)轉(zhuǎn)成字符串陪捷。注意:String類的valueOf方法可以把任意類型的數(shù)據(jù)轉(zhuǎn)成字符串。
    String toLowerCase():把字符串轉(zhuǎn)成小寫诺擅。
    String toUpperCase():把字符串轉(zhuǎn)成大寫市袖。
    String concat(String str):把字符串拼接。

  • 其他方法
    String rerplace(char old,char new);返回一個新的字符串烁涌,它是通過用 newChar 替換此字符串中出現(xiàn)的所有 oldChar 得到的凌盯。
    String replace(String old,String new);返回一個新的字符串,它是通過用 newChar 替換此字符串中出現(xiàn)的所有 oldChar 得到的烹玉。
    String trim(); 去掉字符串兩端的空格

字符串的" "與null的區(qū)別:

  • " "是字符串常量.同時也是一個String類的對象,既然是對象當然可以調(diào)用String類中的方法;
  • Null是空常量,不能調(diào)用任何的方法,否則會出現(xiàn)空指針異常,null常量可以給任意的引用數(shù)據(jù)類型賦值

ps:String創(chuàng)建字符串的方式:直接賦值(在常量池中,只開辟了一塊內(nèi)存阐滩,并且會自動入池二打,不會產(chǎn)生垃圾)和實例化方式(通過構(gòu)造函數(shù)創(chuàng)建的字符串對象在堆中,會開辟兩塊堆內(nèi)存空間掂榔,其中一塊堆內(nèi)存會變成垃圾被系統(tǒng)回收继效,而且不能夠自動入池,需要通過public String intern();方法進行手工入池装获,通常在開發(fā)的過程中不會采用構(gòu)造方法進行字符串的實例化瑞信。)

String是否可變?

String類就是final修飾(字符數(shù)組final修飾)穴豫!Jdk8中String類有兩個成員變量:

    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

也就是說在String類內(nèi)部凡简,一旦初始化就不能被改變。所以可以認為String對象是不可變的精肃。

ps:在 Java 9 之后秤涩,String 、StringBuilder 與 StringBuffer 的實現(xiàn)改用 byte 數(shù)組存儲字符串 private final byte[] value司抱。

String為什么要設(shè)計為不可變筐眷?(String的優(yōu)點)

  • 效率(字符串常量池),字符串常量池的需要习柠,只有字符串不可變時匀谣,字符串常量池才能實現(xiàn)照棋。
  • 安全(多線程、hash值唯一武翎、類加載烈炭,參數(shù)安全)。
    • 多線程安全后频,對象是只讀的梳庆,不會出現(xiàn)線程安全問題。
    • 因為 String 的 hash 值經(jīng)常被使用卑惜,例如 String 用做 HashMap 的 key膏执。不可變的特性可以使得 hash 值也不可變,因此只需要進行一次計算露久。
    • 類加載器要用到字符串更米,不可變提供了安全性,以便類被正確地加載毫痕。
    • String被許多的Java類(庫)用來當做參數(shù)征峦,例如網(wǎng)絡(luò)連接地址URL,文件路徑path消请,還有反射機制所需要的String參數(shù)等栏笆, 假若String不是固定不變的,將會引起各種安全隱患臊泰。

String 是不可變類為什么值可以修改蛉加?

  • String 類和其存儲數(shù)據(jù)的成員變量 value 字符數(shù)組都是 final 修飾的。對一個 String 對象的任何修改實際上都是創(chuàng)建一個新 String 對象缸逃,再引用該對象(只是修改變量引用的對象)针饥。只是修改 String 變量引用的對象,沒有修改原 String 對象的內(nèi)容需频。
  • 用反射丁眼,可以反射出String對象中的value屬性, 進而通過獲得的value引用改變數(shù)組的結(jié)構(gòu)昭殉。可以通過類對象的getDeclaredField()方法字段(Field)對象苞七,然后再通過字段對象的setAccessible(true)將其設(shè)置為可以訪問,接下來就可以通過get/set方法來獲取/設(shè)置字段的值了饲化。

Java里實現(xiàn)不可變類的四大要素:

  • 盡量使用final修飾所有的屬性(field)
  • 盡量使用private修飾屬性莽鸭。
  • 禁止提供可改變實例狀態(tài)的公開接口
  • 禁止不可變類被“外部”繼承
    • 使用final關(guān)鍵字修飾類
    • 構(gòu)造器私有化 & 提供靜態(tài)構(gòu)造方法

String、StringBuffer與StringBuilder的區(qū)別和應(yīng)用場景

是否產(chǎn)生新對象:

  • String是final修飾的吃靠,不可變硫眨,每次操作都會產(chǎn)生新的String對象(一定程度上導(dǎo)致了內(nèi)存浪費)。
  • StringBuffer和StringBuilder都是在原對象上進行操作(不會產(chǎn)生新對象)。

頻繁的對String對象進行修改礁阁,會造成很大的內(nèi)存開銷:

// str指向了一個String對象(內(nèi)容為“hello”)
String str = “hello";

// 對str進行“+”操作巧号,str原來指向的對象并沒有變,而是str又指向了另外一個對象(“hello world”)姥闭,原來的對象還在內(nèi)存中丹鸿。
str = str + "world“;

注意:String類是final修飾棚品,不能被繼承和重寫靠欢,實現(xiàn)了equals()和hashCode()方法。

三者區(qū)別(線程安全性與性能):

  • 線程安全性:StringBuffer是線程安全的(內(nèi)部方法都用synchronized關(guān)鍵字修飾)铜跑,StringBuilder是線程不安全的门怪;String不可變性保證線程安全(可理解為常量)。
  • 性能(效率):StringBuilder>StringBuffer>String锅纺;ps:相同情況下使用 StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升掷空。

注:這里談到一個對象是否線程安全,是不是需要額外進行加鎖囤锉,保證滿足三個條件:多線程環(huán)境下坦弟、變量為共享變量和結(jié)果不受影響。

應(yīng)用場景:操作少量數(shù)據(jù)使用String官地;StringBuffer和StringBuilder經(jīng)常需要改變字符串內(nèi)容時使用:單線程操作字符串緩沖區(qū)下?量數(shù)據(jù)使用StringBuilder酿傍;多線程(共享變量)操作字符串緩沖區(qū)下?量數(shù)據(jù)為了保證結(jié)果的正確性使用StringBuffer。

構(gòu)造方法:作用驱入、特性

  • 主要作?是完成對類對象的初始化?作拧粪。注意:在調(diào)??類構(gòu)造?法之前會先調(diào)??類沒有參數(shù)的構(gòu)造?法,目的是幫助子類初始化沧侥。

構(gòu)造方法特性(特別注意):

  • 名字與類名相同,沒有返回值魄鸦,但不能? void 聲明構(gòu)造函數(shù)宴杀。
  • ?成類的對象時?動執(zhí)?,?需調(diào)?拾因。
  • ?個類即使沒有聲明構(gòu)造?法也會有默認的不帶參數(shù)的構(gòu)造?法旺罢。
  • 構(gòu)造方法不能被繼承,構(gòu)造方法只能被顯式或者隱式地調(diào)用绢记。
  • 子類的構(gòu)造方法總是先調(diào)用父類的構(gòu)造方法扁达,如果子類的構(gòu)造方法沒有顯式地指出使用父類的哪個構(gòu)造方法,子類則默認調(diào)用父類的無參構(gòu)造方法(此時若父類自定義了構(gòu)造方法蠢熄,而子類又沒有用super則會報錯)跪解。

ps:Java不支持像C++中那樣的復(fù)制構(gòu)造方法(沒有這個概念),但是在Object類中有一個clone()方法签孔。

關(guān)于 static 關(guān)鍵字的?些總結(jié)

static關(guān)鍵字常見的用法是修飾變量和方法叉讥,其次可以修飾代碼塊窘行,比較少的應(yīng)用是修飾類(匿名內(nèi)部類)。

static關(guān)鍵字最基本的用法是修飾變量與方法

  • 被static修飾的變量屬于類變量图仓,可以通過類名.變量名直接引用罐盔,而不需要new出一個類來
  • 被static修飾的方法屬于類方法,可以通過類名.方法名直接引用救崔,而不需要new出一個類來

被static修飾的變量惶看、被static修飾的方法統(tǒng)一屬于類的靜態(tài)資源,是類實例之間共享的六孵,換言之纬黎,一處變、處處變狸臣。JDK把不同的靜態(tài)資源放在了不同的類中而不把所有靜態(tài)資源放在一個類里面莹桅,很多人可能想當然認為當然要這么做,但是是否想過為什么要這么做呢烛亦?個人認為主要有三個好處:

  • 不同的類有自己的靜態(tài)資源诈泼,這可以實現(xiàn)靜態(tài)資源分類。比如和數(shù)學(xué)相關(guān)的靜態(tài)資源放在java.lang.Math中煤禽,和日歷相關(guān)的靜態(tài)資源放在java.util.Calendar中铐达,這樣就很清晰了
  • 避免重名。不同的類之間有重名的靜態(tài)變量名檬果、靜態(tài)方法名也是很正常的瓮孙,如果所有的都放在一起不可避免的一個問題就是名字重復(fù),這時候怎么辦选脊?分類放置就好了杭抠。
  • 避免靜態(tài)資源類無限膨脹,這很好理解恳啥。

靜態(tài)資源屬于類偏灿,但是是獨立于類存在的。從JVM的類加載機制的角度講钝的,靜態(tài)資源是類初始化的時候加載的翁垂,而非靜態(tài)資源是類new的時候加載的。類的初始化早于類的new硝桩,比如Class.forName(“xxx”)方法沿猜,就是初始化了一個類,但是并沒有new它碗脊,只是加載這個類的靜態(tài)資源罷了啼肩。所以對于靜態(tài)資源來說,它是不可能知道一個類中有哪些非靜態(tài)資源的;但是對于非靜態(tài)資源來說就不一樣了疟游,由于它是new出來之后產(chǎn)生的呼畸,因此屬于類的這些東西它都能認識。故:

  • 靜態(tài)方法能不能引用非靜態(tài)資源颁虐?不能蛮原,new的時候才會產(chǎn)生的東西,對于初始化后就存在的靜態(tài)資源來說另绩,根本不認識它儒陨。
  • 靜態(tài)方法里面能不能引用靜態(tài)資源?可以笋籽,因為都是類初始化的時候加載的蹦漠,大家相互都認識。
  • 非靜態(tài)方法里面能不能引用靜態(tài)資源车海?可以笛园,非靜態(tài)方法就是實例方法,那是new之后才產(chǎn)生的侍芝,那么屬于類的內(nèi)容它都認識研铆。

靜態(tài)代碼塊也是static的重要應(yīng)用之一。也是用于初始化一個類的時候做操作用的州叠,和靜態(tài)變量棵红、靜態(tài)方法一樣,靜態(tài)塊里面的代碼只執(zhí)行一次咧栗,且只在初始化類的時候執(zhí)行逆甜。靜態(tài)塊很簡單,不過提三個小細節(jié):

  • 靜態(tài)資源的加載順序是嚴格按照靜態(tài)資源的定義順序來加載的
  • 靜態(tài)代碼塊對于定義在它之后的靜態(tài)變量致板,可以賦值交煞,但是不能訪問(如print()操作)。
  • 靜態(tài)代碼塊是嚴格按照父類靜態(tài)代碼塊->子類靜態(tài)代碼塊的順序加載的斟或,且只加載一次错敢。

static修飾類:這個用得相對比前面的用法少多了,static一般情況下來說是不可以修飾類的缕粹,如果static要修飾一個類,說明這個類是一個靜態(tài)內(nèi)部類(注意static只能修飾一個內(nèi)部類)纸淮,也就是匿名內(nèi)部類平斩。像線程池ThreadPoolExecutor中的四種拒絕機制CallerRunsPolicy、AbortPolicy咽块、DiscardPolicy绘面、DiscardOldestPolicy就是靜態(tài)內(nèi)部類。

靜態(tài)方法 與 實例方法

早期的結(jié)構(gòu)化編程,幾乎所有的方法都是“靜態(tài)方法”揭璃,引入實例化方法概念是面向?qū)ο蟾拍畛霈F(xiàn)以后的事情了晚凿,區(qū)分靜態(tài)方法和實例化方法不能單單從性能上去理解(兩者在性能上,如加載時機瘦馍,和內(nèi)存占用都一樣歼秽,調(diào)用速度也沒有太大區(qū)別),創(chuàng)建c++,java,c#這樣面向?qū)ο笳Z言的大師引入實例化方法一定不是要解決什么性能情组、內(nèi)存的問題燥筷,而是為了讓開發(fā)更加模式化、面向?qū)ο蠡?/strong>院崇。這樣說的話肆氓,靜態(tài)方法和實例化方式的區(qū)分是為了解決模式的問題。

靜態(tài)方法和實例方法的區(qū)別主要體現(xiàn)在兩個方面:

外部調(diào)用 訪問特點
靜態(tài)方法 類名.方法名/對象名.方法名 只允許訪問靜態(tài)成員(即靜態(tài)成員變量和靜態(tài)方法)
實例方法 對象名.方法名 訪問無限制

靜態(tài)方法只能訪問靜態(tài)成員底瓣,實例方法可以訪問靜態(tài)和實例成員谢揪!

之所以不允許靜態(tài)方法訪問實例成員變量,是因為實例成員變量是屬于某個對象的捐凭,而靜態(tài)方法在執(zhí)行時拨扶,并不一定存在對象。同樣柑营,因為實例方法可以訪問實例成員變量屈雄,如果允許靜態(tài)方法調(diào)用實例方法,將間接地允許它使用實例成員變量官套,所以它也不能調(diào)用實例方法酒奶。基于同樣的道理奶赔,靜態(tài)方法中也不能使用關(guān)鍵字this惋嚎。

關(guān)于 final 關(guān)鍵字的?些總結(jié)

final 關(guān)鍵字主要應(yīng)用位置:常量、變量站刑、方法和類(除抽象類)

  • 被final修飾的常量:在編譯階段會存入調(diào)用類的常量池中另伍,具體參見類加載機制最后部分和Java內(nèi)存區(qū)域

  • 被final修飾的變量不能被改變: 對于?個 final 變量,如果是基本數(shù)據(jù)類型的變量绞旅,則其數(shù)值?旦在初始化之后便不能更改摆尝;如果是引?類型的變量,則在對其初始化之后便不能再讓其指向另?個對象因悲。切記不可變的是變量的引用堕汞!,但內(nèi)容可以進行改變晃琳。

  • 被final 修飾的類不能被繼承讯检。final 類中的所有成員?法都會被隱式地指定為 final ?法琐鲁。

  • 被final修飾的方法不能被重寫:目的是把?法鎖定,以防任何繼承類修改它的含義人灼。

final關(guān)鍵字的好處:

  • final方法比非final快一些
  • final關(guān)鍵字提高了性能围段。JVM和Java應(yīng)用都會緩存final變量。
  • final變量可以安全的在多線程環(huán)境下進行共享投放,而不需要額外的同步開銷奈泪。
  • 使用final關(guān)鍵字,JVM會對方法跪呈、變量及類進行優(yōu)化段磨。

ps:final不能修飾抽象類和接口!!!

final finally finalize區(qū)別

  • final可以修飾類、變量耗绿、方法苹支,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫误阻、修飾變量表示該變量是一個常量不能被重新賦值(引用類型變量初始化后不能在指向另一個對象)债蜜。

  • finally一般作用在try-catch代碼塊中,在處理異常的時候究反,通常我們將一定要執(zhí)行的代碼方法finally代碼塊中寻定,表示不管是否出現(xiàn)異常,該代碼塊都會執(zhí)行精耐,一般用來存放一些關(guān)閉資源的代碼狼速。

  • finalize是一個方法,屬于Object類的一個方法卦停,而Object類是所有類的父類向胡,該方法一般由垃圾回收器來調(diào)用,當我們調(diào)用System.gc() 方法的時候惊完,由垃圾回收器調(diào)用finalize()僵芹,回收垃圾,一個對象是否可回收的最后判斷小槐。

try-catch-finally相關(guān)

  • try塊: 用于捕獲異常拇派。其后可接零個或多個 catch 塊,如果沒有 catch 塊凿跳,則必須跟一個 finally 塊当窗。
  • catch塊: 用于處理 try 捕獲到的異常垢箕。
  • finally 塊: 無論是否捕獲或處理異常悍募,finally 塊里的語句都會被執(zhí)行矢渊。當在 try 塊或 catch 塊中遇到 return 語句時,finally 語句塊將在方法返回之前被執(zhí)行躬审。

異常處理中return的執(zhí)行順序:

(1)執(zhí)行try的語句塊
(2)轉(zhuǎn)至catch塊,再執(zhí)行finally塊,try塊的return永遠不會執(zhí)行.
(3)若finally塊中有return棘街,則返回值;
(4)若finally塊中沒有return承边,則返回catch塊的return值 (此時catch塊中的return值是暫存的)

finally語句塊什么情況不會執(zhí)行

  • finally語句塊第一行出現(xiàn)異常
  • 程序拋出異常(或者return)之前遭殉,調(diào)用system.exits(int),退出程序
  • 程序拋出異常(或者return)之前博助,線程死亡
  • 程序拋出異常(或者return)之前险污,關(guān)閉CPU

注意: 當 try 語句和 finally 語句中都有 return 語句時,在方法返回之前富岳,finally 語句的內(nèi)容將被執(zhí)行蛔糯,并且 finally 語句的返回值將會覆蓋原始的返回值!=咽健蚁飒!

public class Test {
    public static int f(int value) {
        try {
            return value * value;
        } finally {
            if (value == 2) {
                return 0;
            }
        }
    }
}

如果調(diào)用 f(2),返回值將是 0萝喘,因為 finally 語句的返回值覆蓋了 try 語句塊的返回值淮逻。

Java異常常見問題

異常是什么:java.lang.Throwable派生出ErrorException阁簸。Exception又分為運行時異常非運行時異常爬早。

  • error:程序(JVM)無法處理的嚴重錯誤 ,不能通過 catch 來進行捕獲(智能盡量避免)启妹,通常會導(dǎo)致程序終止筛严。例如系統(tǒng)崩潰、內(nèi)存不足饶米、虛擬機運行錯誤桨啃、類定義錯誤等;
  • exception:程序可以處理的異常咙崎,需要對其進行處理 ;

Exception分類

  • 運行時異常(非受檢異常):繼承自 RuntimeException优幸,即使不做處理也可以通過編譯。RuntimeException及其子類都統(tǒng)稱為非受檢查異常褪猛,例如:NullPointExecrption网杆、NumberFormatException(字符串轉(zhuǎn)換為數(shù)字)、ArrayIndexOutOfBoundsException(數(shù)組越界)伊滋、ClassCastException(類型轉(zhuǎn)換錯誤)碳却、ArithmeticException(算術(shù)錯誤)等⌒ν可以由程序員自己決定(因為運行時異常中有很多是代碼本身寫錯了昼浦,需要的不是處理異常,而是修改代碼筒主,如空指針異常关噪、數(shù)據(jù)訪問越界異常)鸟蟹。
  • 非運行時異常(受檢異常):必須對其進行處理,需要用 try...catch... 語句捕獲并進行處理(如果不進catch/throw處理的話使兔,就沒辦法通過編譯)建钥,并且可以從異常中恢復(fù)。除了RuntimeException及其子類以外虐沥,其他的Exception類及其子類都屬于受檢異常熊经。常見的受檢查異常有:IO 相關(guān)的異常、ClassNotFoundException欲险、SQLException

java常見的異常

  • java.lang.InstantiationError:實例化錯誤镐依。當一個應(yīng)用試圖通過new操作符構(gòu)造一個抽象類或者接口時拋出該異常.
  • java.lang.OutOfMemoryError:內(nèi)存不足錯誤。當可用內(nèi)存不足以讓Java虛擬機分配給一個對象時拋出該錯誤天试。
  • java.lang.StackOverflowError:堆棧溢出錯誤槐壳。當一個應(yīng)用遞歸調(diào)用的層次太深而導(dǎo)致堆棧溢出或者陷入死循環(huán)時拋出該錯誤。
  • java.lang.IndexOutOfBoundsException:索引越界異常秋秤。當訪問某個序列的索引值小于0或大于等于序列大小時宏粤,拋出該異常。
  • java.lang.NullPointerException:空指針異常灼卢。
  • java.lang.ArithmeticException:算術(shù)條件異常绍哎。譬如:整數(shù)除零等。

Throwable 類常用方法

  • public string getMessage():返回異常發(fā)生時的簡要描述鞋真;
  • public string toString():返回異常發(fā)生時的詳細信息崇堰;
  • public string getLocalizedMessage():返回異常對象的本地化信息。使用Throwable 的子類覆蓋這個方法涩咖,可以生成本地化信息海诲。如果子類沒有覆蓋該方法,則該方法返回的信息與getMessage()返回的結(jié)果相同檩互;
  • public void printStackTrace():在控制臺上打印 Throwable 對象封裝的異常信息特幔。

Object 類有哪些方法?

Object 類是一個特殊的類闸昨,是所有類的父類蚯斯。它主要提供了以下 11 個方法:

//native方法,用于返回當前運行時對象的Class對象饵较,使用了final關(guān)鍵字修飾拍嵌,故不允許子類重寫。
public final native Class<?> getClass()

//native方法循诉,用于返回對象的哈希碼横辆,主要使用在哈希表中,比如JDK中的HashMap茄猫。
public native int hashCode() 
public boolean equals(Object obj)//用于比較2個對象的內(nèi)存地址是否相等狈蚤,String類對該方法進行了重寫用戶比較字符串的值是否相等困肩。

protected native Object clone() throws CloneNotSupportedException//naitive方法,用于創(chuàng)建并返回當前對象的一份拷貝脆侮。一般情況下僻弹,對于任何對象 x,表達式 x.clone() != x 為true他嚷,x.clone().getClass() == x.getClass() 為true。Object本身沒有實現(xiàn)Cloneable接口芭毙,所以不重寫clone方法并且進行調(diào)用的話會發(fā)生CloneNotSupportedException異常筋蓖。

public String toString()//返回類的名字@實例的哈希碼的16進制的字符串。建議Object所有的子類都重寫這個方法退敦。

public final native void notify()//native方法粘咖,并且不能重寫。喚醒一個在此對象監(jiān)視器上等待的線程(監(jiān)視器相當于就是鎖的概念)侈百。如果有多個線程在等待只會任意喚醒一個瓮下。

public final native void notifyAll()//native方法,并且不能重寫钝域。跟notify一樣讽坏,唯一的區(qū)別就是會喚醒在此對象監(jiān)視器上等待的所有線程,而不是一個線程例证。

public final native void wait(long timeout) throws InterruptedException//native方法路呜,并且不能重寫。暫停線程的執(zhí)行织咧。注意:sleep方法沒有釋放鎖胀葱,而wait方法釋放了鎖 。timeout是等待時間笙蒙。

public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos參數(shù)抵屿,這個參數(shù)表示額外時間(以毫微秒為單位,范圍是 0-999999)捅位。 所以超時的時間還需要加上nanos毫秒轧葛。

public final void wait() throws InterruptedException//跟之前的2個wait方法一樣,只不過該方法一直等待绿渣,沒有超時時間這個概念

protected void finalize() throws Throwable { }//實例被垃圾回收器回收的時候觸發(fā)的操作

equals:檢測對象是否相等朝群,默認使用 == 比較對象引用,可以重寫 equals 方法自定義比較規(guī)則中符。equals 方法規(guī)范:自反性姜胖、對稱性、傳遞性淀散、一致性右莱、對于任何非空引用 x蚜锨,x.equals(null) 返回 false。

hashCode:散列碼是由對象導(dǎo)出的一個整型值慢蜓,沒有規(guī)律亚再,每個對象都有默認散列碼,值由對象存儲地址得出晨抡。字符串散列碼由內(nèi)容導(dǎo)出氛悬,值可能相同。為了在集合中正確使用耘柱,一般需要同時重寫 equals 和 hashCode如捅,要求 equals 相同 hashCode 必須相同,hashCode 相同 equals 未必相同调煎,因此 hashCode 是對象相等的必要不充分條件镜遣。

toString:打印對象時默認的方法,如果沒有重寫打印的是表示對象值的一個字符串士袄。

clone:clone 方法聲明為 protected悲关,類只能通過該方法克隆它自己的對象,如果希望其他類也能調(diào)用該方法必須定義該方法為 public娄柳。如果一個對象的類沒有實現(xiàn) Cloneable 接口寓辱,該對象調(diào)用 clone 方拋出一個** CloneNotSupport異常。默認的 clone 方法是淺拷貝赤拒,一般重寫 clone 方法需要實現(xiàn) Cloneable 接口并指定訪問修飾符為 public讶舰。

finalize:確定一個對象死亡至少要經(jīng)過兩次標記,如果對象在可達性分析后發(fā)現(xiàn)沒有與 GC Roots 連接的引用鏈會被第一次標記需了,隨后進行一次篩選跳昼,條件是對象是否有必要執(zhí)行 finalize 方法。假如對象沒有重寫該方法或方法已被虛擬機調(diào)用肋乍,都視為沒有必要執(zhí)行鹅颊。如果有必要執(zhí)行,對象會被放置在 F-Queue 隊列墓造,由一條低調(diào)度優(yōu)先級的 Finalizer 線程去執(zhí)行堪伍。虛擬機會觸發(fā)該方法但不保證會結(jié)束,這是為了防止某個對象的 finalize 方法執(zhí)行緩慢或發(fā)生死循環(huán)觅闽。只要對象在 finalize 方法中重新與引用鏈上的對象建立關(guān)聯(lián)就會在第二次標記時被移出回收集合帝雇。由于運行代價高昂且無法保證調(diào)用順序,在 JDK 9 被標記為過時方法蛉拙,并不適合釋放資源尸闸。

getClass:返回包含對象信息的類對象。

wait / notify / notifyAll:阻塞或喚醒持有該對象鎖的線程。

拓展:為什么Java把wait與notify放在Object中吮廉?

  • 功能角度
    1)wait與notify的原始目的苞尝,是多線程場景下,某條件觸發(fā)另一邏輯宦芦,該條件對應(yīng)的直接關(guān)系為某種對象宙址,進而對應(yīng)為Object,其對應(yīng)為內(nèi)存資源调卑。
    2)Thread對應(yīng)為CPU抡砂,與具體條件不是直接關(guān)系,Thread是對象的執(zhí)行依附者恬涧。

  • 內(nèi)存角度
    1)線程的同步需要Monitor的管理舀患,其與實際操作系統(tǒng)的重型資源(鎖)相關(guān)。
    2)只有涉及多線程的場景气破,才需要線程同步,如果wait與notify放在Thread餐抢,則每個Thread都需要分配Monitor现使,浪費資源。
    3)如果放在Object旷痕,單線程場景不分配Monitor碳锈,只在多線程分配。分配Monitor的方法為檢測threadId的不同欺抗。

獲取鍵盤輸入常用的兩種方法

  • Scanner
Scanner input = new Scanner(System. in);
String S = input .nextLine();
input. close();
  • BufferedReader (new InputStreamReader(System. in))
BufferedReader input = new BufferedReader(new InputStreamReader(System. in));
String S = input.readLine();

BufferedReader input = new BufferedReader(new FileReader(file));  // 按行讀取文件售碳!

Java引用和C指針的區(qū)別

  • 現(xiàn)象:指針在運行時可以改變其所指向的值(地址),即指向其它變量绞呈;而引用一旦和某個對象綁定后就不能再改變贸人,總是指向最初的對象。

  • 編譯:程序在編譯時分別將指針和引用添加到符號表上佃声,符號表上記錄的是變量名以及變量所對應(yīng)的地址艺智。指針變量在符號表上對應(yīng)的地址值為指針變量的地址值,而引用在符號表上對應(yīng)的地址值為引用對象的地址值圾亏。符號表生成后就不會再改十拣,指針可以改變,因此指針可以改變指向的對象(指針變量中的值可以改)志鹃,而引用對象不能改夭问。

  • 類型:引用其值為地址的數(shù)據(jù)元素,Java封裝了的地址曹铃,可以轉(zhuǎn)成字符串查看缰趋,長度可以不必關(guān)心,C指針是一個裝地址的變量,長度一般是計算機字長埠胖,可以認為是個int

  • 內(nèi)存占用:引用聲明時沒有實體糠溜,不占空間,C指針如果聲明后會用到才會賦值直撤,如果用不到不會分配內(nèi)存

  • 內(nèi)存溢出:java引用不用主動回收非竿。C指針是容易產(chǎn)生內(nèi)存溢出的,所以程序員需小心使用谋竖、及時回收红柱。

  • 初始化:java的引用初始值為 null。c的指針是int蓖乘,如不初始化指針锤悄,那它的值就不是固定的了。

本質(zhì):java中的引用和C++中的指針本質(zhì)上都是想通過一個叫做引用或者指針的東西嘉抒,找到要操作的目標(變量對象等)零聚,方便在程序里操作。所不同的是JAVA的辦法更安全些侍,方便些隶症,但沒有了C++的靈活,高效岗宣。

以上內(nèi)容僅供學(xué)習(xí)使用蚂会,如有錯誤,感謝指正耗式!

巨人的肩膀:

https://gitee.com/SnailClimb/JavaGuide
https://www.cnblogs.com/xrq730/p/4820992.html
https://www.nowcoder.com/discuss/447742?channel=-1&source_id=profile_follow_post_nctrack
https://blog.csdn.net/qq_33417486/article/details/82787598

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胁住,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子刊咳,更是在濱河造成了極大的恐慌彪见,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娱挨,死亡現(xiàn)場離奇詭異企巢,居然都是意外死亡,警方通過查閱死者的電腦和手機让蕾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門浪规,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人探孝,你說我怎么就攤上這事笋婿。” “怎么了顿颅?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵缸濒,是天一觀的道長。 經(jīng)常有香客問我,道長庇配,這世上最難降的妖魔是什么斩跌? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮捞慌,結(jié)果婚禮上耀鸦,老公的妹妹穿的比我還像新娘。我一直安慰自己啸澡,他們只是感情好袖订,可當我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嗅虏,像睡著了一般洛姑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皮服,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天楞艾,我揣著相機與錄音,去河邊找鬼龄广。 笑死硫眯,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蜀细。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼戈盈,長吁一口氣:“原來是場噩夢啊……” “哼奠衔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起塘娶,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤归斤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后刁岸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脏里,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年虹曙,在試婚紗的時候發(fā)現(xiàn)自己被綠了迫横。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡酝碳,死狀恐怖矾踱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疏哗,我是刑警寧澤呛讲,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響贝搁,放射性物質(zhì)發(fā)生泄漏吗氏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一雷逆、第九天 我趴在偏房一處隱蔽的房頂上張望弦讽。 院中可真熱鬧,春花似錦关面、人聲如沸坦袍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捂齐。三九已至,卻和暖如春缩抡,著一層夾襖步出監(jiān)牢的瞬間奠宜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工瞻想, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留压真,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓蘑险,卻偏偏與公主長得像滴肿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子佃迄,可洞房花燭夜當晚...
    茶點故事閱讀 45,446評論 2 359

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