目錄
訪問修飾符的區別
?this關鍵字的作用
抽象類和接口有什么區別
抽象類可以定義構造方法嗎
但是接口不可以定義構造方法
Java支持多繼承嗎
接口可以多繼承嗎
繼承和抽象的區別?
抽象類和普通類的區別
成員變量和局部變量的區別?
staic關鍵字了解嗎
final關鍵字的作用
final,finally,finalize區別
==和equals的區別
為什么重寫equals時必須重寫hashcode方法
什么是hashcode方法
為什么要有hashcode方法
為什么兩個對象有相同的hashcode值,卻不一定相等呢
Java是值傳遞還是引用傳遞
深拷貝和淺拷貝的區別
java創建對象的方式有哪幾種
new子類的時候,父類和父類靜態代碼塊,構造方法的執行順序
String
String是Java的基本數據類型嗎,可以被繼承嗎
String有哪些常用的方法
String,Stringbuffer,Stringbulider的區別
String
Stringbuilder
Stringbuffer
String str1 = new String("abc")和 String str2 =“abc”的區別
String是不可變類?字符串拼接是如何實現的?
如何保證String不可變
String如何轉為Integer
訪問修飾符的區別
ava 中,可以使用訪問控制符來保護對類、變量、方法和構造方法的訪問。Java 支持 4 種不同的訪問權限。
- default?(即默認,什么也不寫): 在同一包內可見,不使用任何修飾符。可以修飾在類、接口、變量、方法。
- private?: 在同一類內可見。可以修飾變量、方法。注意:不能修飾類(外部類)
- public?: 對所有類可見。可以修飾類、接口、變量、方法
- protected?: 對同一包內的類和所有子類可見。可以修飾變量、方法。注意:不能修飾類(外部類)。
?this關鍵字的作用
this是自身的一個對象,代表對象本身,可以理解為:指向對象本身的一個指針。
1、普通的直接引用,this相當于是指向當前對象本身
2、形參與成員變量名字重用,用this區分
public Person(String name,int age){this.name=name;this.age=age;
}
3、引用本類的構造方法
抽象類和接口有什么區別
一個類只能繼承一個抽象類,但一個類可以實現多個接口。所以我們在新建線程類一般推薦使用實現Runnable接口的方式,這樣線程類還可以繼承其他類,而不單單是Thread類。
抽象類符合is-a的關系,而接口更像是has-a的關系,比如說一個類可以序列化的時候,它只需要實現Seralizable接口就可以了,而不需要去繼承一個序列化的類。
抽象類更多的是用來為多個相關的類提供一個共同的基礎框架,包括狀態的初始化,而接口則是定義了一套行為標準,讓不同的類可以實現同一接口。提供行為的多樣化實現。
抽象類可以定義構造方法嗎
可以,抽象類可以有構造方法
但是接口不可以定義構造方法
接口主要用于定義一組方法規范,沒有具體的實現細節
Java支持多繼承嗎
Java不支持多繼承,一個類只能繼承一個類,多繼承會引發菱形繼承問題
class A {void show() { System.out.println("A"); }
}class B extends A {void show() { System.out.println("B"); }
}class C extends A {void show() { System.out.println("C"); }
}// 如果 Java 支持多繼承
class D extends B, C {// 調用 show() 方法時,D 應該調用 B 的 show() 還是 C 的 show()?
}
接口可以多繼承嗎
接口可以多繼承,一個接口可以繼承多個接口,使用逗號分隔
interface InterfaceA {void methodA();
}interface InterfaceB {void methodB();
}interface InterfaceC extends InterfaceA, InterfaceB {void methodC();
}class MyClass implements InterfaceC {public void methodA() {System.out.println("Method A");}public void methodB() {System.out.println("Method B");}public void methodC() {System.out.println("Method C");}public static void main(String[] args) {MyClass myClass = new MyClass();myClass.methodA();myClass.methodB();myClass.methodC();}
}
在上面的例子中,InterfaceA 和 InterfaceB 是兩個獨立的接口。
InterfaceC 繼承了 InterfaceA 和 InterfaceB,并且定義了自己的方法 methodC。
MyClass 實現了 InterfaceC,因此需要實現 InterfaceA 和 InterfaceB 中的方法 methodA 和 methodB,以及 InterfaceC 中的方法 methodC。
繼承和抽象的區別?
繼承是一種允許子類繼承父類屬性和方法的機制。通過繼承,子類可以重用父類的代碼
抽象是一種隱藏復雜性和只顯示必要部分的技術,在面向對象編程中,抽象可以通過抽象類和接口實現
抽象類和普通類的區別
抽象類使用abstract關鍵字定義,不能被實例化,只能最為其他類的父類。普通類沒有 abstract 關鍵字,可以直接實例化。
抽象類可以包含抽象方法和非抽象方法。抽象方法沒有方法體,必須由子類實現。普通類只能包含非抽象方法。
成員變量和局部變量的區別?
1、語法上來看:成員變量是屬于類的,而局部變量是在方法中定義的變量或是方法的參數;成員變量可以被public,private,static等修飾符修飾,局部變量不能被修飾符修飾。但是成員變量和局部變量都能被final修飾
2、從變量在內存的存儲來看: 如果成員變量使用staic修飾的,那么這個成員變量是屬于類的,如果沒有staic修飾,那么是屬于實例的。對象存于堆內存,如果局部變量類型為基本數據類型,那么存儲在棧內存,如果為引用數據類型,那存放的是指向堆內存對象的引用或者是指向常量池中的地址。
3、從變量在內存的生存時間來看:成員變量是對象的一部分,它隨著對象的創建而存在,而局部變量隨著方法的調用而自動消失。
4、成員變量如果沒有被賦初值:則會自動以類型的默認值而賦值(被final修飾的成員變量也必須顯示的賦值),而局部變量則不會自動賦值
staic關鍵字了解嗎
static關鍵字可以用來修飾變量,方法,代碼塊和內部類,以及導入包
修飾對象 | 作用 |
---|---|
變量 | 靜態變量,類級別變量,所有實例共享同一份數據。 |
方法 | 靜態方法,類級別方法,與實例無關。 |
代碼塊 | 在類加載時初始化一些數據,只執行一次。 |
內部類 | 與外部類綁定但獨立于外部類實例。 |
導入 | 可以直接訪問靜態成員,無需通過類名引用,簡化代碼書寫,但會降低代碼可讀性。 |
靜態變量:?是被 static 修飾符修飾的變量,也稱為類變量,它屬于類,不屬于類的任何一個對象,一個類不管創建多少個對象,靜態變量在內存中有且僅有一個副本。
實例變量:?必須依存于某一實例,需要先創建對象然后通過對象才能訪問到它。靜態變量可以實現讓多個對象共享內存。
靜態方法:static 修飾的方法,也被稱為類方法。在外部調?靜態?法時,可以使?"類名.?法名"的?式,也可以使?"對象名.?法名"的?式。靜態方法里不能訪問類的非靜態成員變量和方法。
實例?法:依存于類的實例,需要使用"對象名.?法名"的?式調用;可以訪問類的所有成員變量和方法。
final關鍵字的作用
1、當final修飾一個類時,表明這個類不能被繼承。
2、當final修飾一個方法時,表明這個方法不能被重寫
3、當final修飾一個變量時,表明這個變量的值一旦被初始化就不能被修改
final,finally,finalize區別
final是一個修飾符,可以修飾類,方法和變量。可以修飾類、方法和變量。當 final 修飾一個類時,表明這個類不能被繼承;當 final 修飾一個方法時,表明這個方法不能被重寫;當 final 修飾一個變量時,表明這個變量是個常量,一旦賦值后,就不能再被修改了。
finally 是Java中異常處理的一部分,用來創建 try 塊后面的 finally 塊。無論 try 塊中的代碼是否拋出異常,finally 塊中的代碼總是會被執行。通常,finally 塊被用來釋放資源,如關閉文件、數據庫連接等。
finallize是Object類的一個方法,用于垃圾回收器將對象從內存中清除出去之前做一些必要的清理工作。
==和equals的區別
1、==用于比較兩個對象的引用,即他們是否指向同一個對象實例。對于基本數據類型,==比較的是值是否相等
2、equals用于比較兩個對象的內容是否相等,但是默認情況下和==相同,比較對象引用。然而,equals()
?方法通常被各種類重寫。例如,String
?類重寫了?equals()
?方法,以便它可以比較兩個字符串的字符內容是否完全一樣。
為什么重寫equals時必須重寫hashcode方法
因為基于哈希的集合類(如 HashMap)需要基于這一點來正確存儲和查找對象。
具體地說,HashMap 通過對象的哈希碼將其存儲在不同的“桶”中,當查找對象時,它需要使用 key 的哈希碼來確定對象在哪個桶中,然后再通過?equals()
?方法找到對應的對象。
如果重寫了?equals()
方法而沒有重寫?hashCode()
方法,那么被認為相等的對象可能會有不同的哈希碼,從而導致無法在 HashMap 中正確處理這些對象。
什么是hashcode方法
hashCode()
?方法的作?是獲取哈希碼,它會返回?個 int 整數,定義在?Object 類中, 是一個本地?法。
為什么要有hashcode方法
hashcode方法主要用于來獲取對象的哈希碼,哈希碼是由對象的內存地址或者對象屬性計算出來的,它是一個int類型的整數,通常是不會重復的,因此可以用來作為鍵值對的建,以提高查詢效率。
為什么兩個對象有相同的hashcode值,卻不一定相等呢
哈希碼是通過哈希函數將對象中映射成一個整數值,其主要目的是在哈希表中快速定位對象的存儲位置。
由于哈希函數將一個較大的輸入域映射到一個較小的輸出域,不同的輸入值(即不同的對象)可能會產生相同的輸出值(即相同的哈希碼)。
這種情況稱為哈希沖突。當兩個不相等的對象發生哈希沖突時,它們會有相同的 hashCode。為了解決哈希沖突的問題,哈希表在處理鍵時,不僅會比較鍵對象的哈希碼,還會使用 equals 方法來檢查鍵對象是否真正相等。如果兩個對象的哈希碼相同,但通過 equals 方法比較結果為 false,那么這兩個對象就不被視為相等。
Java是值傳遞還是引用傳遞
Java是值傳遞
當一個對象被作為參數傳遞到方法中時,參數的值就是該對象的引用。引用的值是對象在堆中的地址。對象是存儲在堆中的,所以傳遞對象的時,可以理解為把變量存儲的對象地址給傳遞過去。
深拷貝和淺拷貝的區別
在 Java 中,深拷貝(Deep Copy)和淺拷貝(Shallow Copy)是兩種拷貝對象的方式,它們在拷貝對象的方式上有很大不同。
?淺拷貝會創建一個新的對象,但這個對象的屬性和原對象的屬性完全相同。如果屬性是基本數據類型,拷貝的是基本數據類型的值;如果屬性是引用類型,拷貝的是引用地址。因此新舊對象共享一個引用對象。
淺拷貝的實現方式:實現Cloneable接口并重寫clone方法
深拷貝也會創建一個新對象,但是會遞歸的賦值所有的引用對象,確保新對象和原對象完全獨立。新對象與原對象的任何更改都不會相互影響。
深拷貝的實現方法有:手動復制所有的引用對象,或者使用序列化和反序列化。
java創建對象的方式有哪幾種
new子類的時候,父類和父類靜態代碼塊,構造方法的執行順序
1、首先執行父類的靜態代碼塊(僅在第一次加載時執行)
2、接著執行子類的靜態代碼塊(僅在類第一次加載時執行)
3、再執行父類的構造方法
4、最后執行子類的構造方法
String
String是Java的基本數據類型嗎,可以被繼承嗎
不是,String是一個類,屬于引用數據類型。String也不可以被繼承,因為被final修飾
String有哪些常用的方法
1、length 返回字符串長度
2、charAt 返回指定位置的字符
3、substring 返回字符串的一個子串
4、contains 檢查字符換是否包含指定的字符序列
5、equals比較兩個字符串內容是否相等
6、indexof 返回指定字符或者字符串首次出現的位置
7、replace替換字符串中的字符或字符序列
8、trim去除字符串兩端的空白字符
9、split 根據給定正則表達式的匹配拆分此字符串
String,Stringbuffer,Stringbulider的區別
String
、StringBuilder
和StringBuffer
在 Java 中都是用于處理字符串的,它們之間的區別是,String 是不可變的,平常開發用得最多,當遇到大量字符串連接時,就用 StringBuilder,它不會生成很多新的對象,StringBuffer 和 StringBuilder 類似,但每個方法上都加了 synchronized 關鍵字,所以是線程安全的。
String
String
類的對象是不可變的。也就是說,一旦一個String
對象被創建,它所包含的字符串內容是不可改變的。- 每次對
String
對象進行修改操作(如拼接、替換等)實際上都會生成一個新的String
對象,而不是修改原有對象。這可能會導致內存和性能開銷,尤其是在大量字符串操作的情況下。
Stringbuilder
StringBuilder
提供了一系列的方法來進行字符串的增刪改查操作,這些操作都是直接在原有字符串對象的底層數組上進行的,而不是生成新的 String 對象。StringBuilder
不是線程安全的。這意味著在沒有外部同步的情況下,它不適用于多線程環境。- 相比于
String
,在進行頻繁的字符串修改操作時,StringBuilder
能提供更好的性能。 Java 中的字符串連+
操作其實就是通過StringBuilder
實現的。
Stringbuffer
StringBuffer
和StringBuilder
類似,但StringBuffer
是線程安全的,方法前面都加了synchronized
關鍵字。
String str1 = new String("abc")和 String str2 =“abc”的區別
直接使用雙引號為字符串變量賦值時,Java 首先會檢查字符串常量池中是否已經存在相同內容的字符串。
如果存在,Java 就會讓新的變量引用池中的那個字符串;如果不存在,它會創建一個新的字符串,放入池中,并讓變量引用它。
使用?new String("abc")
?的方式創建字符串時,實際分為兩步:
- 第一步,先檢查字符串字面量 "abc" 是否在字符串常量池中,如果沒有則創建一個;如果已經存在,則引用它。
- 第二步,在堆中再創建一個新的字符串對象,并將其初始化為字符串常量池中 "abc" 的一個副本。
?new String("abc")創建了幾個對象
字符串常量池中如果之前已經有一個,則不再創建新的,直接引用;如果沒有,則創建一個。
堆中肯定有一個,因為只要使用了 new 關鍵字,肯定會在堆中創建一個。
String是不可變類?字符串拼接是如何實現的?
String 是不可變的,這意味著一旦一個 String 對象被創建,其存儲的文本內容就不能被改變。這是因為:
①、不可變性使得 String 對象在使用中更加安全。因為字符串經常用作參數傳遞給其他 Java 方法,例如網絡連接、打開文件等。
如果 String 是可變的,這些方法調用的參數值就可能在不知不覺中被改變,從而導致網絡連接被篡改、文件被莫名其妙地修改等問題。
②、不可變的對象因為狀態不會改變,所以更容易進行緩存和重用。字符串常量池的出現正是基于這個原因。
當代碼中出現相同的字符串字面量時,JVM 會確保所有的引用都指向常量池中的同一個對象,從而節約內存。
③、因為 String 的內容不會改變,所以它的哈希值也就固定不變。這使得 String 對象特別適合作為 HashMap 或 HashSet 等集合的鍵,因為計算哈希值只需要進行一次,提高了哈希表操作的效率。
因為 String 是不可變的,因此通過“+”操作符進行的字符串拼接,會生成新的字符串對象。Java 8 時,JDK 對“+”號的字符串拼接進行了優化,Java 會在編譯期基于 StringBuilder 的 append 方法進行拼接,String.join()
?等方式
如何保證String不可變
第一,String 類內部使用一個私有的字符數組來存儲字符串數據。這個字符數組在創建字符串時被初始化,之后不允許被改變。
第二,String 類沒有提供任何可以修改其內容的公共方法,像 concat 這些看似修改字符串的操作,實際上都是返回一個新創建的字符串對象,而原始字符串對象保持不變。
第三,String 類本身被聲明為 final,這意味著它不能被繼承。這防止了子類可能通過添加修改方法來改變字符串內容的可能性。
String如何轉為Integer
String 轉成 Integer,主要有兩個方法:
- Integer.parseInt(String s)
- Integer.valueOf(String s)
不管哪一種,最終還是會調用 Integer 類內中的parseInt(String s, int radix)
方法。