1 你是怎樣理解面向?qū)ο蟮?/strong>
面向?qū)ο笫抢镁幊陶Z言對現(xiàn)實事物進行抽象。面向?qū)ο缶哂幸韵滤拇筇卣鳎?/p>
(1)繼承:繼承是從已有類得到繼承信息創(chuàng)建新類的過程
(2)封裝:通常認為封裝是把數(shù)據(jù)和操作數(shù)據(jù)的方法綁定起來,對數(shù)據(jù)的訪問只能通過已定義的接口。
(3)多態(tài)性:多態(tài)性是指允許不同子類型的對象對同一消息作出不同的響應(yīng)。
(4)抽象:抽象是將一類對象的共同特征總結(jié)出來構(gòu)造類的過程,包括數(shù)據(jù)抽象和行為抽象兩方面。
2 int和Integer有什么區(qū)別,以及以下程序結(jié)果
(1)Integer是int的包裝類,int則是java的一種基本數(shù)據(jù)類型
(2)Integer變量必須實例化后才能使用,而int變量不需要
(3)Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲數(shù)據(jù)值
(4)Integer的默認值是null,int的默認值是0
package com.atguigu.interview.chapter03;
public class Test01 {
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b); //true
System.out.println(c == d); //false
}
}
3 ==和Equals區(qū)別
(1) ==
如果比較的是基本數(shù)據(jù)類型,那么比較的是變量的值
如果比較的是引用數(shù)據(jù)類型,那么比較的是地址值(兩個對象是否指向同一塊內(nèi)存)
(2)equals
如果沒重寫equals方法比較的是兩個對象的地址值
如果重寫了equals方法后我們往往比較的是對象中的屬性的內(nèi)容
equals()方法最初在Object類中定義的,默認的實現(xiàn)就是使用==
4 談?wù)勀銓Ψ瓷涞睦斫?/strong>
(1)反射機制:
所謂的反射機制就是java語言在運行時擁有一項直觀的能力。通過這種能力可以徹底地了解自身的情況為下一步的動作做準備。
Java的反射機制的實現(xiàn)要借助于4個類:Class,Constructor,F(xiàn)ield,Method;
其中Class代表的是類對 象,Constructor-類的構(gòu)造器對象,F(xiàn)ield-類的屬性對象,Method-類的方法對象。通過這四個對象我們可以粗略地看到一個類的各個組 成部分。
(2)Java反射的作用:
在Java運行時環(huán)境中,對于任意一個類,可以知道這個類有哪些屬性和方法。對于任意一個對象,可以調(diào)用它的任意一個方法。這種動態(tài)獲取類的信息以及動態(tài)調(diào)用對象的方法的功能來自于Java 語言的反射(Reflection)機制。
(3)Java 反射機制提供功能
在運行時判斷任意一個對象所屬的類。
在運行時構(gòu)造任意一個類的對象。
在運行時判斷任意一個類所具有的成員變量和方法。
在運行時調(diào)用任意一個對象的方法
5 ArrarList和linkedList區(qū)別
(1)ArrayList是實現(xiàn)了基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),linkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)。
(2)對于隨機訪問get和set,ArrayList絕對優(yōu)于linkedList,因為linkedList要移動指針。
(3)對于插入和刪除操作add和remove,linkedList比較占優(yōu)勢,因為ArrayList每插入或刪除一條數(shù)據(jù),都要移動插入點或刪除點及之后的所有數(shù)據(jù)。
6 HashMap底層源碼,數(shù)據(jù)結(jié)構(gòu)
HashMap的底層結(jié)構(gòu)在jdk1.7中由數(shù)組+鏈表實現(xiàn),在jdk1.8中由數(shù)組+鏈表+紅黑樹實現(xiàn),以數(shù)組+鏈表的結(jié)構(gòu)為例。
JDK1.8之前put方法:
JDK1.8之后put方法:
7 HashMap和Hashtable區(qū)別
(1)線程安全性不同
HashMap是線程不安全的,Hashtable是線程安全的,其中的方法是Synchronized的,在多線程并發(fā)的情況下,可以直接使用Hashtable,但是使用HashMap時必須自己增加同步處理。
(2)是否提供contains方法
HashMap只有containsValue和containsKey方法;Hashtable有contains、containsKey和containsValue三個方法,其中contains和containsValue方法功能相同。
(3)key和value是否允許null值
Hashtable中,key和value都不允許出現(xiàn)null值。HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應(yīng)的值為null。
(4)數(shù)組初始化和擴容機制
Hashtable在不指定容量的情況下的默認容量為11,而HashMap為16,Hashtable不要求底層數(shù)組的容量一定要為2的整數(shù)次冪,而HashMap則要求一定為2的整數(shù)次冪。
Hashtable擴容時,將容量變?yōu)樵瓉淼?倍加1,而HashMap擴容時,將容量變?yōu)樵瓉淼?倍。
3.8 TreeSet和HashSet區(qū)別
HashSet是采用hash表來實現(xiàn)的。其中的元素沒有按順序排列,add()、remove()以及contains()等方法都是復(fù)雜度為O(1)的方法。
TreeSet是采用樹結(jié)構(gòu)實現(xiàn)(紅黑樹算法)。元素是按順序進行排列,但是add()、remove()以及contains()等方法都是復(fù)雜度為O(log (n))的方法。它還提供了一些方法來處理排序的set,如first(), last(), headSet(), tailSet()等等。
9 StringBuffer和StringBuilder區(qū)別
(1)StringBuffer 與 StringBuilder 中的方法和功能完全是等價的,
(2)只是StringBuffer 中的方法大都采用了 synchronized 關(guān)鍵字進行修飾,因此是線程安全的,而 StringBuilder 沒有這個修飾,可以被認為是線程不安全的。
(3)在單線程程序下,StringBuilder效率更快,因為它不需要加鎖,不具備多線程安全而StringBuffer則每次都需要判斷鎖,效率相對更低
10 Final、Finally、Finalize
final:修飾符(關(guān)鍵字)有三種用法:修飾類、變量和方法。修飾類時,意味著它不能再派生出新的子類,即不能被繼承,因此它和abstract(abstract修飾的類通常都需要子類來繼承)在使用上可以理解為互斥的。修飾變量時,該變量使用中不被改變,必須在聲明時給定初值,在引用中只能讀取不可修改,即為常量。修飾方法時,也同樣只能使用,不能在子類中被重寫。
finally:通常放在try…catch的后面構(gòu)造最終執(zhí)行代碼塊,這就意味著程序無論正常執(zhí)行還是發(fā)生異常,這里的代碼只要JVM不關(guān)閉都能執(zhí)行,可以將釋放外部資源的代碼寫在finally塊中。
finalize:Object類中定義的方法,Java中允許使用finalize() 方法在垃圾收集器將對象從內(nèi)存中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在銷毀對象時調(diào)用的,通過重寫finalize() 方法可以整理系統(tǒng)資源或者執(zhí)行其他清理工作。
11 什么是 java 序列化,如何實現(xiàn) java 序列化?
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內(nèi)容進行流化??梢詫α骰蟮膶ο筮M行讀寫操作,也可將流化后的對象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決在對對象流進行讀寫操作時所引發(fā)的問題。
序 列 化 的 實 現(xiàn) : 將 需 要 被 序 列 化 的 類 實 現(xiàn) Serializable 接 口 , 該 接 口 沒 有 需 要 實 現(xiàn) 的 方 法 , implements Serializable 只是為了標注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構(gòu)造一個ObjectOutputStream(對象流)對象,接著,使用 ObjectOutputStream 對象的 writeObject(Object obj)方法就可以將參數(shù)為 obj 的對象寫出(即保存其狀態(tài)),要恢復(fù)的話則用輸入流。
12 Object中有哪些方法
(1)protected Object clone()—>創(chuàng)建并返回此對象的一個副本。
(2)boolean equals(Object obj)—>指示某個其他對象是否與此對象“相等”。
(3)protected void finalize()—>當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調(diào)用此方法。
(4)Class<? extends Object> getClass()—>返回一個對象的運行時類。
(5)int hashCode()—>返回該對象的哈希碼值。
(6)void notify()—>喚醒在此對象監(jiān)視器上等待的單個線程。
(7)void notifyAll()—>喚醒在此對象監(jiān)視器上等待的所有線程。
(8)String toString()—>返回該對象的字符串表示。
(9)void wait()—>導(dǎo)致當前的線程等待,直到其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)—>導(dǎo)致當前的線程等待,直到其他線程調(diào)用此對象的 notify() 方法或 notifyAll()方法,或者超過指定的時間量。
void wait(long timeout, int nanos)—>導(dǎo)致當前的線程等待,直到其他線程調(diào)用此對象的 notify()
13 線程有幾種狀態(tài),產(chǎn)生的條件是什么
14 產(chǎn)生死鎖的基本條件
產(chǎn)生死鎖的原因:
(1) 因為系統(tǒng)資源不足。
(2) 進程運行推進的順序不合適。
(3) 資源分配不當?shù)取?br>如果系統(tǒng)資源充足,進程的資源請求都能夠得到滿足,死鎖出現(xiàn)的可能性就很低,否則
就會因爭奪有限的資源而陷入死鎖。其次,進程運行推進順序與速度不同,也可能產(chǎn)生死鎖。
產(chǎn)生死鎖的四個必要條件:
(1) 互斥條件:一個資源每次只能被一個進程使用。
(2) 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:進程已獲得的資源,在未使用完之前,不能強行剝奪。
(4) 循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
這四個條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發(fā)生死鎖。
死鎖的解除與預(yù)防:
理解了死鎖的原因,尤其是產(chǎn)生死鎖的四個必要條件,就可以最大可能地避免、預(yù)防和
解除死鎖。所以,在系統(tǒng)設(shè)計、進程調(diào)度等方面注意如何不讓這四個必要條件成立,如何確
定資源的合理分配算法,避免進程永久占據(jù)系統(tǒng)資源。此外,也要防止進程在處于等待狀態(tài)
的情況下占用資源。因此,對資源的分配要給予合理的規(guī)劃。
15 什么是線程池,如何使用?
線程池就是事先將多個線程對象放到一個容器中,當使用的時候就不用 new 線程而是直接去池中拿線程即可,節(jié)省了開辟子線程的時間,提高的代碼執(zhí)行效率。
在 JDK 的
java.util.concurrent.Executors 中提供了生成多種線程池的靜態(tài)方法。
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(4);
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(4);
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
然后調(diào)用他們的 execute 方法即可。
優(yōu)點:
第一:降低資源消耗。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。
第二:提高響應(yīng)速度。當任務(wù)到達時,任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行。
第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。
16 Java自帶有哪幾種線程池?
一、ThreadPoolExecutor
ThreadPoolExecutor提供了四個構(gòu)造方法:
我們以最后一個構(gòu)造方法(參數(shù)最多的那個),對其參數(shù)進行解釋:
public ThreadPoolExecutor(int corePoolSize, // 1
int maximumPoolSize, // 2
long keepAliveTime, // 3
TimeUnit unit, // 4
BlockingQueue < Runnable > workQueue, // 5
ThreadFactory threadFactory, // 6
RejectedExecutionHandler handler) { // 7
if (corePoolSize < 0 || maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize || keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.tonanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
二、預(yù)定義線程池
JDK給我們預(yù)定義的幾種線程池
1、FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new linkedBlockingQueue<Runnable>());
}
- corePoolSize與maximumPoolSize相等,即其線程全為核心線程,是一個固定大小的線程池,是其優(yōu)勢;
- keepAliveTime = 0 該參數(shù)默認對核心線程無效,而FixedThreadPool全部為核心線程;
- workQueue 為linkedBlockingQueue(無界阻塞隊列),隊列最大值為Integer.MAX_VALUE。如果任務(wù)提交速度持續(xù)大于任務(wù)處理速度,會造成隊列大量阻塞。因為隊列很大,很有可能在拒絕策略前,內(nèi)存溢出。是其劣勢;
- FixedThreadPool的任務(wù)執(zhí)行是無序的;
適用場景:可用于Web服務(wù)瞬時削峰,但需注意長時間持續(xù)高峰情況造成的隊列阻塞。
2、CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即線程數(shù)量幾乎無限制;
- keepAliveTime = 60s,線程空閑60s后自動結(jié)束。
- workQueue 為 SynchronousQueue 同步隊列,這個隊列類似于一個接力棒,入隊出隊必須同時傳遞,因為CachedThreadPool線程創(chuàng)建無限制,不會有隊列等待,所以使用SynchronousQueue;
適用場景:快速處理大量耗時較短的任務(wù),如Netty的NIO接受請求時,可使用CachedThreadPool。
3、SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new linkedBlockingQueue<Runnable>()));
}
這里多了一層
FinalizableDelegatedExecutorService包裝,以下代碼解釋一下其作用:
public static void main(String[] args) {
ExecutorService fixedExecutorService = Executors.newFixedThreadPool(1);
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) fixedExecutorService;
System.out.println(threadPoolExecutor.getMaximumPoolSize());
threadPoolExecutor.setCorePoolSize(8);
ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();
// 運行時異常 java.lang.ClassCastException
//ThreadPoolExecutor threadPoolExecutor2 = (ThreadPoolExecutor) singleExecutorService;
}
對比可以看出,F(xiàn)ixedThreadPool可以向下轉(zhuǎn)型為ThreadPoolExecutor,并對其線程池進行配置,而SingleThreadExecutor被包裝后,無法成功向下轉(zhuǎn)型。因此,SingleThreadExecutor被定以后,無法修改,做到了真正的Single。
4、ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
newScheduledThreadPool調(diào)用的是ScheduledThreadPoolExecutor的構(gòu)造方法,而ScheduledThreadPoolExecutor繼承了ThreadPoolExecutor,構(gòu)造是還是調(diào)用了其父類的構(gòu)造方法。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
三、自定義線程池
以下是自定義線程池,使用了有界隊列,自定義ThreadFactory和拒絕策略的demo:
public class ThreadTest {
public static void main(String[] args) throws InterruptedException, IOException {
int corePoolSize = 2;
int maximumPoolSize = 4;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
ThreadFactory threadFactory = new NameTreadFactory();
RejectedExecutionHandler handler = new MyIgnorePolicy();
ThreadPoolExecutor executor
= new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue, threadFactory, handler);
executor.prestartAllCoreThreads(); // 預(yù)啟動所有核心線程
for (int i = 1; i <= 10; i++) {
MyTask task = new MyTask(String.valueOf(i));
executor.execute(task);
}
System.in.read(); //阻塞主線程
}
static class NameTreadFactory implements ThreadFactory {
private final AtomicInteger mThreadNum = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
System.out.println(t.getName() + " has been created");
return t;
}
}
public static class MyIgnorePolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
doLog(r, e);
}
private void doLog(Runnable r, ThreadPoolExecutor e) {
// 可做日志記錄等
System.err.println( r.toString() + " rejected");
// System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
}
}
static class MyTask implements Runnable {
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.toString() + " is running!");
Thread.sleep(3000); //讓任務(wù)執(zhí)行慢點
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getName() {
return name;
}
@Override
public String toString() {
return "MyTask [name=" + name + "]";
}
}
}
17 Java 中有幾種類型的流
18 字節(jié)流如何轉(zhuǎn)為字符流
字節(jié)輸入流轉(zhuǎn)字符輸入流通過 InputStreamReader 實現(xiàn),該類的構(gòu)造函數(shù)可以傳入 InputStream 對象。
字符輸出流轉(zhuǎn)字節(jié)輸出流通過OutputStreamWriter 實現(xiàn),該類的構(gòu)造函數(shù)可以傳入 OutputStream 對象。
3.19 請寫出你最常見的5個Exception
(1)
java.lang.NullPointerException 空指針異常;出現(xiàn)原因:調(diào)用了未經(jīng)初始化的對象或者是不存在的對象。
(2)
java.lang.ClassNotFoundException 指定的類找不到;出現(xiàn)原因:類的名稱和路徑加載錯誤;通常都是程序試圖通過字符串來加載某個類時可能引發(fā)異常。
(3)
java.lang.NumberFormatException 字符串轉(zhuǎn)換為數(shù)字異常;出現(xiàn)原因:字符型數(shù)據(jù)中包含非數(shù)字型字符。
(4)
java.lang.IndexOutOfBoundsException 數(shù)組角標越界異常,常見于操作數(shù)組對象時發(fā)生。
(5)
java.lang.IllegalArgumentException 方法傳遞參數(shù)錯誤。
(6)
java.lang.ClassCastException 數(shù)據(jù)類型轉(zhuǎn)換
標簽:java面試題
本文鏈接:
本文章“Java SE相關(guān)面試題匯總”已幫助 147 人
免責聲明:本信息由用戶發(fā)布,本站不承擔本信息引起的任何交易及知識產(chǎn)權(quán)侵權(quán)的法律責任!
本文由賦能網(wǎng) 整理發(fā)布。了解更多培訓機構(gòu)》培訓課程》學習資訊》課程優(yōu)惠》課程開班》學校地址等機構(gòu)信息,可以留下您的聯(lián)系方式,讓課程老師跟你詳細解答:
咨詢熱線:4008-569-579