Java基礎(chǔ)什么的最喜歡了

J2SE基礎(chǔ)

1. 九種基本數(shù)據(jù)類型的大小暗甥,以及他們的封裝類

注:事實上應(yīng)該是八種基本數(shù)據(jù)類型框往,String類并不屬于基本類型。

String a = "hello world"知允; String b = new String ("hello world");
先創(chuàng)建一個字符串對象“hello world”撒蟀,而這個字符串實際上是放在字符串緩沖區(qū)(敲黑板??)中,然后把a指向這個對象 創(chuàng)建兩個對象一個是“hello world”這個放在字符串緩沖區(qū)中的温鸽,另一個是new String()這個對象保屯,新對象中保存的是“hello world”對象罷了,這個對象是放在堆內(nèi)存(敲黑板??)中嗤朴,而b指向這個new String ()對象

字符串緩沖區(qū)中對相同的字符串只會存一次配椭。
假如我們同時寫了String a ="hello world",String b = new String("hello world")雹姊,那么字符串緩沖區(qū)實際只有一個hello world字符串股缸。

基本數(shù)據(jù)類型 大小 封裝類
byte 1字節(jié) Byte
short 2字節(jié) Short
int 4字節(jié) Integer
long 8字節(jié) Long
float 4字節(jié) Float
double 8字節(jié) Double
char 2字節(jié) Character(不推薦使用)
boolean 1字節(jié)或者4字節(jié) Boolean

往ArrayList,HashMap中放東西時吱雏,像int敦姻,double這種內(nèi)建類型是放不進去的瘾境,因為容器都是裝object的

《Java虛擬機規(guī)范》一書中的描述:“雖然定義了boolean這種數(shù)據(jù)類型,但是只對它提供了非常有限的支持镰惦。在Java虛擬機中沒有任何供boolean值專用的字節(jié)碼指令迷守,Java語言表達式所操作的boolean值,在編譯之后都使用Java虛擬機中的int數(shù)據(jù)類型來代替旺入,而boolean數(shù)組將會被編碼成Java虛擬機的byte數(shù)組兑凿,每個元素boolean元素占8位”。這樣我們可以得出boolean類型占了單獨使用是4個字節(jié),在數(shù)組中又是1個字節(jié)
PS:使用int的原因是库物,對于當(dāng)下32位的處理器(CPU)來說,一次處理數(shù)據(jù)是32位(這里不是指的是32/64位系統(tǒng)圣絮,而是指CPU硬件層面)更高效。

char是unsigned(無符號的)雕旨,byte/short/int/long/float/double是signed(有符號的)扮匠,boolean應(yīng)該是unsigned(個人的猜想,并未驗證過)
PS:因為char要用Unicode(敲黑板??)表示凡涩,必須16位棒搜,所以無符號,是實在擠不出來位了突照,要不然Java設(shè)計者肯定也設(shè)計成有符號的帮非,因為他覺得unsigned大部分人并不能真正搞懂??(不是針對你氧吐,是說在座的都是...)

//驗證char有幾位
public class Test {

    public static void main(String[] args) {
        System.out.println(java.nio.charset.Charset.defaultCharset());

        String str = "中";
        char x = '中';
        //也可以getBytes('utf-8')讹蘑,我的系統(tǒng)默認是utf-8
        byte[] bytesStr = str.getBytes();      
        byte[] bytesChar = charToByte(x);

        System.out.println("bytesStr 大小:" + bytesStr.length);
        byteResult(bytesStr);
        //其實這個輸出是沒意義的筑舅,只是純粹的格式整齊而已
        System.out.println("bytesChar 大凶俊:" + bytesChar.length);     
        byteResult(bytesChar);
    }

    private static byte[] charToByte(char c) {
        /**
         * 定義成3個字節(jié),只是為了更好的驗證翠拣,b[0]都是0版仔,并未使用
         * 當(dāng)然英文字母的情況下b[1]都是0,但這情況下實際是的確使用了的
         */
        byte[] b = new byte[3];       
        b[0] = (byte) ((c & 0xFF0000) >> 16);
        b[1] = (byte) ((c & 0xFF00) >> 8);
        b[2] = (byte) (c & 0xFF);
        return b;
    }

    private static void byteResult(byte[] bs) {
        for (byte b : bs) {
            for (int i = 7; i >= 0; i--) {
                System.out.print(b >> i & 1);
            }
            System.out.println();
        }
    }
}

結(jié)果如下:
UTF-8
bytesStr 大形竽埂:3
11100100
10111000
10101101
bytesChar 大新浮:3
00000000
01001110
00101101

為什么String和char按位輸出的結(jié)果不一樣呢?
因為char輸出的是Unicode格式谜慌,而String在本機的編譯器上輸出的是UTF-8格式
美國的ASCII全部編碼范圍是0-127(PS:編號從0開始的32種狀態(tài)分別規(guī)定了特殊的用途)
??
西歐國家規(guī)定從128 到255這一頁的字符集被稱擴展字符集
??
中國的GB2312(對ASCII 的中文擴展)規(guī)定:一個小于127的字符的意義與原來相同然想,但兩個大于127的字符連在一起時,就表示一個漢字欣范,前面的一個字節(jié)(高字節(jié))從0xA1用到0xF7变泄,后面一個字節(jié)(低字節(jié))從0xA1到0xFE令哟,這樣我們就可以組合出大約7000多個簡體漢字了(還包括了數(shù)學(xué)符號、羅馬希臘的字母妨蛹、日文的假名們)
PS:GB2312下一個字節(jié)大于0xA1屏富,就是漢字的內(nèi)碼的一部分(因為兩個字節(jié)才組成一個漢字)
??
但是中國的漢字太多了
0xA1十進制是161,那還有128->160的空間可以使用
還是不夠用
所以又規(guī)定只要第一個字節(jié)是大于127就固定表示這是一個漢字的開始蛙卤,不管后面跟的是不是擴展字
這就是GBK標(biāo)準(zhǔn)狠半,包括了GB2312 的所有內(nèi)容,同時又增加了近20000個新的漢字(包括繁體字)和符號
后來少數(shù)民族也要用電腦了颤难,又加了幾千個新的少數(shù)民族的字
GBK擴成了GB18030
??
計算機的巴比倫塔命題
ISO廢了所有的地區(qū)性編碼方案典予,重新搞一個包括了地球上所有文化、所有字母和符號的編碼乐严!
他們打算叫它”Universal Multiple-Octet Coded Character Set”瘤袖,簡稱UCS, 俗稱Unicode
Unicode開始制訂時昂验,計算機的存儲器容量極大地發(fā)展了捂敌,空間再也不成為問題了,于是ISO就直接規(guī)定必須用兩個字節(jié)既琴。
這種大氣的方案在保存英文文本時會多浪費一倍的空間(其高8位永遠是0)
??
直到互聯(lián)網(wǎng)的出現(xiàn)占婉,為解決Unicode如何在網(wǎng)絡(luò)上傳輸?shù)膯栴},于是面向傳輸?shù)谋姸郩TF(UCS Transfer Format)標(biāo)準(zhǔn)出現(xiàn)了甫恩,顧名思義逆济,UTF-8就是每次8個位傳輸數(shù)據(jù),而UTF-16就是每次16個位
UTF-8最大的一個特點磺箕,就是它是一種變長的編碼方式奖慌。它可以使用1~4個字節(jié)表示一個符號,根據(jù)不同的符號而變化字節(jié)長度
當(dāng)字符在ASCII碼的范圍時松靡,就用一個字節(jié)表示简僧,保留了ASCII字符一個字節(jié)的編碼做為它的一部分,注意的是Unicode一個中文字符占2個字節(jié)雕欺,而UTF-8一個中文字符占3個字節(jié)

Unicode符號范圍(十六進制) UTF-8編碼方式(二進制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

其中byte和short應(yīng)用于底層文件處理或者需要占據(jù)存儲空間量的大數(shù)組(如:byte[])岛马,舉個??,??

對象的序列化就是將你程序中實例化的某個類的對象屠列,比如啦逆,你自定一個類MyClass,或者任何一個類的對象笛洛,將它轉(zhuǎn)換成字節(jié)數(shù)組夏志,也就是說可以放到一個byte數(shù)組中,這時候撞蜂,你既然已經(jīng)把一個對象放到了byte數(shù)組中盲镶,那么你當(dāng)然就可以隨便處置了它了侥袜,用得最多的就是把他發(fā)送到網(wǎng)絡(luò)上遠程的計算機上了

對象的序列化

EJB概念
運行在一個獨立的服務(wù)器上,并封裝了業(yè)務(wù)邏輯的組件就是EJB(Enterprise JavaBean)
客戶端是通過網(wǎng)絡(luò)對EJB 對象進行調(diào)用的溉贿。在Java中枫吧,能夠?qū)崿F(xiàn)遠程對象調(diào)用的技術(shù)是RMI,而EJB 技術(shù)基礎(chǔ)正是RMI

RMI實現(xiàn)機制

2. Switch能否用string做參數(shù)

Java 7之后可以
在jdk1.7之前宇色,switch只能支持byte九杂、short、char宣蠕、int這幾個基本數(shù)據(jù)類型和其對應(yīng)的封裝類型例隆。switch后面的括號里面只能放int類型的值(敲黑板??),但由于byte抢蚀,short镀层,char類型,它們會自動轉(zhuǎn)換為int類型(精精度小的向大的轉(zhuǎn)化)皿曲,所以它們也支持唱逢。
注意,對于精度比int大的類型屋休,比如long坞古、float,doulble劫樟,不會自動轉(zhuǎn)換為int痪枫,如果想使用,就必須強轉(zhuǎn)為int叠艳,如(int)float;
為什么jdk1.7后又可以用string類型作為switch參數(shù)呢奶陈?
其實,jdk1.7并沒有新的指令來處理switch string虑绵,而是通過調(diào)用switch中string.hashCode()尿瞭,將string轉(zhuǎn)換為int從而進行判斷。

3. equals與==的區(qū)別

  1. 基本數(shù)據(jù)類型byte,short,char,int,long,float,double,boolean
    他們之間的比較翅睛,應(yīng)用==,比較的是他們的值黑竞。
  2. 復(fù)合數(shù)據(jù)類型(類)
    當(dāng)他們用==進行比較的時候捕发,比較的是他們在內(nèi)存中的存放地址,所以除非是同一個new出來的對象很魂,他們的比較后的結(jié)果為true扎酷,否則比較后結(jié)果為false。
  1. Java中默認的equals方法實現(xiàn)如下:
public boolean equals(Object obj) {
   return (this == obj);
}
  1. 而String類則覆寫了這個方法,直觀的講就是比較字符是不是都相同
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}

4. Object有哪些公用方法

  1. clone方法
    實現(xiàn)對象的淺拷貝(敲黑板??)遏匆,只有實現(xiàn)了Cloneable接口才可以調(diào)用該方法法挨,否則拋出CloneNotSupportedException異常谁榜。

在java語言中,有幾種方式可以創(chuàng)建對象呢(敲黑板??)

使用new操作符創(chuàng)建一個對象 使用clone方法復(fù)制一個對象
看new操作符后面的類型知道分配多大的內(nèi)存空間 分配和源對象的相同大小的內(nèi)存空間
再調(diào)用構(gòu)造函數(shù)凡纳,填充對象的各個域窃植,這一步叫做對象的初始化 然后再使用原對象中對應(yīng)的各個域,填充新對象的域
構(gòu)造方法返回后荐糜,一個對象創(chuàng)建完畢巷怜,可以引用(地址)發(fā)布到外部 clone方法返回,一個新的相同的對象被創(chuàng)建暴氏,同樣可以把這個新對象的引用發(fā)布到外部

復(fù)制引用 or 復(fù)制對象

//復(fù)制引用
public static void main(String[] args) {
    Person p = new Person(23, "zhang");
    Person p1 = p;

    System.out.println(p);
    System.out.println(p1);
}

public static class Person {
    private int age ;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

輸出結(jié)果:
java_study.CloneTest$Person@60e53b93
java_study.CloneTest$Person@60e53b93
同一個對象不同引用.png
//復(fù)制對象
public static void main(String[] args)  {
    Person p = new Person(23, "zhang");
    Person p1 = null;
    try {
        p1 = (Person) p.clone();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }

    System.out.println(p);
    System.out.println(p1);
}

public static class Person implements Cloneable {
    private int age ;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
         return age;
    }

    public String getName() {
        return name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

輸出結(jié)果:
java_study.CloneTest$Person@60e53b93
java_study.CloneTest$Person@5e2de80c
創(chuàng)建了新的對象

由于age是基本數(shù)據(jù)類型延塑, 那么對它的拷貝沒有什么疑議,直接將一個4字節(jié)的整數(shù)值拷貝過來就行答渔。但是name是String類型的关带, 它只是一個引用, 指向一個真正的String對象沼撕,那么對它的拷貝有兩種方式

淺拷貝和深拷貝的原理
//驗證原生clone是淺拷貝還是深拷貝
String result = p.getName() == p1.getName() ? "clone是淺拷貝的" : "clone是深拷貝的";
System.out.println(result);

輸出結(jié)果:
clone是淺拷貝的
//覆蓋Object中的clone方法豫缨, 實現(xiàn)深拷貝
public static void main(String[] args) throws CloneNotSupportedException {
    Body body = new Body(new Head());
    Body body1 = (Body) body.clone();

    System.out.println("body == body1 : " + (body == body1));
    System.out.println("body.head == body1.head : " + (body.head == body1.head));
    System.out.println("body.head.face == body1.head.face : " + (body.head.face == body1.head.face));
}

static class Body implements Cloneable {
    public Head head;

    public Body() {
    }

    public Body(Head head) {
        this.head = head;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Body newBody =  (Body) super.clone();
        newBody.head = (Head) head.clone();
        return newBody;
    }
}

static class Head implements Cloneable {
    public Face face;

    public Head() {
    }

    public Head(Face face) {
        this.face = face;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

static class Face {
}

輸出結(jié)果:
body == body1 : false
body.head == body1.head : false
body.head.face == body1.head.face : true
不徹底的深拷貝

如果想要深拷貝一個對象, 這個對象必須要實現(xiàn)Cloneable接口端朵,實現(xiàn)clone方法好芭,并且在clone方法內(nèi)部,把該對象引用的其他對象也要clone一份 冲呢, 這就要求這個被引用的對象必須也要實現(xiàn)Cloneable接口并且實現(xiàn)clone方法舍败。
(PS:clone的前提是對象new過,
例如Body body = new Body(new Head());
后來改造Face時忘記把new Head()里加上new Face()敬拓,一直報空指針??)

  1. getClass方法
    final方法邻薯,獲得運行時對象類型。
public static void main(String[] args) {
    A a = new A();
    B b = new B();
    A ab = new B();

    System.out.println(a.getClass() + " " + A.class);
    System.out.println(b.getClass() + " " + B.class);
    System.out.println(ab.getClass());
    ab = a;
    System.out.println(ab.getClass());
}

static class A {
}

static class B extends A {
}

輸出結(jié)果:
class A class A
class B class B
class B
class A
  1. toString方法
    該方法用得比較多乘凸,一般子類都有覆蓋厕诡。
    打印對象時默認調(diào)用toString方法
public static void main(String[] args) {
    Person p = new Person(23, "zhang");

    System.out.println(p);
}

public static class Person {
    private int age ;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

輸出結(jié)果:
zhang
  1. finalize方法
    垃圾回收器要回收對象的時候,首先要調(diào)用這個類的finalize方法营勤,一般的純Java編寫的Class不需要重新覆蓋這個方法灵嫌。
  1. equals方法
    該方法是非常重要的一個方法。一般equals和==是不一樣的葛作,但是在Object中兩者是一樣的寿羞。子類一般都要重寫這個方法。
  1. hashCode方法
    該方法用于哈希查找赂蠢,可以減少在查找中使用equals的次數(shù)绪穆,重寫了equals方法一般都要重寫hashCode方法。
public class HashTest {
    private int i;

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public int hashCode() {
        return i%10;
    }

    public boolean equals(Object object) {
        if (object == null || !(object instanceof HashTest))
            return false;
        HashTest other = (HashTest) object;
        if (object == this || other.getI() == this.getI())
            return true;
        return false;
    }

    public static void main(String[] args) {
        HashTest a = new HashTest();
        HashTest b = new HashTest();
        a.setI(1);
        b.setI(1);
        Set<HashTest> set = new HashSet<>();
        set.add(a);
        set.add(b);
        System.out.println(a.hashCode() == b.hashCode());
        System.out.println(a.equals(b));
        System.out.println(set);
    }
}

輸出結(jié)果:
true
true
[java_study.HashTest@1]

Set的集合里不允許對象有重復(fù)的值,List允許有重復(fù)玖院,它對集合中的對象進行索引菠红,Queue的工作原理是FCFS算法(First Come, First Serve)
如果不重寫hashCode(),在HashSet中添加兩個equals的對象(hashCode有可能會相同难菌,所以最后還是要用equals()比較)试溯,會將兩個對象都加入進去,這樣HashSet就失去了他本身的意義了扔傅。

  1. wait方法
    wait方法就是使當(dāng)前線程等待該對象的鎖耍共,當(dāng)前線程必須是該對象的擁有者,也就是具有該對象的鎖猎塞。wait()方法一直等待试读,直到獲得鎖或者被中斷。wait(long timeout)設(shè)定一個超時間隔荠耽,如果在規(guī)定時間內(nèi)沒有獲得鎖就返回钩骇。
    調(diào)用該方法后當(dāng)前線程進入睡眠狀態(tài),直到以下事件發(fā)生铝量。
    (1)其他線程調(diào)用了該對象的notify方法倘屹。
    (2)其他線程調(diào)用了該對象的notifyAll方法。
    (3)其他線程調(diào)用了interrupt中斷該線程慢叨。
    (4)時間間隔到了纽匙。
    此時該線程就可以被調(diào)度了,如果是被中斷的話就拋出一個InterruptedException異常拍谐。
  2. notify方法
    該方法喚醒在該對象上等待的某個線程烛缔。
  3. notifyAll方法
    該方法喚醒在該對象上等待的所有線程。

5. Java的四種引用轩拨,強弱軟虛践瓷,用到的場景

(1) 強引用(StrongReference)
??強引用是我們在編程過程中使用的最簡單的引用,如代碼String s=”abc”中變量s就是字符串對象”abc”的一個強引用亡蓉。任何被強引用指向的對象都不能被垃圾回收器回收晕翠,這些對象都是在程序中需要的。
(2) 軟引用(SoftReference)
??軟引用是用來描述一些有用但并不是必需的對象砍濒。對于軟引用關(guān)聯(lián)著的對象淋肾,只有在內(nèi)存不足的時候JVM才會回收該對象。因此梯影,這一點可以很好地用來解決OOM的問題巫员,并且這個特性很適合用來實現(xiàn)緩存:比如網(wǎng)頁緩存、圖片緩存等甲棍。
??軟引用可以和一個引用隊列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對象被JVM回收,這個軟引用就會被加入到與之關(guān)聯(lián)的引用隊列中感猛。  
(3) 弱引用(WeakReference)
??弱引用也是用來描述非必需對象的七扰,當(dāng)JVM進行垃圾回收時,無論內(nèi)存是否充足陪白,都會回收被弱引用關(guān)聯(lián)的對象颈走。
(4) 虛引用(PhantomReference)
??虛引用和前面的軟引用、弱引用不同咱士,它并不影響對象的生命周期立由。如果一個對象與虛引用關(guān)聯(lián),則跟沒有引用與之關(guān)聯(lián)一樣序厉,在任何時候都可能被垃圾回收器回收锐膜。
??要注意的是,虛引用必須和引用隊列關(guān)聯(lián)使用弛房,當(dāng)垃圾回收器準(zhǔn)備回收一個對象時道盏,如果發(fā)現(xiàn)它還有虛引用,就會把這個虛引用加入到與之關(guān)聯(lián)的引用隊列中文捶。程序可以通過判斷引用隊列中是否已經(jīng)加入了虛引用荷逞,來了解被引用的對象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個虛引用已經(jīng)被加入到引用隊列粹排,那么就可以在所引用的對象的內(nèi)存被回收之前采取必要的行動种远。

public class ReferenceTest {
    public static void main(String[] args) {
        // 軟引用,沒有隊列,可以有
        String hello = new String("hello");//強引用
        SoftReference<String> sr = new SoftReference<>(hello);
        hello = null;
        System.out.println(sr.get());
        System.out.println();

        // 弱引用,沒有隊列,可以有
        String hello1 = new String("hello1");
        WeakReference<String> sr1 = new WeakReference<>(hello1);
        hello1 = null;
        System.out.println(sr1.get());
        System.gc();
        System.out.println(sr1.get());
        System.out.println();

        // 虛引用,有隊列
        ReferenceQueue<String> queue = new ReferenceQueue<>();
        String hello2 = new String("hello2");
        PhantomReference<String> pr = new PhantomReference<>(hello2, queue);
        hello2 = null;
        System.out.println(pr.get());
        System.out.println();
    }
}

輸出結(jié)果:
hello
hello1
null
null

6. Hashcode的作用

見4.Object有哪些公用方法

7. ArrayList、LinkedList顽耳、Vector的區(qū)別

ArrayList LinkedList Vector
一個可改變大小的數(shù)組 一個雙鏈表 ArrayList類似坠敷,但屬于強同步類
大小將會動態(tài)地增長.內(nèi)部的元素可以直接通過get與set方法進行訪問 在添加和刪除元素時具有比ArrayList更好的性能 程序本身是線程安全的(thread-safe,沒有在多個線程之間共享同一個集合/對象),那么使用ArrayList是更好的選擇
每次對size增長50% 還實現(xiàn)了 Queue 接口 每次請求其大小的雙倍空間

8. String、StringBuffer與StringBuilder的區(qū)別

String StringBuffer StringBuilder
不可變類斧抱,任何對String的改變都會生成新的對象 可變類常拓,支持并發(fā)操作,適合多線程中使用 可變類辉浦,不支持并發(fā)操作弄抬,線程不安全的,單線程中的性能比StringBuffer高

經(jīng)常改變內(nèi)容的字符串最好不要用String宪郊,因為每次生成對象都會對系統(tǒng)性能產(chǎn)生影響掂恕,而如果是使用 StringBuffer 類則結(jié)果就不一樣了,每次結(jié)果都會對 StringBuffer 對象本身進行操作弛槐。而在某些特別情況下懊亡,String 效率是遠要比 StringBuffer 快的:
String S1 = "This is only a " + "simple " + "test";
StringBuffer Sb = new StringBuilder( "This is only a ").append( "simple ").append( "test");
你會很驚訝的發(fā)現(xiàn),生成 String S1 對象的速度簡直太快了乎串,而這個時候 StringBuffer 居然速度上根本一點都不占優(yōu)勢店枣。其實這是 JVM 的一個把戲,在 JVM 眼里,這個
String S1 = "This is only a " + "simple " + "test";其實就是:
String S1 = "This is only a simple test"; 所以當(dāng)然不需要太多的時間了鸯两。但大家這里要注意的是闷旧,如果你的字符串是來自另外的 String對象的話,速度就沒那么快了钧唐,譬如:
String S2 = "This is only a ";
String S3 = "simple " ;
String S4 = "test";
String S1 = S2 +S3 + S4;
這時候 JVM 會規(guī)規(guī)矩矩的按照原來的方式去做

9. Map忙灼、Set、List钝侠、Queue该园、Stack的特點與用法

Collection的類繼承

圖其實畫的不準(zhǔn)確了,LinkedHashSet應(yīng)該是繼承自HashSet
LinkedList也只是實現(xiàn)了Queue帅韧,并不是繼承哦??
Collection-------Iterable是該的父接口里初,iterator()方法用于遍歷操作
├ List-----------List可以通過下標(biāo) (1,2..) 來取得值,值可以重復(fù)
│├ LinkedList---線程不安全的弱匪,雙向鏈表實現(xiàn)
│├ ArrayList----線程不安全的青瀑,數(shù)組實現(xiàn)
│└ Vector-------線程安全的,數(shù)組實現(xiàn)
│   └ Stack----一個后進先出的棧萧诫,push斥难、pop、peak帘饶、empty哑诊、search
├ Set-----------Set只能通過Iterable(迭代器)來取值,并且值不能重復(fù)
│├ HashSet-----使用hash來存儲元素及刻,因此具有良好的存取和查找性能
││  └ LinkedHashSet--使用鏈表維護元素的次序镀裤,遍歷時按添加順序來訪問
│└ TreeSet------是SortedSet接口的實現(xiàn)類,可以確保元素處于排序狀態(tài)
└ Queue--------Queue保持一個隊列(先進先出)的順序缴饭,offer暑劝、poll、peek
└ PriorityQueue--按照隊列元素的大小進行重新排序

Map------不關(guān)心元素添加的順序颗搂,采用了hash担猛,因此查找元素比ArrayList快
├ Hashtable---------線程安全的,key和value不能為null
├ HashMap----------線程不安全的丢氢,key和value可以為null
│├ LinkedHashMap--雙向鏈表來維護key-value對的次序傅联,與插入順序一致
│└ WeakHashMap
├ TreeMap---紅黑樹數(shù)據(jù)結(jié)構(gòu),每個key-value對即作為紅黑樹的一個節(jié)點
└ IdentifyHashMap--當(dāng)且僅當(dāng)key1 == key2時疚察,才認為兩個key相等

10. HashMap和HashTable的區(qū)別

主要區(qū)別在多個線程訪問Hashtable時蒸走,不需要自己為它的方法實現(xiàn)同步,
而HashMap 就必須為之提供外同步(Collections.synchronizedMap)貌嫡。

11. HashMap和ConcurrentHashMap的區(qū)別比驻,HashMap的底層源碼

Hashmap本質(zhì)是數(shù)組加鏈表该溯。根據(jù)key取得hash值,然后計算出數(shù)組下標(biāo)嫁艇,如果多個key對應(yīng)到同一個下標(biāo)朗伶,就用鏈表串起來弦撩,新插入的在前面步咪。
ConcurrentHashMap:在hashMap的基礎(chǔ)上,ConcurrentHashMap將數(shù)據(jù)分為多個segment益楼,默認16個(concurrency level)猾漫,然后每次操作對一個segment加鎖,避免多線程鎖的幾率感凤,提高并發(fā)效率悯周。
后面的太多了??提取不了了http://blog.csdn.net/stephenxe/article/details/52386786

12. TreeMap、HashMap陪竿、LindedHashMap的區(qū)別

見9. Map禽翼、Set、List族跛、Queue闰挡、Stack的特點與用法

13. Collection包結(jié)構(gòu),與Collections的區(qū)別

Collections是一個包裝類(java.util.Collections)礁哄,此類不能實例化长酗,就像一個工具類,用于對集合中元素進行排序桐绒、搜索以及線程安全等各種操作
Collection接口的意義是為各種具體的集合提供了最大化的統(tǒng)一操作方式

14. try catch finally夺脾,try里有return,finally還執(zhí)行么

public static void main(String[] args) {
    fun();
}
static void fun() {
    try {
        System.out.println("代碼段");
        return;
    } catch (Exception e) {

    }finally {
        System.out.println("finally執(zhí)行");
    }
}

輸出結(jié)果:
代碼段 
finally執(zhí)行

(1) 在try中沒有異常的情況下try茉继、catch咧叭、finally的執(zhí)行順序 try — finally
(2) 如果try中有異常,執(zhí)行順序是try — catch — finally
(3) 如果try中沒有異常并且try中有return這時候正常執(zhí)行順序是try —- finally — return
(4) 如果try中有異常并且try中有return這時候正常執(zhí)行順序是try—-catch—finally— return
(5) 總之 finally 永遠執(zhí)行烁竭!

15. Excption與Error包結(jié)構(gòu)菲茬。OOM你遇到過哪些情況,SOF你遇到過哪些情況

(1) Exception與Error都繼承了Throwable
(2) Error類體系描述了Java運行系統(tǒng)中的內(nèi)部錯誤颖变,一般都是由JVM拋出生均,一般我們都不關(guān)注
(3) Exception類體系,如RuntimeException和IOException等繼承與它腥刹,一般都是由于程序本身的因數(shù)或是外部環(huán)境因數(shù)造成马胧,這是我們需要關(guān)注盡量解決的異常

JVM中常見的OutOfMemory和StackOverFlow產(chǎn)生的機理
首先必須了解JVM運行時數(shù)據(jù)區(qū)域
方法區(qū)
用于存儲已被JVM加載的類信息,常量衔峰,靜態(tài)變量佩脊,即時編譯器編譯后的代碼蛙粘,線程共享。
運行時常量池
方法區(qū)一部分威彰。存放編譯期生成的各種字面量和符號引用出牧。
虛擬機棧
內(nèi)部創(chuàng)建棧幀,來存放局部變量表歇盼,操作數(shù)棧舔痕,動態(tài)鏈接,方法出口等豹缀,線程私有伯复。
本地方法棧(HotSpot不區(qū)分虛擬機棧和本地方法棧)
類似虛擬機棧,但是只為Native方法服務(wù)邢笙。

存放實例對象和數(shù)組啸如,線程共享。
程序計數(shù)器
存放當(dāng)前線程執(zhí)行的字節(jié)碼的行號氮惯。

//堆OutOfMemory
public class HeapOOM {  
    static class OOMObject {  
      
    }  
      
    public static void main(String[] args) {  
        List<OOMObject> list = new ArrayList<OOMObject>();  
        while (true) {  
            list.add(new OOMObject());  
        }  
    }  
}  

//棧OutOfMemory
public class JavaVMStackOOM {  
    private void dontStop() {  
        while (true) {  
              
        }  
    }  
      
    public void stackLeakByThread() {  
        while (true) {  
            Thread thread = new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    dontStop();  
                }  
            });  
            thread.start();  
        }  
    }  
      
    public static void main(String[] args) {  
        JavaVMStackOOM oom = new JavaVMStackOOM();  
        oom.stackLeakByThread();  
    }  
}  

//StackOverFlow
public class JavaVMStackSOF {  
    private int stackLength = 1;  
    public void stackLeak() {  
        stackLength++;  
        stackLeak();  
    }  
    public static void main(String[] args) throws Throwable {  
        JavaVMStackSOF oom = new JavaVMStackSOF();  
        try {  
            oom.stackLeak();  
        } catch(Throwable e) {  
            System.out.println("stack length:" + oom.stackLength);  
            e.printStackTrace();  
        }  
    }  
} 

16. Java面向?qū)ο蟮娜齻€特征與含義

封裝:將可以描述這一類事物的屬性和行為歸納到一個類中叮雳,以方便使用,提高了代碼的利用和效率妇汗,降低了代碼的重復(fù)帘不。
繼承:封裝的屬性和行為沒有包含到具體某一事物,這時我們就需要繼承與封裝類添加這一具體事物所獨有的特征铛纬。
多態(tài):多態(tài)是以封裝和繼承為基礎(chǔ)的厌均,多態(tài)是站在一個抽象的層面去實施一個統(tǒng)一的行為,具體到個體時這個統(tǒng)一的行為會施行自己的特征行為告唆。

17. Override和Overload的含義去區(qū)別

Override(重寫棺弊、覆蓋)
方法名、參數(shù)擒悬、返回值相同
存在于子父類之間
定義成final不能被覆寫
子類方法不能縮小父類的訪問權(quán)限
子類不能拋出比父類更多的異常
Overload(重載模她,過載)
參數(shù)類型、個數(shù)懂牧、順序至少一個不同
返回值不同是不行的
存在于子類侈净、父類、同類
區(qū)別
Override是子類與父類之間的多態(tài)表現(xiàn)僧凤,Overload是一個類中的多態(tài)

18. Interface與abstract類的區(qū)別

Interface abstract
所有方法都是公開畜侦、抽象方法,所有屬性都是公開、靜態(tài)、常量 如果一個類如果要添加抽象方法就必須將類設(shè)置為abstract
類只能是實現(xiàn)接口莹汤,并且可以實現(xiàn)多個接口您朽,類必須實現(xiàn)接口的方法,否則為抽象類 abstract類必須被繼承使用缩膝,不能生成對象(所以Final和abstract永遠不會同時出現(xiàn))
接口可不寫public雇盖,但子類中實現(xiàn)接口的過程中public不可省 abstract的方法不可以private修飾
接口和接口之間可以允許多繼承 其子類必須覆蓋父類的抽象方法
接口是實現(xiàn)了不同層次蝗罗、不同體系對象的共同屬性 abstract和static不能在方法中放在一起(測了下類是可以放在一起的)

19. Static class 與not static class的區(qū)別

static class not static class
可以脫離外部類被創(chuàng)建 必須先new外部類义图,再new內(nèi)部類
只能訪問外部類的靜態(tài)成員 可以訪問外部類的數(shù)據(jù)和方法减俏,因為他就在外部類里面

20. java多態(tài)的實現(xiàn)原理

靠的是父類或接口定義的引用變量可以指向子類或具體實現(xiàn)類的實例對象,而程序調(diào)用的方法在運行期才動態(tài)綁定(敲黑板??)碱工,就是引用變量所指向的具體實例對象的方法娃承,也就是內(nèi)存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法

21. 實現(xiàn)多線程的兩種方法:Thread與Runable

public class ThreadRunableTest {

    public static void main(String[] args) {
        MyThreadRunnable mr = new MyThreadRunnable();
        new Thread(mr).start();
        new Thread(mr).start();
        new MyThread().start();
        new MyThread().start();
    }

    static class MyThreadRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("hello");
        }
    }
    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("world");
        }
    }

}

輸出結(jié)果:
hello
hello
world
world

22. 線程同步的方法:sychronized痛垛、lock草慧、reentrantLock等

如果你向一個變量寫值,而這個變量接下來可能會被另一個線程所讀取匙头,或者你從一個變量讀值,而它的值可能是前面由另一個線程寫入的仔雷,此時你就必須使用同步
synchronized會在進入同步塊的前后分別形成monitorenter和monitorexit字節(jié)碼指令.在執(zhí)行monitorenter指令時會嘗試獲取對象的鎖,如果此沒對象沒有被鎖,或者此對象已經(jīng)被當(dāng)前線程鎖住,那么鎖的計數(shù)器加一,每當(dāng)monitorexit被鎖的對象的計數(shù)器減一.直到為0就釋放該對象的鎖.由此synchronized是可重入的,不會出現(xiàn)自己把自己鎖死.
synchronized關(guān)鍵字可以作為函數(shù)的修飾符蹂析,也可作為函數(shù)內(nèi)的語句,也就是平時說的同步方法和同步語句塊碟婆。如果再細的分類电抚,synchronized可作用于instance變量、object reference(對象引用)竖共、static函數(shù)和class literals(類名稱字面常量)身上蝙叛。
在進一步闡述之前,我們需要明確幾點:
A.無論synchronized關(guān)鍵字加在方法上還是對象上公给,它取得的鎖都是對象(敲黑板??)借帘,而不是把一段代碼或函數(shù)當(dāng)作鎖――而且同步方法很可能還會被其他線程的對象訪問。
B.每個對象只有一個鎖(lock)與之相關(guān)聯(lián)淌铐。
C.實現(xiàn)同步是要很大的系統(tǒng)開銷作為代價的肺然,甚至可能造成死鎖,所以盡量避免無謂的同步控制腿准。

一际起、當(dāng)兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內(nèi)只能有一個線程得到執(zhí)行吐葱。另一個線程必須等待當(dāng)前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊街望。

public class Thread1 implements Runnable {
    public void run() {
        synchronized(this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
            }
        }
    }
    public static void main(String[] args) {
        Thread1 t1 = new Thread1();
        Thread ta = new Thread(t1, "A");
        Thread tb = new Thread(t1, "B");
        ta.start();
        tb.start();
    }
}

輸出結(jié)果:
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4

二、然而弟跑,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時灾前,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

public class Thread2 {
    public void m4t1() {
        synchronized (this) {
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void m4t2() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        final Thread2 myt2 = new Thread2();
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                myt2.m4t1();
            }
        }, "t1");
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                myt2.m4t2();
            }
        }, "t2");
        t1.start();
        t2.start();
    }
}

輸出結(jié)果:
t2 : 4
t1 : 4
t1 : 3
t2 : 3
t1 : 2
t2 : 2
t1 : 1
t2 : 1
t1 : 0
t2 : 0

三窖认、尤其關(guān)鍵的是豫柬,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時告希,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

//修改Thread2.m4t2()方法:  
public void m4t2() {
    synchronized (this) {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

輸出結(jié)果:
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

四烧给、第三個例子同樣適用其它同步代碼塊燕偶。也就是說,當(dāng)一個線程訪問object的一個synchronized(this)同步代碼塊時础嫡,它就獲得了這個object的對象鎖指么。結(jié)果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞榴鼎。

//修改Thread2.m4t2()方法如下:
public synchronized void m4t2() {  
    int i = 5;  
    while( i-- > 0) {  
        System.out.println(Thread.currentThread().getName() + " : " + i);  
        try {  
            Thread.sleep(500);  
        } catch (InterruptedException e) {
            e.printStackTrace();
        }  
    }  
}

輸出結(jié)果:
t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0
t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

具體見http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html??

Lock是一個接口伯诬,reentrantLock是Lock接口的一個實現(xiàn)類

Lock lock = new ReentrantLock();
    public void fun() {
        lock.lock();//得到鎖
        try {
            / /同步代碼段
        } finally{
            lock.unlock();//釋放鎖
        }
}

具體見http://blog.csdn.net/kai_wei_zhang/article/details/8196130

在并發(fā)量比較小的情況下,使用synchronized是個不錯的選擇巫财,但是在并發(fā)量比較高的情況下盗似,其性能下降很嚴重,此時ReentrantLock是個不錯的方案平项。

23. 鎖的等級:方法鎖赫舒、對象鎖、類鎖

對象鎖是用來控制實例方法之間的同步闽瓢,類鎖是用來控制靜態(tài)方法(或靜態(tài)變量互斥體)之間的同步
對于類鎖接癌,則會把整個類鎖住,也就說只能有一個對象擁有當(dāng)前類的鎖扣讼。當(dāng)一個對象擁有了類鎖之后缺猛,另外一個對象還想競爭鎖的話則會被阻塞。兩個對象A椭符,B荔燎,如果A正在訪問一個被類鎖修飾的方法function,那么B則不能訪問艰山。因為類鎖只能在同一時刻被一個對象擁有湖雹。相對于對象鎖,則是不同曙搬。還是A摔吏,B兩個對象,如果A正在訪問對象鎖修飾的function纵装,那么這個時候B也可以同時訪問征讲。
對于對象鎖,當(dāng)一個對象擁有鎖之后橡娄,訪問一個加了對象鎖的方法诗箍,而該方法中又調(diào)用了該類中其他加了對象鎖的方法,那么這個時候是不會阻塞住的挽唉。這是java通過可重入鎖機制(敲黑板??)實現(xiàn)的滤祖】昀牵可重入鎖指的是當(dāng)一個對象擁有對象鎖之后,可以重復(fù)獲取該鎖匠童。因為synchronized塊是可重入的埂材,所以當(dāng)你訪問一個對象鎖的方法的時候,在該方法中繼續(xù)訪問其他對象鎖方法是不會被阻塞的汤求。

// 對象鎖:形式1(方法鎖) 
public synchronized void Method1() { 
    System.out.println(“我是對象鎖也是方法鎖”); 
    try { 
        Thread.sleep(500); 
    } catch (InterruptedException e) { 
        e.printStackTrace(); 
    }
}

// 對象鎖:形式2(代碼塊形式)
public void Method2() {
    synchronized (this) {
        System.out.println("我是對象鎖");
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// 類鎖:形式1 
public static synchronized void Method1() { 
    System.out.println("我是類鎖一號"); 
    try { 
          Thread.sleep(500); 
    } catch (InterruptedException e) { 
        e.printStackTrace(); 
    }
}

// 類鎖:形式2
public void Method2() {
    synchronized (Test.class) {
        System.out.println("我是類鎖二號");
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

24. 寫出生產(chǎn)者消費者模式

public class ProduceConsumerTest {

    public static void main(String[] args) {
        MyService myService = new MyService();

        ProduceThread[] pt = new ProduceThread[2];
        ConsumeThread[] ct = new ConsumeThread[2];

        for (int i = 0; i < 2; i++) {
            pt[i] = new ProduceThread(myService);
            pt[i].setName(String.valueOf(i + 1));
            ct[i] = new ConsumeThread(myService);
            ct[i].setName(String.valueOf(i + 1));
            pt[i].start();
            ct[i].start();
        }
    }

    static class MyService {
        ArrayList<Integer> list = new ArrayList<>();     //用list存放生產(chǎn)之后的數(shù)據(jù)俏险,最大容量為1

        synchronized void produce() {
            try {
                while (!list.isEmpty()) {                //只有l(wèi)ist為空時才會去進行生產(chǎn)操作
                    System.out.println("生產(chǎn)者" + Thread.currentThread().getName() + " waiting");
                    this.wait();
                }
                int value = 9999;
                list.add(value);
                System.out.println("生產(chǎn)者" + Thread.currentThread().getName() + " Runnable");
                this.notifyAll();                       //然后去喚醒因object調(diào)用wait方法處于阻塞狀態(tài)的線程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        synchronized void consumer() {
            try {
                while (list.isEmpty()) {                //只有l(wèi)ist不為空時才會去進行消費操作
                    System.out.println("消費者" + Thread.currentThread().getName() + " waiting");
                    this.wait();
                }
                list.clear();
                System.out.println("消費者" + Thread.currentThread().getName() + " Runnable");
                this.notifyAll();                       //然后去喚醒因object調(diào)用wait方法處于阻塞狀態(tài)的線程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    static class ProduceThread extends Thread {
        private MyService p;

        ProduceThread(MyService p) {
            this.p = p;
        }

        @Override
        public void run() {
            while (true) {
                p.produce();
            }
        }
    }

    static class ConsumeThread extends Thread {
        private MyService c;

        ConsumeThread(MyService c) {
            this.c = c;
        }

        @Override
        public void run() {
            while (true) {
                c.consumer();
            }
        }
    }

}

輸出結(jié)果:
生產(chǎn)者1 Runnable
生產(chǎn)者1 waiting
消費者2 Runnable
消費者2 waiting
生產(chǎn)者2 Runnable
生產(chǎn)者2 waiting
消費者1 Runnable
消費者1 waiting
...
static class MyService {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private boolean hasValue = false;

    void produce() {
        lock.lock();
        try {
            while (hasValue == true) {
                System.out.println("生產(chǎn)者" + Thread.currentThread().getName() + " waiting");
                condition.await();
            }
            hasValue = true;
            System.out.println("生產(chǎn)者" + Thread.currentThread().getName() + " Runnable");
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void consumer() {
        lock.lock();
        try {
            while (hasValue == false) {
                System.out.println("消費者" + Thread.currentThread().getName() + " waiting");
                condition.await();
            }
            hasValue = false;
            System.out.println("消費者" + Thread.currentThread().getName() + " Runnable");
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

輸出結(jié)果:
生產(chǎn)者1 Runnable
生產(chǎn)者1 waiting
消費者1 Runnable
消費者1 waiting
生產(chǎn)者2 Runnable
生產(chǎn)者2 waiting
消費者2 Runnable
消費者2 waiting

25. ThreadLocal的設(shè)計理念與作用

他并不是一個Thread,而是thread local variable(線程局部變量)
雖然所有的線程都能訪問到這個ThreadLocal實例扬绪,但是每個線程卻只能訪問到自己通過調(diào)用ThreadLocal的set()方法設(shè)置的值竖独。即使是兩個不同的線程在同一個ThreadLocal對象上設(shè)置了不同的值,他們?nèi)匀粺o法訪問到對方的值挤牛。

public class ThreadLocalTest {
    public static void main(String[] args) {
        MyThreadRunnable mr = new MyThreadRunnable();
        Thread thread1 = new Thread(mr);
        Thread thread2 = new Thread(mr);
        thread1.start();
        thread2.start();
    }

    static class MyThreadRunnable implements Runnable {
        private ThreadLocal threadLocal = new ThreadLocal();

        @Override
        public void run() {
            threadLocal.set(new Random().nextInt(30));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadLocal.get());
        }
    }
}

26. ThreadPool用法與優(yōu)勢

線程池可以應(yīng)對突然大爆發(fā)量的訪問莹痢,通過有限個固定線程為大量的操作服務(wù),減少創(chuàng)建和銷毀線程所需的時間赊颠。

public class DifferentKindsThreadPool {

    public static void main(String[] args) {
        //displayScheduledThreadPool();
        //displaySingleThreadPool();
        //displayCachedThreadPool();
        displayThreadPool();
    }

    /**
     * 創(chuàng)建一個定時任務(wù)的線程池
     */
    public static void displayScheduledThreadPool() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(4);
        //它可以向固定線程池一樣執(zhí)行任務(wù)
        distributeTaskForThreadPool(scheduledThreadPool);
        //這是它的特殊之處格二,可以定時任務(wù)
        scheduledThreadPool.schedule(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("開始執(zhí)行任務(wù)1");
                    }
                },
                5,
                TimeUnit.SECONDS);
        //每隔2秒再次重新執(zhí)行任務(wù)
        scheduledThreadPool.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("開始執(zhí)行任務(wù)2");
                    }
                },
                5,
                2,
                TimeUnit.SECONDS);
    }

    /**
     * 創(chuàng)建只有一個線程的線程池,如果線程終止竣蹦,
     * 他將會創(chuàng)建一個新的線程加入到池子中,這
     * 個線程池會保證池子中始終有一個線程
     */
    public static void displaySingleThreadPool() {
        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
        distributeTaskForThreadPool(singleThreadPool);
    }

    /**
     * 創(chuàng)建一個可根據(jù)需要創(chuàng)建線程的線程池沧奴,但是
     * 當(dāng)先前創(chuàng)建的線程可得到時就會重用先前的線
     * 程痘括,如果不存在可得到的線程,一個新的線程
     * 將被創(chuàng)建并被加入到池子中滔吠。60秒沒有被用到
     * 的線程將被終止并從緩存中移除
     */
    public static void displayCachedThreadPool() {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        distributeTaskForThreadPool(cachedThreadPool);
    }

    /**
     * 創(chuàng)建一個帶有固定線程的線程池
     */
    public static void displayThreadPool() {
        // 創(chuàng)建一個帶有4個固定線程的線程池
        ExecutorService threadPool = Executors.newFixedThreadPool(4);
        distributeTaskForThreadPool(threadPool);
    }

    /**
     * 為線程池分配8個任務(wù)纲菌,使其驅(qū)動
     */
    public static void distributeTaskForThreadPool(ExecutorService threadPool) {
        // 讓線程池驅(qū)動8個任務(wù)
        for (int i = 1; i <= 8; i++) {
            // 由于內(nèi)部類里面不能放一個非final的變量,所以我把i的值賦予task
            final int task = i;

            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("我是" + Thread.currentThread().getName()
                            + "疮绷," + "拿到了第" + task + "個任務(wù)翰舌,我開始執(zhí)行了");
                }
            });
        }
    }
}
public class BankTest {
    public static void main(String[] args) {
        BankCount bankCount = new BankCount();

        ExecutorService executor = Executors.newFixedThreadPool(10);
        executor.execute(new Runnable() {                   //存錢線程
            @Override
            public void run() {
                int i = 5;
                while (i-- > 0) {
                    bankCount.addMoney(200);
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Future future = executor.submit(new Runnable() {    //取錢線程
            @Override
            public void run() {
                int i = 5;
                while (i-- > 0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    bankCount.getMoney(200);
                }
            }
        });
        try {
            Object res = future.get();
            System.out.println(res);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();                            // 關(guān)閉線程池
        }
    }

    static class BankCount {
        public synchronized void addMoney(int money) {
            System.out.println(Thread.currentThread().getName() + ">存入:" + money);
        }

        public synchronized void getMoney(int money) {
            System.out.println(Thread.currentThread().getName() + ">取錢:" + money);
        }
    }
}

27. Concurrent包里的其他東西:ArrayBlockingQueue、CountDownLatch等等

...

28. wait()和sleep()的區(qū)別

(1) 這兩個方法來自不同的類分別是Thread和Object
(2) 最主要是sleep方法沒有釋放鎖(OS認為該線程正在工作冬骚,不會讓出系統(tǒng)資源)椅贱,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法
(3) wait只冻、notify和notifyAll只能在同步控制方法或者同步控制塊里面使用庇麦,而sleep可以在任何地方使用
4,sleep必須捕獲異常,而wait喜德、notify和notifyAll不需要捕獲異常

29. foreach與正常for循環(huán)效率對比

使用foreach的對象必須實現(xiàn)Iterator接口山橄,對Iterator進行了更多操作,效率相比for更低舍悯。但是也有例外:

public class ForAndForeachTest {
    public static void main(String[] args) {
        //實例化arrayList
        List<Integer> arrayList = new ArrayList<Integer>();
        //實例化linkList
        List<Integer> linkList = new LinkedList<Integer>();

        //插入10萬條數(shù)據(jù)
        for (int i = 0; i < 100000; i++) {
            arrayList.add(i);
            linkList.add(i);
        }

        int array = 0;
        //用for循環(huán)arrayList
        long arrayForStartTime = System.currentTimeMillis();
        for (int i = 0; i < arrayList.size(); i++) {
            array = arrayList.get(i);
        }
        long arrayForEndTime = System.currentTimeMillis();
        System.out.println("用for循環(huán)arrayList 10萬次花費時間:" + (arrayForEndTime - arrayForStartTime) + "毫秒");

        //用foreach循環(huán)arrayList
        long arrayForeachStartTime = System.currentTimeMillis();
        for (Integer in : arrayList) {
            array = in;
        }
        long arrayForeachEndTime = System.currentTimeMillis();
        System.out.println("用foreach循環(huán)arrayList 10萬次花費時間:" + (arrayForeachEndTime - arrayForeachStartTime) + "毫秒");

        //用for循環(huán)linkList
        long linkForStartTime = System.currentTimeMillis();
        int link = 0;
        for (int i = 0; i < linkList.size(); i++) {
            link = linkList.get(i);
        }
        long linkForEndTime = System.currentTimeMillis();
        System.out.println("用for循環(huán)linkList 10萬次花費時間:" + (linkForEndTime - linkForStartTime) + "毫秒");

        //用froeach循環(huán)linkList
        long linkForeachStartTime = System.currentTimeMillis();
        for (Integer in : linkList) {
            link = in;
        }
        long linkForeachEndTime = System.currentTimeMillis();
        System.out.println("用foreach循環(huán)linkList 10萬次花費時間:" + (linkForeachEndTime - linkForeachStartTime) + "毫秒");
    }
}

輸出測試:
用for循環(huán)arrayList 10萬次花費時間:3毫秒
用foreach循環(huán)arrayList 10萬次花費時間:3毫秒
用for循環(huán)linkList 10萬次花費時間:7037毫秒
用foreach循環(huán)linkList 10萬次花費時間:3毫秒

30. Java IO與NIO

IO NIO
面向流 面向緩沖
阻塞IO 非阻塞IO
選擇器

具體見http://ifeve.com/java-nio-vs-io/

31. 反射的作用與原理

在程序運行期間獲得類里面的信息
反射的常用方法:
(1) forName(String className)
返回與帶有給定字符串名的類或接口相關(guān)聯(lián)的 Class 對象
(2) forName(String name, boolean initialize, ClassLoader loader)
使用給定的類加載器航棱,返回與帶有給定字符串名的類或接口相關(guān)聯(lián)的 Class 對象
(3) getAnnotation(Class<A> annotationClass)
如果存在該元素的指定類型的注釋睡雇,則返回這些注釋,否則返回 null
(4) getAnnotations()
返回此元素上存在的所有注釋
(5) getConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象饮醇,它反映此 Class 對象所表示的類的指定公共構(gòu)造方法
(6) getDeclaredField(String name)
返回一個 Field 對象它抱,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段
(7) getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法

public class ImitateTest {
    public static void main(String[] args) {
        //1. 首先我們創(chuàng)建一個bean,模擬從前端獲取的數(shù)據(jù)
        ImitateTest t = new ImitateTest();
        Bean bean = t.getBean();
        //2.生成我們需要的SQL 并設(shè)值
        t.save(bean);
    }

    private Bean getBean() {
        //模擬用反射實現(xiàn)
        Bean bean = null;
        try {
            Class c = Class.forName("java_study.Bean");
            bean = (Bean) c.newInstance();
            // 私有字段無法訪問驳阎,我們通過方法賦值
            Method m1 = c.getDeclaredMethod("setId", Integer.class);
            Method m2 = c.getDeclaredMethod("setName", String.class);
            Method m3 = c.getDeclaredMethod("setPassword", String.class);
            m1.invoke(bean, 1);
            m2.invoke(bean, "admin");
            m3.invoke(bean, "123456");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bean;
    }

    //假設(shè)我們的表  就是 BEAN
    private void save(Bean bean) {
        Field[] fields = Bean.class.getDeclaredFields();
        StringBuffer sb = new StringBuffer("INSERT INTO BEAN VALUES");
        sb.append(getInsertStr(fields.length));
        //這里我們可以看到SQL 已經(jīng)生成
        System.out.println(sb);
        //這里就是我們的JDBC 根據(jù)字段名字賦值 的操作了抗愁。
        //當(dāng)然hibernate 寫得肯定會復(fù)雜很多,但是基本原理不變
    }

    private String getInsertStr(int fields) {
        StringBuffer sb = new StringBuffer("(");
        for (int i = 0; i < fields; i++) {
            sb.append("?,");
        }
        sb.delete(sb.length() - 1, sb.length());
        sb.append(")");
        return sb.toString();
    }
}

32. 泛型常用特點呵晚,List<String>能否轉(zhuǎn)為List<Object>

一個方法如果接收List<Object>作為形式參數(shù)蜘腌,那么如果嘗試將一個List<String>的對象作為實際參數(shù)傳進去,卻發(fā)現(xiàn)無法通過編譯饵隙。雖然從直覺上來說撮珠,Object是String的父類,這種類型轉(zhuǎn)換應(yīng)該是合理的金矛。但是實際上這會產(chǎn)生隱含的類型轉(zhuǎn)換問題芯急,因此編譯器直接就禁止這樣的行為。
Java中的泛型基本上都是在編譯器這個層次來實現(xiàn)的驶俊。在生成的Java字節(jié)代碼中是不包含泛型中的類型信息的娶耍。使用泛型的時候加上的類型參數(shù),會被編譯器在編譯的時候去掉饼酿。這個過程就稱為類型擦除(敲黑板??)榕酒。如在代碼中定義的List<Object>和List<String>等類型,在編譯之后都會變成List故俐。JVM看到的只是List想鹰,而由泛型附加的類型信息對JVM來說是不可見的。Java編譯器會在編譯時盡可能的發(fā)現(xiàn)可能出錯的地方药版,但是仍然無法避免在運行時刻出現(xiàn)類型轉(zhuǎn)換異常的情況辑舷。

//所聲明的類型參數(shù)在Java類中可以像一般的類型一樣作為方法的參數(shù)和返回值,或是作為域和局部變量的類型槽片。
//但是由于類型擦除機制何缓,類型參數(shù)并不能用來創(chuàng)建對象或是作為靜態(tài)變量的類型。
class ClassTest<X, Y , Z extends Number> {
    private X x;
    private static Y y; //編譯錯誤筐乳,不能用在靜態(tài)變量中    
    public X getFirst() {
        //正確用法        
        return x;
    }
    public void wrong() {
        Z z = new Z(); //編譯錯誤歌殃,不能創(chuàng)建對象    
    }
}

33. 解析XML的幾種方式的原理與特點:DOM、SAX蝙云、PULL

SAX解析器的優(yōu)點是解析速度快氓皱,占用內(nèi)存少。
DOM在內(nèi)存中以樹形結(jié)構(gòu)存放,因此檢索和更新效率會更高波材。但是對于特別大的文檔股淡,解析和加載整個文檔將會很耗資源。
PULL解析器的運行方式和SAX類似廷区,都是基于事件的模式唯灵。PULL解析器小巧輕便,解析速度快隙轻,簡單易用埠帕。

具體見http://blog.csdn.net/cangchen/article/details/44034799

34. Java與C++對比

具體見http://www.cnblogs.com/sunyoung/p/5975995.html

35. Java1.7與1.8新特性

具體見http://blog.csdn.net/ludx212/article/details/17281729

36. 設(shè)計模式:單例、工廠玖绿、適配器敛瓷、責(zé)任鏈、觀察者等等

37. JNI的使用

具體見http://blog.csdn.net/jiangwei0910410003/article/details/17465085

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斑匪,一起剝皮案震驚了整個濱河市呐籽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚀瘸,老刑警劉巖狡蝶,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異贮勃,居然都是意外死亡贪惹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門寂嘉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馍乙,“玉大人,你說我怎么就攤上這事垫释。” “怎么了撑瞧?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵棵譬,是天一觀的道長。 經(jīng)常有香客問我预伺,道長订咸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任酬诀,我火速辦了婚禮脏嚷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瞒御。我一直安慰自己父叙,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趾唱,像睡著了一般涌乳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甜癞,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天夕晓,我揣著相機與錄音,去河邊找鬼悠咱。 笑死蒸辆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的析既。 我是一名探鬼主播躬贡,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渡贾!你這毒婦竟也來了逗宜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤空骚,失蹤者是張志新(化名)和其女友劉穎纺讲,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體囤屹,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡熬甚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肋坚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乡括。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖智厌,靈堂內(nèi)的尸體忽然破棺而出诲泌,到底是詐尸還是另有隱情,我是刑警寧澤铣鹏,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布敷扫,位于F島的核電站,受9級特大地震影響诚卸,放射性物質(zhì)發(fā)生泄漏葵第。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一合溺、第九天 我趴在偏房一處隱蔽的房頂上張望卒密。 院中可真熱鬧,春花似錦棠赛、人聲如沸哮奇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屏镊。三九已至依疼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間而芥,已是汗流浹背律罢。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留棍丐,地道東北人误辑。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像歌逢,于是被迫代替她去往敵國和親巾钉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法秘案,類相關(guān)的語法砰苍,內(nèi)部類的語法,繼承相關(guān)的語法阱高,異常的語法赚导,線程的語...
    子非魚_t_閱讀 31,598評論 18 399
  • 一:java概述:1,JDK:Java Development Kit赤惊,java的開發(fā)和運行環(huán)境吼旧,java的開發(fā)工...
    ZaneInTheSun閱讀 2,635評論 0 11
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,079評論 0 62
  • 畢業(yè)一年,好似回到最初的起點裕膀。 【畢業(yè)前夕】 為畢業(yè)選擇工作员串,其實我準(zhǔn)備了三年。 學(xué)校采用通識教...
    _你會陪我看細水長流_閱讀 216評論 0 0
  • 破天荒她發(fā)來了信息昼扛, 這是分開一年多唯一的她主動發(fā)來的信息 雖然說是交待一下沒有了結(jié)的事 他都欣喜若狂了昵济,他忘不了...
    蜀山袖手人閱讀 138評論 0 2