針對《面試心得與總結—BAT、網易、蘑菇街》一文中出現的技術問題的收集與整理(2)

16. Java面向對象的三個特徵與含義

1 . 封裝性

  將對象的狀態信息儘可能的隱藏在對象內部,只保留有限的接口和方法與外界進行交互,從而避免了外界對對象內部屬性的破壞。

  Java中使用訪問控制符來保護對類、變量、方法和構造方法的訪問

2. 繼承

   java通過繼承創建分等級層次的類,可以理解爲一個對象從另一個對象獲取屬性的過程。

3.多態

  多態是同一個行爲具有多個不同表現形式或形態的能力。 多態性是對象多種表現形式的體現

參考鏈接:https://yq.aliyun.com/articles/52843

17. Override和Overload的含義和區別

方法的重寫(Overriding)和重載(Overloading)是Java多態性的不同表現。   
重寫(Overriding)是父類與子類之間多態性的一種表現,而重載(Overloading)是一個類中多態性的一種表現。如果在子類中定義某方法與其父類有相同的名稱和參數,我們說該方法被重寫 (Overriding) 。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被"屏蔽"了。如果在一個類中定義了多個同名的方法,它們或有不同的參數個數或有不同的參數類型或有不同的參數次序,則稱爲方法的重載(Overloading)。不能通過訪問權限、返回類型、拋出的異常進行重載。 

1. Override 特點   
1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;   
2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;   
3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類; 
4、方法被定義爲final不能被重寫。  
5、對於繼承來說,如果某一方法在父類中是訪問權限是private,那麼就不能在子類對其進行重寫覆蓋,如果定義的話,也只是定義了一個新方法,而不會達到重寫覆蓋的效果。(通常存在於父類和子類之間。) 

2.Overload 特點   
1、在使用重載時只能通過不同的參數樣式。例如,不同的參數類型,不同的參數個數,不同的參數順序(當然,同一方法內的幾個參數類型必須不一樣,例如可以是fun(int, float), 但是不能爲fun(int, int));   
2、不能通過訪問權限、返回類型、拋出的異常進行重載;   
3、方法的異常類型和數目不會對重載造成影響;   
4、重載事件通常發生在同一個類中,不同方法之間的現象。 
5、存在於同一類中,但是隻有虛方法和抽象方法才能被覆寫。 

其具體實現機制: 

overload是重載,重載是一種參數多態機制,即代碼通過參數的類型或個數不同而實現的多態機制。 是一種靜態的綁定機制(在編譯時已經知道具體執行的是哪個代碼段)。   
    
override是覆蓋。覆蓋是一種動態綁定的多態機制。即在父類和子類中同名元素(如成員函數)有不同 的實現代碼。執行的是哪個代碼是根據運行時實際情況而定的。


18. Interface與abstract類的區別

抽象類和接口都不能夠實例化,但可以定義抽象類和接口類型的引用。一個類如果繼承了某個抽象類或者實現了某個接口都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明爲抽象類。接口比抽象類更加抽象,因爲抽象類中可以定義構造器,可以有抽象方法和具體方法,而接口中不能定義構造器而且其中的方法全部都是抽象方法。抽象類中的成員可以是private、默認、protected、public的,而接口中的成員全都是public的。抽象類中可以定義成員變量,而接口中定義的成員變量實際上都是常量。有抽象方法的類必須被聲明爲抽象類,而抽象類未必要有抽象方法。

19. Static class 與non static class的區別

內部靜態類不需要有指向外部類的引用。但非靜態內部類需要持有對外部類的引用。非靜態內部類能夠訪問外部類的靜態和非靜態成員。靜態類不能訪問外部類的非靜態成員。他只能訪問外部類的靜態成員。一個非靜態內部類不能脫離外部類實體被創建,一個非靜態內部類可以訪問外部類的數據和方法,因爲他就在外部類裏面。

1.首先是類中的數據,static的
class A {
static int a;
}
class B {
int b;
}
無論新建幾個A對象,這幾個對象公用一個int a,一個對象的a改變,另一個也會改變。
而B對象,不同對象之間的int b獨立存在,互不影響,可以有多個值。

2.類中的方法
靜態的方法,不需要建立對象就可以訪問
如Math.abs()這個方法,我們沒有建立Math的對象,就可以通過類名直接使用abs這個方法。
而非靜態的方法,必須先建立對象,然後通過對象名,調用這個方法。
如JButton jb = new JButton();
jb.addActionListener(l);

ps:在靜態方法的定義中,不能直接引用本類的其他非靜態方法。例如。我們不能在main中直接引用,本類的其他方法。所以我們經常可以看見,在main方法中,先建立本類的一個對象,然後才通過對象調用本類的其他方法。

3.在初始化過程中,靜態的總是先初始化

20. java多態的實現原理。

參考鏈接:http://www.cnblogs.com/startRuning/p/5673485.html


21. 實現多線程的兩種方法:Thread與Runable

Thread 和 Runnable 的相同點:都是“多線程的實現方式”。
Thread 和 Runnable 的不同點:
Thread 是類,而Runnable是接口;Thread本身是實現了Runnable接口的類。我們知道“一個類只能有一個父類,但是卻能實現多個接口”,因此Runnable具有更好的擴展性。
此外,Runnable還可以用於“資源的共享”。即,多個線程都是基於某一個Runnable對象建立的,它們會共享Runnable對象上的資源。
通常,建議通過“Runnable”實現多線程

參考鏈接:http://hjsj186.blog.163.com/blog/static/2465820332015218115231968/

22. 線程同步的方法:sychronized、lock、reentrantLock等

一.什麼是sychronized

sychronized是Java中最基本同步互斥的手段,可以修飾代碼塊,方法,類.

在修飾代碼塊的時候需要一個reference對象作爲鎖的對象.

在修飾方法的時候默認是當前對象作爲鎖的對象.

在修飾類時候默認是當前類的Class對象作爲鎖的對象.

synchronized會在進入同步塊的前後分別形成monitorenter和monitorexit字節碼指令.在執行monitorenter指令時會嘗試獲取對象的鎖,如果此沒對象沒有被鎖,或者此對象已經被當前線程鎖住,那麼鎖的計數器加一,每當monitorexit被鎖的對象的計數器減一.直到爲0就釋放該對象的鎖.由此synchronized是可重入的,不會出現自己把自己鎖死.


二.什麼ReentrantLock

以對象的方式來操作對象鎖.相對於sychronized需要在finally中去釋放鎖 

三.synchronized和ReentrantLock的區別

除了synchronized的功能,多了三個高級功能.

等待可中斷,公平鎖,綁定多個Condition.

1.等待可中斷

在持有鎖的線程長時間不釋放鎖的時候,等待的線程可以選擇放棄等待.   tryLock(long timeout, TimeUnit unit)

2.公平鎖

按照申請鎖的順序來一次獲得鎖稱爲公平鎖.synchronized的是非公平鎖,ReentrantLock可以通過構造函數實現公平鎖.    new RenentrantLock(boolean fair)

3.綁定多個Condition

通過多次newCondition可以獲得多個Condition對象,可以簡單的實現比較複雜的線程同步的功能.通過await(),signal();


分析理解:
在併發量比較小的情況下,使用synchronized是個不錯的選擇,但是在併發量比較高的情況下,其性能下降很嚴重,此時ReentrantLock是個不錯的方案。

 

1、ReentrantLock 擁有Synchronized相同的併發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候

     線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定,

     如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷

     如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而幹別的事情

 

    ReentrantLock獲取鎖定與三種方式:
    a)  lock(), 如果獲取了鎖立即返回,如果別的線程持有鎖,當前線程則一直處於休眠狀態,直到獲取鎖

    b) tryLock(), 如果獲取了鎖立即返回true,如果別的線程正持有鎖,立即返回false;

    c)tryLock(long timeout,TimeUnit unit),   如果獲取了鎖定立即返回true,如果別的線程正持有鎖,會等待參數給定的時間,在等待的過程中,如果獲取了鎖定,就返回true,如果等待超時,返回false;

    d) lockInterruptibly:如果獲取了鎖定立即返回,如果沒有獲取鎖定,當前線程處於休眠狀態,直到或者鎖定,或者當前線程被別的線程中斷

 

2、synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中

 

3、在資源競爭不是很激烈的情況下,Synchronized的性能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態;

JDK5.0的多線程任務包對於同步的性能方面有了很大的改進,在原有synchronized關鍵字的基礎上,又增加了ReentrantLock,以及各種Atomic類。瞭解其性能的優劣程度,有助與我們在特定的情形下做出正確的選擇。 

總體的結論先擺出來:  

synchronized: 
在資源競爭不是很激烈的情況下,偶爾會有同步的情形下,synchronized是很合適的。原因在於,編譯程序通常會儘可能的進行優化synchronize,另外可讀性非常好,不管用沒用過5.0多線程包的程序員都能理解。 

ReentrantLock: 
ReentrantLock提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,性能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的性能一下子能下降好幾十倍。而ReentrantLock確還能維持常態。 

Atomic: 
和上面的類似,不激烈情況下,性能比synchronized略遜,而激烈的時候,也能維持常態。激烈的時候,Atomic的性能會優於ReentrantLock一倍左右。但是其有一個缺點,就是隻能同步一個值,一段代碼中只能出現一個Atomic的變量,多於一個同步無效。因爲他不能在多個Atomic之間同步。 


所以,我們寫同步的時候,優先考慮synchronized,如果有特殊需要,再進一步優化。ReentrantLock和Atomic如果用的不好,不僅不能提高性能,還可能帶來災難。

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

方法鎖(synchronized修飾方法時)

通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。

synchronized 方法控制對類成員變量的訪問:
每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨佔該鎖,直到從該方法返回時纔將鎖釋放,此後被阻塞的線程方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對於每一個類實例,其所有聲明爲 synchronized 的成員函數中至多隻有一個處於可執行狀態,從而有效避免了類成員變量的訪問衝突。

對象鎖(synchronized修飾方法或代碼塊)

  當一個對象中有synchronized method或synchronized block的時候調用此對象的同步方法或進入其同步區域時,就必須先獲得對象鎖。如果此對象的對象鎖已被其他調用者佔用,則需要等待此鎖被釋放。(方法鎖也是對象鎖)       

java的所有對象都含有1個互斥鎖,這個鎖由JVM自動獲取和釋放。線程進入synchronized方法的時候獲取該對象的鎖,當然如果已經有線程獲取了這個對象的鎖,那麼當前線程會等待;synchronized方法正常返回或者拋異常而終止,JVM會自動釋放對象鎖。這裏也體現了用synchronized來加鎖的1個好處,方法拋異常的時候,鎖仍然可以由JVM來自動釋放。

類鎖(synchronized 修飾靜態的方法或代碼塊)

  由於一個class不論被實例化多少次,其中的靜態方法和靜態變量在內存中都只有一份。所以,一旦一個靜態的方法被申明爲synchronized。此類所有的實例化對象在調用此方法,共用同一把鎖,我們稱之爲類鎖。  

對象鎖是用來控制實例方法之間的同步,類鎖是用來控制靜態方法(或靜態變量互斥體)之間的同步。 

類鎖只是一個概念上的東西,並不是真實存在的,它只是用來幫助我們理解鎖定實例方法和靜態方法的區別的。

24. 寫出生產者消費者模式。

生產者-消費者(producer-consumer)問題,也稱作有界緩衝區(bounded-buffer)問題,兩個進程共享一個公共的固定大小的緩衝區。其中一個是生產者,用於將消息放入緩衝區;另外一個是消費者,用於從緩衝區中取出消息。問題出現在當緩衝區已經滿了,而此時生產者還想向其中放入一個新的數據項的情形,其解決方法是讓生產者此時進行休眠,等待消費者從緩衝區中取走了一個或者多個數據後再去喚醒它。同樣地,當緩衝區已經空了,而消費者還想去取消息,此時也可以讓消費者進行休眠,等待生產者放入一個或者多個數據時再喚醒它。

一,首先定義公共資源類,其中的變量number是保存的公共數據。並且定義兩個方法,增加number的值和減少number的值。由於多線程的原因,必須加上synchronized關鍵字,注意while判斷的條件。

    /** 
     * 公共資源類 
     */  
    public class PublicResource {  
        private int number = 0;  
      
        /** 
         * 增加公共資源 
         */  
        public synchronized void increace() {  
            while (number != 0) {  
                try {  
                    wait();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
            number++;  
            System.out.println(number);  
            notify();  
        }  
      
        /** 
         * 減少公共資源 
         */  
        public synchronized void decreace() {  
            while (number == 0) {  
                try {  
                    wait();  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
            number--;  
            System.out.println(number);  
            notify();  
        }  
    }  

二,分別定義生產者線程和消費者線程,並模擬多次生產和消費,即增加和減少公共資源的number值
    /** 
     * 生產者線程,負責生產公共資源 
     */  
    public class ProducerThread implements Runnable {  
        private PublicResource resource;  
      
        public ProducerThread(PublicResource resource) {  
            this.resource = resource;  
        }  
      
        @Override  
        public void run() {  
            for (int i = 0; i < 10; i++) {  
                try {  
                    Thread.sleep((long) (Math.random() * 1000));  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                resource.increace();  
            }  
        }  
    }  
    /** 
     * 消費者線程,負責消費公共資源 
     */  
    public class ConsumerThread implements Runnable {  
        private PublicResource resource;  
      
        public ConsumerThread(PublicResource resource) {  
            this.resource = resource;  
        }  
      
        @Override  
        public void run() {  
            for (int i = 0; i < 10; i++) {  
                try {  
                    Thread.sleep((long) (Math.random() * 1000));  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                resource.decreace();  
            }  
        }  
    }  

三,模擬多個生產者和消費者操作公共資源的情形,結果須保證是在允許的範圍內。
public class ProducerConsumerTest {  
    public static void main(String[] args) {  
        PublicResource resource = new PublicResource();  
        new Thread(new ProducerThread(resource)).start();  
        new Thread(new ConsumerThread(resource)).start();  
        new Thread(new ProducerThread(resource)).start();  
        new Thread(new ConsumerThread(resource)).start();  
        new Thread(new ProducerThread(resource)).start();  
        new Thread(new ConsumerThread(resource)).start();  
    }  
}
參考鏈接:http://blog.csdn.net/u010339647/article/details/52013123

25. ThreadLocal的設計理念與作用

ThreadLocal類的大致結構和進行ThreadLocalMap的操作.我們可以從中得出以下的結論:1. ThreadLocalMap變量屬於線程(Thread)的內部屬性,不同的線程(Thread)擁有完全不同的ThreadLocalMap變量.2. 線程(Thread)中的ThreadLocalMap變量的值是在ThreadLocal對象進行set或者get操作時創建的.3. 在創建ThreadLocalMap之前,會首先檢查當前線程(Thread)中的ThreadLocalMap變量是否已經存在,如果不存在則創建一個;如果已經存在,則使用當前線程(Thread)已創建的ThreadLocalMap.4. 使用當前線程(Thread)的ThreadLocalMap的關鍵在於使用當前的ThreadLocal的實例作爲key進行存儲ThreadLocal模式,至少從兩個方面完成了數據訪問隔離,有了橫向和縱向的兩種不同的隔離方式,ThreadLocal模式就能真正地做到線程安全:縱向隔離 —— 線程(Thread)與線程(Thread)之間的數據訪問隔離.這一點由線程(Thread)的數據結構保證.因爲每個線程(Thread)在進行對象訪問時,訪問的都是各自線程自己的ThreadLocalMap.橫向隔離 —— 同一個線程中,不同的ThreadLocal實例操作的對象之間的相互隔離.這一點由ThreadLocalMap在存儲時,採用當前ThreadLocal的實例作爲key來保證.

話不多說,給大家推薦一篇原創博文,我就是在這篇博客http://blog.csdn.net/hua286306956/article/details/8660268裏 學習的

26. ThreadPool用法與優勢。

先定義一個線程池ThreadPoolExecutor,使用的時候用executor來調用runnable

優勢:合理利用線程池能夠帶來三個好處。第一:降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。


推薦鏈接:http://blog.csdn.net/scboyhj__/article/details/48805881

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

ArrayBlockingQueue

一個建立在數組之上被BlockingQueue綁定的阻塞隊列。這個隊列元素順序是先進先出。隊列的頭部是在隊列中待的時間最長的元素。隊列的尾部是再隊列中待的時間最短的元素。新的元素會被插入到隊列尾部,並且隊列從隊列頭部獲取元素。

    這是一個典型的綁定緩衝,在這個緩衝區中,有一個固定大小的數組持有生產者插入的數據,並且消費者會提取這些數據。一旦這個類被創建,那麼這個數組的容量將不能再被改變。嘗試使用put操作給一個滿隊列插入元素將導致這個操作被阻塞;嘗試從空隊列中取元素也會被阻塞。

    這個類推薦了一個可選的公平策略來排序等待的生產者和消費者線程。默認的,這個順序是不確定的。但是隊列會使用公平的設置true來使線程按照先進先出順序訪問。通常公平性會減少吞吐量但是卻減少了可變性以及避免了線程飢餓。

參考博文:http://blog.csdn.net/startupmount/article/details/37413275?utm_source=tuicool&utm_medium=referral

concurrent包是jdk1.5引入的重要的包,主要代碼由大牛Doug Lea完成,其實是在jdk1.4時代,由於java語言內置對多線程編程的支持比較基礎和有限,所以他寫了這個,因爲實在太過於優秀,所以被加入到jdk之中; 

通常所說的concurrent包基本有3個package組成 
java.util.concurrent:提供大部分關於併發的接口和類,如BlockingQueue,Callable,ConcurrentHashMap,ExecutorService, Semaphore等 
java.util.concurrent.atomic:提供所有原子操作的類, 如AtomicInteger, AtomicLong等; 
java.util.concurrent.locks:提供鎖相關的類, 如Lock, ReentrantLock, ReadWriteLock, Condition等;


ountDownLatch, 可以用來在一個線程中等待多個線程完成任務的類; 
通常的使用場景是,某個主線程接到一個任務,起了n個子線程去完成,但是主線程需要等待這n個子線程都完成任務了以後纔開始執行某個操作; 

掩飾代碼:

@Test  
public void demoCountDown()  
{  
    int count = 10;  
  
    final CountDownLatch l = new CountDownLatch(count);  
    for(int i = 0; i < count; ++i)  
    {  
        final int index = i;  
        new Thread(new Runnable() {  
  
            @Override  
            public void run() {  
  
                try {  
                    Thread.currentThread().sleep(20 * 1000);  
                } catch (InterruptedException e) {  
  
                    e.printStackTrace();  
                }  
  
                System.out.println("thread " + index + " has finished...");  
  
                l.countDown();  
  
            }  
        }).start();  
    }  
  
    try {  
        l.await();  
    } catch (InterruptedException e) {  
  
        e.printStackTrace();  
    }  
  
    System.out.println("now all threads have finished");  
  
}

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

① 這兩個方法來自不同的類分別是,sleep來自Thread類,和wait來自Object類。

sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程裏調用b的sleep方法,實際上還是a去睡覺,要讓b線程睡覺要在b的代碼中調用sleep。

② 鎖: 最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。

sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其他線程可以佔用CPU。一般wait不會加時間限制,因爲如果wait線程的運行資源不夠,再出來也沒用,要等待其他線程調用notify/notifyAll喚醒等待池中的所有線程,纔會進入就緒隊列等待OS分配系統資源。sleep(milliseconds)可以用時間指定使它自動喚醒過來,如果時間不到只能調用interrupt()強行打斷。

Thread.sleep(0)的作用是“觸發操作系統立刻重新進行一次CPU競爭”。

③ 使用範圍:wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep可以在任何地方使用。

   synchronized(x){ 
      x.notify() 
     //或者wait() 
   }

29. foreach與正常for循環效率對比

不是絕對的,在選擇for, foreach的時候,應該考慮以下幾點:

1. 如果只是讀數據,優先選擇foreach,因爲效率高,而且代碼簡單,方便;

2. 如果要寫數據,就只能選擇for了

30. Java IO與NIO

區別對比

IO                NIO
面向流            面向緩衝
阻塞IO            非阻塞IO
無                選擇器
1、面向流與面向緩衝

Java NIO和IO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。 Java IO面向流意味着每次從流中讀一個或多個字節,直至讀取所有字節,它們沒有被緩存在任何地方。此外,它不能前後移動流中的數據。如果需要前後移動從流中讀取的數據,需要先將它緩存到一個緩衝區。 Java NIO的緩衝導向方法略有不同。數據讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有您需要處理的數據。而且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裏尚未處理的數據。

2、阻塞與非阻塞IO

Java IO的各種流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再幹任何事情了。 Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閒時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。

3、選擇器(Selector)

ava NIO的選擇器允許一個單獨的線程來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的線程來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。

31. 反射的作用與原理。

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

推薦鏈接:Class對象和java反射機制

java反射

32. 泛型常用特點,List<String>能否轉爲List<Object>。

1、類型安全。類型錯誤現在在編譯期間就被捕獲到了,而不是在運行時當作java.lang.ClassCastException展示出來,將類型檢查從運行時挪到編譯時有助於開發者更容易找到錯誤,並提高程序的可靠性

2、消除了代碼中許多的強制類型轉換,增強了代碼的可讀性

3、爲較大的優化帶來了可能

List<String>向上轉換至List<Object>會丟失String類的身份(String類型的特有接口),這種轉換是不完美的。
當需要由List向下轉型時,你的程序必須明確的知道將對象轉換成何種具體類型,不然這將是不不‘安全的操作!

33. 解析XML的幾種方式的原理與特點:DOM、SAX、PULL
  • SAX是基於事件流的解析
    當解析器發現元素開始、元素結束、文本、文檔的開始或結束等時,發送事件,程序員編寫響應這些事件的代碼,保存數據
  • DOM是基於XML文檔樹結構的解析
    解析器讀入整個文檔,然後構建一個駐留內存的樹結構,然後代碼就可以使用 DOM 接口來操作這個樹結構

Sax定義

         SAX是一個解析速度快並且佔用內存少的xml解析器,非常適合用於android等移動設備

         SAX全稱是Simple API for Xml,既是指一種接口,也是一個軟件包

         作爲接口,sax是事件驅動型xml解析的一個標準接口

Sax工作原理

         Sax的工作原理簡單的說,就是對文檔進行順序掃描,掃描到文檔(document)開始與結束,掃描到元素(element)開始、結束等地方時調用事件處理

         處理函數做相應動作,然後繼續掃描,直到文檔結束。

Sax特點

        1. 解析效率高,佔用內存少

        2.可以隨時停止解析

        3.不能載入整個文檔到內存

        4.不能寫入xml

        5.SAX解析xml文件採用的是事件驅動

        ---sax並不需要解析完 整個文檔,在按內容順序解析文檔的過程中,sax會判斷當前讀到的字符是否合法xml語法中的某部分,如果符合就會觸發事件

DOM工作原理

dom全稱Document Object Model ,爲xml文檔的已解析版本定義了一組接口。解析器讀入整個文檔,然後構建一個主流內存的樹結構,

         然後代碼就可以使用dom接口來操作這個樹結構

DOM的特點

         >優點

                  1.整個文檔樹在內存中,便於操作;支持刪除、修改、重新排列等多種功能

                  2.通過樹形結構存取xml文檔

                  3.可以在樹的某個節點上向前或向後移動

           >缺點

                  1.將整個文檔調入內存(包括無用的節點),浪費時間和空間

            >適用場合

                  一旦解析了文檔還需多次訪問這些數據;硬件資源充足(內存,cpu)

pull解析器簡介

        1.pull解析器是android內置的解析器,解析原理與sax類似

        2.pull它提供了類似的事件。

              如:開始元素和結束元素事件,使用parse.next()可以進入下一個元素並觸發相應的事件,事件將作爲數值代碼被髮送

                      因此可以使用一個switch對感興趣的事件進行處理。當元素開始解析時,調用parser.nextText()方法獲取下一個Text類型節點的值

pull與sax的不同之處

          1.pull讀取xml文件後觸發相應的事件調用方法返回的是數字。

          2.pull可以在程序中控制,想解析到哪裏就可以停止到哪裏

          3.Android中更推薦使用pull解析

參考鏈接:http://blog.csdn.net/kukulongzai_123/article/details/7058008
34. Java與C++對比
  1. Java沒有顯式指針,而在C++中卻可以用。
  2. Java是主動多態的,不用關心具有繼承關係的多個類之間的同名成員函數會調用哪個,Java會主動地從祖父類、祖祖父類……,追溯至最高一級父類,然後從上至下開始尋找並調用;C++卻不會主動使用多態,要使用多態,就要用虛函數。
  3. Java是隱式繼承的;C++是被動多態的,C++把話說明白了,你繼承誰就繼承誰,繼承多個都可以,你什麼都不說那麼就不繼承。
  4. Java有接口,C++中卻沒有。C++中是定義了一個抽象類,把成員函數設爲常量,並改成純虛函數,在C++中這樣的抽象類就是接口。
  5. Java是單根繼承的,但是允許一個類實現多個接口;C++雖然支持多繼承,儘管很少有人去用它。
  6. Java中所有的函數都與類相關,沒有全局變量和非成員函數,而C++卻支持這些。
  7. C++中使用的動態內存怎麼用就怎麼還,Java中由於包含一個垃圾收集系統。
  8. Java有很緊湊的異常處理機制,而C++稍微顯得草率了一些。但是,這不代表C++異常處理機制不強大,因爲Java只能拋出Throwable之類的異常,而C++卻什麼都可以。
  9. Java標準庫是Java龐大的體現,涵蓋了國際化、網絡化、數學、聲音、Web應用和服務以及數據庫等。
35. Java1.7與1.8新特性。
 

JDK 1.7 新特性

1,switch中可以使用字串了

2,"<>"這個玩意兒的運用List<String> tempList = new ArrayList<>(); 即泛型實例化類型自動推斷

3. 自定義自動關閉類

4. 新增一些取環境信息的工具方法

5. Boolean類型反轉,空指針安全,參與位運算

6. 兩個char間的equals

7,安全的加減乘除

8、對Java集合(Collections)的增強支持

9、數值可加下劃線

10、支持二進制文字

11、簡化了可變參數方法的調用

12、在try catch異常撲捉中,一個catch可以寫多個異常類型,用"|"隔開,

13、jdk7之前,你必須用try{}finally{}在try內使用資源,在finally中關閉資源,不管try中的代碼是否正常退出或者異常退出。jdk7之後,你可以不必要寫finally語句來關閉資源,只要你在try()的括號內部定義要使用的資源

JDK 1.8 新特性

一、接口的默認方法

二、Lambda 表達式

三、函數式接口

四、方法與構造函數引用

五、Lambda 作用域

六、訪問局部變量

八、訪問接口的默認方法

九、Date API

十、Annotation 註解

強烈推薦參考鏈接:JDK各個版本的新特性jdk1.5-jdk8

36. 設計模式:單例、工廠、適配器、責任鏈、觀察者等等。

Java開發中的23種設計模式詳解(轉)

37. JNI的使用

JNI是Java Native Interface的縮寫,它提供了若干的API實現了Java和其他語言的通信(主要是C&C++)。從Java1.1開始,JNI標準成爲java平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI一開始是爲了本地已編譯語言,尤其是C和C++而設計的,但是它並不妨礙你使用其他編程語言,只要調用約定受支持就可以了。使用java與本地已編譯的代碼交互,通常會喪失平臺可移植性。但是,有些情況下這樣做是可以接受的,甚至是必須的。例如,使用一些舊的庫,與硬件、操作系統進行交互,或者爲了提高程序的性能。JNI標準至少要保證本地代碼能工作在任何Java 虛擬機環境。

 推薦鏈接:JNI的簡單使用


j2se的部分 可算整理完了,希望各位讀者能夠喜歡,不足的地方希望各位大神多多批評指正,過幾天給大家整理JVM 的部分

發佈了23 篇原創文章 · 獲贊 17 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章