1. Java 基礎
JVM, JRE, JDK的關(guān)系是什么
- JVM是虛擬機, 負責運行Java程序
- JRE是Java運行環(huán)境, 包括Java虛擬機, Java類庫
- JDK是Java Development Kit 包括JRE和編譯器和其他工具, 比如Java Doc
Switch(expr) 中的expr可以用什么類型
- 可以是 byte, short, char, int, string, enum
訪問修飾符public, private, protected和default的區(qū)別
- 訪問修飾符可以修飾方法, 成員變量. 默認是default
- public 是對所有類可見
- protected是只對一個包內(nèi)的本類和子類可見
- private是只對本類可見
- default是對同一包的所有類可見
final, finally, finalize的區(qū)別
- final
- 修飾變量表示變量值不能被改變
- 修飾方法表示方法不能被重寫但是可以被繼承
- 修飾類表示類不能被繼承
- finally
- fianlly是異常處理中用的關(guān)鍵字
- 表示不管是否發(fā)生異常, finally里的語句一定會被執(zhí)行
- 即使在finally之前有return 比如在try中或者catch中, finally里的代碼還是會被執(zhí)行
- 一般會把資源釋放的代碼放在finally里, 比如關(guān)閉文件等
- finalize: 是Object的自帶方法, 和垃圾回收有關(guān)
講一下static關(guān)鍵字
- static關(guān)鍵字可以修飾 變量, 方法, 常量, 類
靜態(tài)成員變量 和 靜態(tài)成員常量
- 一個類的所有實例共享靜態(tài)成員變量, 直接用類名調(diào)用
- 即使沒有對象實例, 靜態(tài)成員也存在
//Example: 給每個雇員產(chǎn)生unique ID
public void setId() {
id = nextId;
nextId++;
}
harry.id = Employee.nextId;
Employee.nextId++;
靜態(tài)成員方法
- 靜態(tài)方法跟類的對象沒有關(guān)系, 不管有沒有對象實例, 靜態(tài)方法都存在. 也是直接用類名調(diào)用
- 靜態(tài)方法不能使用非靜態(tài)成員變量, 但是可以使用靜態(tài)成員變量
什么時候使用靜態(tài)方法:
- 當一個方法不需要使用對象的狀態(tài), 比如成員變量和成員方法, 也就是所需的參數(shù)都是外部直接傳入的, 比如:
Math.pow
- 當一個方法使用的都是靜態(tài)成員變量時
靜態(tài)類
- 只有內(nèi)部類可以是靜態(tài)的, 也只有內(nèi)部類可以用static關(guān)鍵字修飾
- 靜態(tài)內(nèi)部類是不需要依賴于外部類的,這點和類的靜態(tài)成員屬性有點類似
- 它不能使用外部類的非static成員變量或者方法
- 因為在沒有外部類的對象的情況下,可以創(chuàng)建靜態(tài)內(nèi)部類的對象,如果允許訪問外部類的非static成員就會產(chǎn)生矛盾,因為外部類的非static成員必須依附于具體的對象
描述一下 Java OOP
封裝
- 封裝是將一個概念或者物體封裝成一個類. 在類中通過成員變量和成員方法描述這個概念或者物體
比如一個Car類用來描述車這個物體, 那么成員變量可能包括車輪, 排量等描述一個車的物理參數(shù). 成員變量可以包括drive, stop等用來描述車具體的行為.
繼承
- 繼承的作用是提高代碼的復用性, 去除冗余代碼, 避免復制代碼, 提升代碼的拓展性. 在設計代碼時, 我們可以將多個類中重復出現(xiàn)的成員變量和方法封裝成父類, 這樣子類可以通過繼承的方式具有父類所有的特性, 并且可以增添只屬于子類的方法和變量. 比如之前說的car這個類, 我們可以將所有車共有的基本參數(shù)比如車門, 方向盤以及共有的行為比如drive, stop設計成父類. 然后不同牌子的車可以繼承car這個父類, 并加入不同品牌特有的feature等.
多態(tài)文章來源:http://www.zghlxwxcb.cn/news/detail-427488.html
- 個人覺得Java中多態(tài)是基于繼承的概念. 然后Java中多態(tài)是通過兩個方面體現(xiàn)的:
- override和overload: override就是子類擁有父類的方法, 并且可以對父類的方法根據(jù)子類的需要進行重寫. override必須保持方法的名字, 參數(shù)列表和返回值不變, 具體實現(xiàn)可以變. overload是同一個類中可以有方法名一樣的方法, 方法的參數(shù)和返回值可以不變. Java通過方法的參數(shù)列表判斷調(diào)用哪個方法. 所以每個重載的方法都必須有一個獨一無二的參數(shù)類型列表. 最常見的是構(gòu)造方法overload.
- 向上轉(zhuǎn)型和向下轉(zhuǎn)型: 在Java中, 聲明一個變量的時候, 等號左邊的是變量的聲明類型, new 后面的是變量的實際類型. 聲明類型是實際類型的父類, 所以在Java中一個變量既可以是子類的類型, 也可以是父類的類型. 最常見的是在寫方法時, 參數(shù)列表可以使用父類的類型, 這樣可以對所有子類使用. 在參數(shù)傳遞時編譯器會自動進行向上轉(zhuǎn)型. 然后在方法的實現(xiàn)中可以通過instantof關(guān)鍵字判斷變量的實際類型, 并使用強轉(zhuǎn)進行向下轉(zhuǎn)型, 然后進行不同的操作. 這樣可以節(jié)省代碼量, 去除冗余代碼.
Overload和Override的區(qū)別是什么
- override和overload: override就是子類擁有父類的方法, 并且可以對父類的方法根據(jù)子類的需要進行重寫. override必須保持方法的名字, 參數(shù)列表和返回值不變, 具體實現(xiàn)可以變.
- overload是同一個類中可以有方法名一樣的方法, 方法的參數(shù)和返回值可以不變. Java通過方法的參數(shù)列表判斷調(diào)用哪個方法. 所以每個重載的方法都必須有一個獨一無二的參數(shù)類型列表. 最常見的是構(gòu)造方法overload.
構(gòu)造方法能不能被重寫
- 構(gòu)造方法不能被繼承, 所以不能被重寫
說一下抽象類
- 用abstract修飾的類為抽象類, 一般抽象類都包括至少一個或多個抽象方法. 也存在沒有抽象方法的抽象類, 用abstract修飾是為了表明這是子類的基類.
- 其中抽象方法只有方法聲明沒有具體實現(xiàn),具體是現(xiàn)實是由子類提供. 抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現(xiàn)該方法. 抽象類不能被實例化,即不能通過new生成一個抽象類的對象).
- 抽象類不能被實例化,即不能通過new生成一個抽象類的對象, 作用是為某類定義通用方法. (比如一個算幾何圖形面積和周長的類可以定義兩個抽象方法計算面積和周長, 而具體實現(xiàn)通過不同圖形子類定義)
- 構(gòu)造方法必須聲明為Protected(因為要供子類使用)
- 子類(如果不是抽象類)則必須覆寫抽象類之中的全部抽象方法(如果子類沒有實現(xiàn)父類的抽象方法,則必須將子類也定義為為abstract類)
說一下接口的作用
- 因為java中沒有多繼承(一個子類只能有一個父類),所以提出了接口的概念
- Java中接口可以多繼承, 也就是一個接口同時繼承多個接口
- 接口可以使程序的耦合度降低, 發(fā)揮多態(tài)的優(yōu)點. 比如我們現(xiàn)在有一個叫Car的基類, 底下有分為電車和油車抽象類, 然后各自有不同品牌的車對應具體的實現(xiàn)類. 如果我們想給車加入新的功能, 比如智能助手功能, 只需要給car這個類加入AI 這個接口就可以讓所有品牌的車都擁有統(tǒng)一的AI功能. 這樣可以在不改動原有類的基礎關(guān)系的情況下, 加入新功能, 并降低耦合度.
- 接口中的所有成員變量都為
public static final
抽象類可以用final修飾嗎, 可以被實例化嗎
- 不能, 因為用final修飾的類不能被繼承,而抽象類需要子類去重寫抽象類的方法
- 抽象類也不能被實例化.
說一說String類
- String類是字符串對象,程序中定義""都是字符串對象,這個對象的使用頻率最高.
- String類不是Java的基本類型, 是Object類. String的聲明方法有兩種一種是等于號直接賦值, 一種是用new聲明. 然后用等號賦值是儲存在字符串常量池中, 用new是將值儲存在堆中
String類有一個突出特性就是不可變性, 具體體現(xiàn)在: 只要對string做出修改, 就會開辟新的內(nèi)存空間文章來源地址http://www.zghlxwxcb.cn/news/detail-427488.html
- 1.當對字符串重新賦值時,會重新開辟新的內(nèi)存空間儲存新的字符串
//常量池中會同時儲存 "hello world" 和 "hello" , 而不是 "hello world" 被覆蓋掉
String s = "hello world"
s = "hello"
- 2.當對現(xiàn)有的字符串進行連接操作時,會重新開辟新的內(nèi)存空間儲存拼接后的字符串
- 3.當調(diào)用String的
replace().
或者substring()
等方法修改指定字符或字符串時,也會重新開辟新的內(nèi)存空間儲存修改后的字符串
如何對比兩個String
- 使用 == 對比兩字符串時實際對比的是地址, 而不是實際內(nèi)容
- 所以一律使用
s1.equals(s2)
或者s1.compareTo(s2)
對比string
public static void main(String args[]) {
String s = "hello";
String ss = "hello";
String sss = new String("hello");
System.out.println(s == ss);
System.out.println(s == sss);
System.out.println(ss == sss);
}
output:
true // 因為 直接賦值創(chuàng)建String時, JVM會首先在常量池中尋找是否已經(jīng)有同樣的字符串. 所以s和ss指向同樣的地址
false //使用構(gòu)造器創(chuàng)建String時, 地址會指向堆內(nèi)存, 然后堆內(nèi)存中的地址指向常量池, 所以不一樣
false //同上
— String為什么要設計成不可變的
- 可以使用字符常量池
- 線程安全
String, StringBuilder和StringBuffer的區(qū)別
- String是不可變對象, 也就是對String的任何操作都會生成新的對象
- StringBuilder和StringBuffer是可變的字符串對象, 但是StringBuilder是線程不安全的, StringBuffer是線程安全的, StringBuffer對方法加入了同步鎖synchronized
- 因為StringBuilder是線程不安全的, 所以有速度優(yōu)勢
什么是字符串常量池
- 為了減少內(nèi)存開銷, 字符串常量池可以避免重復創(chuàng)建字符串, 當需要一個字符串時, 首先在字符串常量池中尋找字符串是否已經(jīng)存在
Java中的基本類型包括哪些
- Java中的基本類型包括byte, short, int, long,char, float, double, boolean等
- 其中String不是基本類型
比較包裝類怎么比較
- 應該用equals, 不能用等于號
- 在緩存范圍內(nèi)時可以用等于號比較, 比如Integer的 -128 到 127
- 但是為了保險起見, 還是統(tǒng)一用equals
//下面代碼會打印 not equal
Integer a = 300;
Integer b = 300;
if (a == b) {
System.out.println("equal");
}
else {
System.out.println("not equal");
}
Integer和Int的區(qū)別
- 每一個基本類型都對應有一個包裝類, Integer就是包裝類, int就是基本類型. 包裝類是引用類型, 屬于Object類, 所以可以使用集合容器, 并且值可以等于null.
包裝類是什么? 基本類型和包裝類型有什么區(qū)別
- 每一個基本類型都對應有一個包裝類, 包裝類是引用類型, 屬于Object類, 所以可以使用集合容器, 并且值可以等于null
- valueOf 方法可以將基本類型轉(zhuǎn)為包裝類. doubleValue, intValue等方法可以將包裝類轉(zhuǎn)為基本類型.
- 也可以使用=號直接轉(zhuǎn)換, Java自動調(diào)用上面兩個方法, 被稱為自動裝箱和自動封箱
- 包裝類還有一個特點是有緩存機制, 比如當?shù)谝淮握{(diào)用valueOf方法時, 會自動創(chuàng)建一個Integer數(shù)組儲存-128到127的Integer對象, 這樣下次遇到在緩存范圍內(nèi)的對象時, 就直接返回已經(jīng)緩存的對象.
//關(guān)于緩存
public class ValuePassing {
public static void fun1(Integer i, Integer j) {
System.out.println("在fun1中賦值前i的地址是: " + System.identityHashCode(i));
System.out.println("在fun1中賦值后j的地址是: " + System.identityHashCode(j));
//對i和j同時賦予一樣的值后(在-128-127之間),地址一樣
i = 10;
j = 10;
System.out.println("-----------------------------------------------");
System.out.println("在fun1中賦值后i的地址是: " + System.identityHashCode(i));
System.out.println("在fun1中賦值后j的地址是: " + System.identityHashCode(j));
}
public static void main(String[] args) {
Integer i = 5;
Integer j = 20;
System.out.println("在main中i的地址是: " + System.identityHashCode(i));
System.out.println("在main中j的地址是: " + System.identityHashCode(j));
System.out.println("-----------------------------------------------");
fun1(i, j);
}
}
output:
在main中i的地址是: 1072591677
在main中j的地址是: 1523554304
-----------------------------------------------
在fun1中賦值前i的地址是: 1072591677
在fun1中賦值后j的地址是: 1523554304
-----------------------------------------------
在fun1中賦值后i的地址是: 1175962212
在fun1中賦值后j的地址是: 1175962212
什么是反射
- Java的每個class都會在虛擬機中生成一個.class文件. 在程序運行時, 可以通過.class文件得到一個類的所有信息, 包括屬性, 方法等
- 反射可以在動態(tài)的創(chuàng)建對象實例, 提高代碼靈活性
- Java中的反射通過Class, Field, Method, Constructor類獲得
為什么需要泛型, 介紹下泛型
- 泛型可以解決generic programming的問題, 也就是寫的代碼可以適配各種類. 比如集合框架中的容器
- 在沒有泛型以前, Java使用利用Object類解決泛型問題. 比如聲明一個List為Object類型.
- 但是這樣有兩個問題, 當獲取List里面的值時需要轉(zhuǎn)型
- 沒有Error checking, 這個list里可以同時放進所有類型的數(shù)據(jù), 因為所有類的父類都是Object類.
- 泛型提供了type parameter, 這樣就可以給泛型指定一個類型, 代碼更易讀, 不用轉(zhuǎn)型并且有error checking
Java語言是如何處理泛型的 (介紹下類型擦除)
- Java 中的泛型只有在編譯階段存在,在代碼運行的時候是沒有泛型的,這也被稱為泛型擦除
- 虛擬機會對泛型代碼進行泛型擦除, 也就是將所有的類型 T 替換成raw type, raw type就是bound list中的第一個類型, 或者是Object類型 (如果沒有bounds list)
什么是泛型中的限定通配符
- 限定通配符對類型進行了限制
- <? Extend T> 限制了泛型中的類只能是T的子類
- < ? super T> 限制了泛型中的類只能是T的父類
講一講Error和Exception
- Error和Exception都繼承自Throwable類
- Exception
- Checked Exception: 必須使用try catch處理的exception, 包括. SQLException
- Unchecked Exception: 不用被強制的顯式的拋出或者捕獲. 包括Arithmetic, NullPointer, IndexOutOfBounds, Illegalargument等
- Error: 屬于編譯器無法檢測到的錯誤, 比如Virtual Machine Error, Linkage Error
throw和throws的區(qū)別是什么
- throw用在方法內(nèi)部, 用于拋出一種異常
- throws寫在方法聲明的后面, 用來標識可能拋出的方法列表. 調(diào)用該方法的方法必須包括try catch處理對應的異常, 否則需要繼續(xù)使用throws拋出對應的異常.
Java常見異常有哪些
- StackoverflowError
- ClassNotFoundException
- ArthimeticException
- IndexOutOfBoundsException
- NullPointerException
try-catch-finally 中, 如果catch中有return, finally還會執(zhí)行嗎
- 會執(zhí)行, 在return之前執(zhí)行
Java變量命名規(guī)范
- 必須以字母、下劃線、或者美元符$開頭
- 類名第一個字母大寫, 遵循駝峰原則
- 變量名, 方法名第一個字母小寫, 遵循駝峰原則
i++ 和 ++i的區(qū)別
- n = i++ 是先把i的值賦給左邊再對i進行遞增.
- n= ++i 是先對i進行遞增, 再把值賦給左邊.
Object類有哪些方法
- toString(), notifyAll(), wait(), hashCode(), finalize(), clone(), equals(), getClass()
什么是hashCode以及為什么需要hashCode
- hashcode方法是Object類的方法, 也就是說所有類都有hashcode方法
- hashcode方法可以產(chǎn)生一個hash值. Java容器中的hashSet或者hashMap需要使用hashCode判斷實例是否存在或者判斷實例的位置. 具體的算法需要對hashcode產(chǎn)生的值進行處理(加入高位擾動等)
- 比如HashSet()的put操作, 首先計算對象的hashCode值, 判斷hashtable中對應的位置是否已經(jīng)有對象, 如果有則調(diào)用equals判斷兩個對象是否相等, 如果相等則拒絕加入, 如果不相等則通過probing放入到其他位置
hashCode和equals的關(guān)系 / 為什么重寫equals一定要重寫hashCode方法
- 如果兩個對象hashCode不一樣, 則一定不equals
- 如果兩個對象hashCode一樣, 有可能不equals
- 如果兩個對象不equals但是hashCode可能一樣
- 也就是重寫equals必須重寫hashCode, 否則會出現(xiàn)兩個對象equals但是hashCode不一樣的情況, 導致兩個equals的對象被同時加入hash
如何判斷double的0值
- 因為double 在運算中,由于截尾的原因,總是有誤差的。而此時是否為0,要看你的這個運算的精度要求。
- 比如運算后,f = 0.001,需要和規(guī)定精度比較,比如你的精度要求是0.000001,則認為 f 值不為0,若精度為0.01,則認為 f 就等于0
- 可以這樣 if(abs(f) < 精度0.000001) 執(zhí)行 f 等于0時的操作
— double和float是如何在內(nèi)存中儲存的
2. Java 集合框架
說一說Java集合框架常用的類
- 集合框架分為兩個部分, 分別為Collection和Map
- Collection里常用的類有, LinkedList, ArrayList, HashSet, TreeSet, ArrayQueue
- Map里常用的類有HashMap, TreeMap
說一下HashMap的底層原理實現(xiàn)
說一下StringBuilder, StringBuffer的區(qū)別
- StringBuilder 類在 Java 5 中被提出,它和 StringBuffer 之間的最大不同在于 StringBuilder 的方法不是線程安全的(不能同步訪問)
- 由于 StringBuilder 相較于 StringBuffer 有速度優(yōu)勢,所以多數(shù)情況下建議使用 StringBuilder 類。
Comparator和Comparable的區(qū)別
線程安全的集合有哪些
- HashTable, ConcurrentHashMap, Vector, Stack
- 優(yōu)先使用ConcurrentHashMap
ArrayList和LinkedList的異同點
Collection中容器的比較要怎么做
HashMap和HashSet的區(qū)別是什么
HashMap如果計算Index值
HashMap是如何擴容的
HashMap的put流程是什么
HashMap為什么線程不安全
說一下TreeMap有什么特點, 是如何實現(xiàn)的
到了這里,關(guān)于八股文 -- Java基礎和集合框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!