文章目錄
- 一、==和equals區別?
- 二、hashcode方法作用?兩個對象的hashCode方法相同,則equals方法也一定為true嗎?
- 三、為什么重寫equals方法就一定要重寫hashCode方法?
- 四、Java中的參數傳遞時傳值呢還是傳引用?
- 五、深拷貝和淺拷貝?
- 六、Java中創建對象的幾種方式?
- 七、Java對象初始化過程?(筆試)
- 八、怎么精確表示任意精度的整數和任何精度的定點數或者貨幣?
- 九、String是Java基本數據類型嗎?可以被繼承嗎?
- 十、String是不可變類嗎?字符串拼接是如何實現的?
- 十一、不同String創建方法分別創建了幾個對象?
- 十二、String為什么是不可變的?設計原因?
- 十三、String、StringBuilder、StringBuffer 的區別?
- 總結
一、==和equals區別?
- ==:如果比較的對象是基本數據類型,則比較的是數值是否相等;如果比較的對象是引用數據類型,則比較的是對象的地址值是否相等
- equals方法:沒有重寫相當于==,重寫后比較兩個對象的內容是否相等。String、Integer重寫了
二、hashcode方法作用?兩個對象的hashCode方法相同,則equals方法也一定為true嗎?
- hashCode 方法主要用來獲取對象的哈希碼,哈希碼是由對象的內存地址或者對象的屬性計算出來的,它是?個int類型的整數,重復率低,因此可以用來作為鍵值對的鍵,以提高查詢效率。
- 不一定。因為存在哈希沖突,不同的對象可能會有相同的哈希值,所以哈希值相等,并不一定能equals方法相等。為了解決哈希沖突的問題,在判斷對象是否相等時,不僅會比較鍵對象的哈希碼,還會使用 equals 方法。如果兩個對象的哈希碼相同,但通過equals方法比較結果為 false,那么這兩個對象就不被視為相等。
三、為什么重寫equals方法就一定要重寫hashCode方法?
- 保證在equals相同的情況下hashcode值必定相同:如果只重寫equals方法,那么被認為相等的對象可能會有不同的哈希碼(默認是對象的地址,因此所有對象都是不同的哈希碼),存儲在集合不同的位置,導致集合出現重復元素或者無法找到對應元素(因為equals是根據對象的特征進行重寫)
- 提升性能:hashCode能提高hashmap等集合去重的性能,如果沒有重寫hashCode()方法,那么集合每次添加元素都要遍歷已有元素調用equals方法,性能太差,重寫hashcode能減少equals方法調用次數
四、Java中的參數傳遞時傳值呢還是傳引用?
- java基本類型作為參數被傳遞時是值傳遞;引用類型作為參數被傳遞時也是值傳遞,參數值是對象的引用。
五、深拷貝和淺拷貝?
- 淺拷貝僅拷貝被拷貝對象的基本數據類型變量的值和引用數據類型變量的地址值,而對于引用類型變量指向的堆中的對象不會拷貝
- 深拷貝完全拷貝一個對象,拷貝被拷貝對象的成員變量的值,堆中的對象也會拷貝一份。
- 淺拷貝需要實現Cloneable接口并重寫Object類中的clone()方法;
- 深拷貝需要實現Serializable接口,通過對象的序列化和反序列化,或者使所有引用類型屬性實現Cloneable接口
六、Java中創建對象的幾種方式?
- 使用new關鍵字
A a = new A();
- 使用Class類的newInstance方法,Class.forName.newInstance()
Class clazz = Class.forName("A");
A a = (A) clazz.newInstance();
- 使用clone方法
A a = new A();
A a2= (A) a.clone();
- 反序列化,比如調用ObjectInputStream類的readObject()方法
A a= new A();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt"));
oos.writeObject(a);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt"));
A a2 = (A) ois.readObject();
七、Java對象初始化過程?(筆試)
- 父類靜態屬性
- 父類靜態代碼塊
- 子類靜態屬性
- 子類靜態代碼塊
- 父類非靜態屬性
- 父類構造代碼塊
- 父類構造方法
- 子類非靜態屬性
- 子類構造代碼塊
- 子類構造方法
八、怎么精確表示任意精度的整數和任何精度的定點數或者貨幣?
- BigInteger任意精度的整數
- BigDecimal任何精度的定點數->貨幣
- 轉成分用int運算
九、String是Java基本數據類型嗎?可以被繼承嗎?
- 引用類型,String被final修飾不能被繼承
十、String是不可變類嗎?字符串拼接是如何實現的?
- String是不可變的,1.8以前+的拼接操作,如果字符串在常量池中不存在,則會生成新的對象。1.8時被優化為基于StringBuilder的append方法進行處理
十一、不同String創建方法分別創建了幾個對象?
String str1 = "abc";//1
String str2 = new String("abc")//2
- 1在內存的字符串常量池中存儲abc字符串對象
- 2在內存的字符串常量池中找abc字符串對象,沒有則創建;在堆中創建str2對象,引用指向abc字符串對象
十二、String為什么是不可變的?設計原因?
- 不可變:一旦String對象被創建,它所包含的字符串內容是不可改變的。
- 不可變是因為引用的char數組(jdk1.9后改為byte數組)被final修飾。字符串的值本身不能改變,但引用字符串的變量中記錄的地址值是可以改變的。每次修改操作(如拼接、替換等)都會產生新對象。
- 避免內存浪費:當創建一個String對象時,如果字符串值在常量池中已經存在則不會創建,只是引用已經存在的對象
- 性能優化:字符串不變性保證了hash碼的唯一性,允許String對象緩存頻繁使用的HashCode(如HashMap),不必每次都去計算新的哈希碼
- 安全性:String被許多的Java類用來當做參數,例如:網絡連接地址URL、文件路徑path、反射機制的String參數等, 如果String不是固定不變的,將會引起各種安全隱患。
十三、String、StringBuilder、StringBuffer 的區別?
- String:類的對象是不可變的;適用于字符串內容不經常改變的場景。在使用字符串常量或進行少量的字符串操作時使用。每次對String對象進行修改操作(如拼接、替換等)實際上都會生成一個新的String對象,而不是修改原有對象。大量字符串連接情況下,產生太多對象浪費內存。線程安全
- StringBuilder:適用于單線程環境下需要頻繁修改字符串內容的場景,比如在循環中拼接或修改字符串,使用字符數組char[]保存字符串,可變類,每次對String對象進行修改操作(如拼接、替換等)都是直接在原有字符串對象的底層數組上進行,不產生新對象,線程不安全;效率高
- StringBuffer:適用于多線程環境下需要頻繁修改字符串內容的場景,使用字符數組char[]保存字符串,可變類,方法加同步鎖synchronized,線程安全;效率低
- 多線程強制使用StringBuilder()
public class StringBuilderHolder {private final StringBuilder sb;public StringBuilderHolder(int capacity) {sb = new StringBuidler(capacity);}//3.避免重復構造String,重用StringBuilderpublic StringBuilder resetAndGetStringBuilder() {sb.setLength(0);return sb;}
}
//2.ThreadLocal避免多線程沖突
private static final ThreadLocal<StringBuilderHolder> threadLocalStringBuilderHolder = new ThreadLocal<StringBuilderHolder>() {protected StringBuilderHolder initialValue() {//1.設置好初始長度,超過char[]默認16調用System.arraycopy成倍復制擴容太浪費資源return new StringBuilderHolder(256);}
}StringBuilder sb = threadLocalStringBuilderHolder.get().resetAndGetStringBuilder();
總結
本文介紹了的java面試之java基礎(下),如有問題歡迎私信和評論