面向對象和面向過程的區別
兩者的主要區別在于解決問題的方式不同
面向過程把解決問題的過程拆成一個個方法,通過一個個方法的執行解決問題。
面向對象會先抽象出對象,然后用對象執行方法的方式解決問題。
另外,面向對象開發的程序一般更易維護、易復用 易擴展。
創建一個對象用什么運算符?對象實體與對象引用有何不同?
new運算符,new創建對象實例(對象實例在堆內存中),對象引用指向對象實例(對象引用存放在棧內存中)
一個對象引用可以指向0個或1個對象(一根繩子可以不系氣球,也可以系一個氣球)一個對象可以有n個引用指向它(可以用n條繩子系住一個氣球)。
對象的相等和引用相等的區別
對象的相等一般比較的是內存中存放的內容是否相等
引用相等一般比較的是他們指向的內存地址是否相等
類的構造方法的作用是什么
溝造方法是一種特殊的方法,主要作用是完成對象的初始化工作。
如果一個類沒有聲明構造方法, 該程序能正確執行嗎?
如果一個類沒有聲明構造方法,也可以執行! 因為一個類即使沒有聲明構造方法也會有默認的不帶參數的構造方法。如果我們自己添加了類的構造方法(無論是否有參),ava就不會再添加默認的
無參數的構造方法了,我們一直在不知不覺地使用構造方法,這也是為什么我們在創建對象的時候
后面要加一個括號(因為要調用無參的構造方法)。如果我們重載了有參的構造方法,記得都要把無參的構造方法也寫出來(無論是否用到),因為這可以幫助我們在創建對象的時候少踩。
溝造方法有哪些特點? 是否可被override
構造方法特點如下:
名字與類名相同
沒有返回值,但不能用void聲明構造函數
生成類的對象時自動執行,無需調用
構造方法不能被override (重寫),但是可以overload (重載)所以你可以看到一個類中有多個構造函數的情況
面向對象的三大特征
封裝
封裝是指把一個對象的狀態信息(也就是屬性)隱藏在對象內部,不允許外部對象直接訪問對象的為部信息。但是可以提供一些可以被外界訪問的方法來操作屬性。
繼承
不同類型的對象,相互之間經常有一定數量的共同點。
接口和抽象類有什么共同點和區別
共同點:
都不能被實例化
都可以包含抽象方法
都可以有默認實現的方法(java8可以用 default 關鍵字在接口中定義默認方法)
區別:
接口主要用于對類的行為進行約束,你實現了某個接口就具有了對應的行為。抽象類主要用于
代碼復用,強調的是所屬關系
一個類只能繼承一個類, 但是可以實現多個接口
接口中的成員變量只能是 public static final 類型的,不能被修改且必須有初始值,而抽
象類的成員變量默認default, 可在子類中被重新定義,也可被重新賦值。
深接貝和淺貝區別了解嗎?什么是引用貝?
關于深貝和淺貝區別,我這里先給結論
淺拷貝:淺貝會在堆上創建一個新的對象(區別于引用拷貝的一點),不過,如果原對象內
部的屬性是引用類型的話,淺貝會直接復制內部對象的引用地址,也就是說貝對象和原對象共用同一個內部對象
深拷貝:深拷貝會完全復制整個對象,包括這個對象所包含的內部對象。
Object類的常見方法有哪些?
Object類是一個特殊的類,是所有類的父類。它主要提供了以下11個方法
== 和equals的區別
對于基本類型和引用類型的作用效果是不同的:
對于基本數據類型來說, 比較的是值。
對于引用數據類型來說, 比較的是對象的內存地址,
因為java只有值傳遞,所以,對于==來說,不管是比較基本數據類型,還是引用數據類型的變量,其本質比較的都是值,只是引用類型變量存的值是對象的地址
equals) 不能用于判斷基本數據類型的變量,只能用來判斷兩個對象是否相等。 equals()方法存在于bject類中,而object類是所有類的直接或間接父類,因此所有的類都有equalsC)方法。
Object類 equalsC) 方法:
equals) 方法存在兩種使用情況:
類沒有重寫 equas()方法:通過equals()比較該類的兩個對象時,等價于通過 == 比較
這兩個對象,使用的默認是 object類equals()方法
類重寫了 equals()方法: 般我們都重寫 equas()方法來比較兩個對象中的屬性是否柜等;若它們的屬性相等,則返回true(即,認為這兩個對象相等)
舉個例子 (這里只是為了舉例。 實際上, 你按照下面這種寫法的話,像IDEA這種比較智能的IDEA 都會提示你將 == 換成 equals()。
String 中的 equals 方法是被重寫過的,因為 Object 的 equals 方法是比較的對象的內存
地址,而 String 的 equals 方法比較的是對象的值
當創建 String 類型的對象時,虛擬機會在常量池中查找有沒有已經存在的值和要創建的值相同
的對象,如果有就把它賦給當前引用。如果沒有就在常量池中重新創建一個 String 對象。
String類equals()方法:
hashCodeO有什么用?
hashcodeC 的作用是獲取哈希碼(int整數),也稱為散列碼。這個哈希碼的作用是確定該對象在哈希表中的索引位置
hashcode()定義在DK的 Object 類中,這就意味著java中的任何類都包含有
hashcode() 函數。另外需要注意的是:Object的hashcode()方法是本地方法,也就是用C語言或c++實現的,該方法通常用來將對象的內存地址轉換為整數之后返回。
散列表存儲的是鍵值對(key-value),它的特點是:能根據鍵“快速的檢索出對應的值”。這其中就利用到了散列碼! (可以快速找到所需要的對象)
為什么要有hashCode?
我們以HashSet 如何檢查重復為例子來說明為什么要有 hashcode
下面這段內容摘自我的Java啟蒙書 《HeadFirst java》:
當你把對象加入 HashSet 時, HashSet 會先計算對象的 hashcode 值來判斷對象加入的位置,同時也會與其他已經加入的對象的 hashcode值作比較,如果沒有相符的 hashcode
HashSet 會假設對象沒有重復出現。但是如果發現有相同hashcode 值的對象,這時會調用equals) 方法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同,HashSet就不會讓其加入操作成功。如果不同的話,就會重新散列到其他位置。這樣我們就大大減少了
equals 的次數,相應就大大提高了執行速度。
其實, hashcodeC) 和 equals)都是用于比較兩個對象是否相等
那為什么JDK還要同時提供這兩個方法呢?
這是因為在一些容器(比如 HashMap、 HashSet)中,有了 hashcodeC)之后,判斷元素是否在對應容器中的效率會更高 (參考添加元素進HashSet的過程)
我們在前面也提到了添加元素進Hashset的過程,如果HashSet在對比的時候,同樣的
hashcode 有多個對象,它會繼續使用 equals) 來判斷是否真的相同。也就是說 hashcode
幫助我們大大縮小了查找成本。
那為什么不只提供 hashcodeO 方法呢?
這是因為兩個對象的hashcode 值相等并不代表兩個對象就相等
那為什么兩個對象有相同的 hashcode 值,它們也不一定是相等的?
因為 hashcodeC 所使用的哈希算法也許剛好會讓多個對象傳回相同的哈希值。越糟糕的哈希算法越容易碰撞,但這也與數據值域分布的特性有關 (所請哈希碰撞也就是指的是不同的對象得到柜同的 hashcode)
總結下來就是:
如果兩個對象的hashcode 值相等,那這兩個對象不一定相等(哈希碰撞)。
如果兩個對象的hashcode 相等并且equals()方法也返回 true,我們才認為這兩個對象
相等。
如果兩個對象的hashcode 值不相等,我們就可以直接認為這兩個對象不相等
相信大家看了我前面對 hashcodeO) 和equalsO 的介紹之后, 下面這個問題已經難不倒你們
了。
為什么重寫equals() 時必須重寫hashCode() 方法?
因為兩個相等的對象的 hashcode 值必須是相等。也就是說如果 equals 方法判斷兩個對象是相等的,那這兩個對象的 hashcode 值也要相等,
如果重寫 equals) 時沒有重寫 hashcode() 方法的話就可能會導致 equals 方法判斷是相等的兩個對象, hashcode 值卻不相等
思考:重寫 equals) 時沒有重寫 hashcode) 方法的話,使用 HashMap 可能會出現什么問
題。
總結:
equals 方法判斷兩個對象是相等的,那這兩個對象的 hashcode 值也要相等
兩個對象有相同的 hashcode 值,他們也不一定是相等的(哈希碰撞)
String
String、 StringBuffer、StringBuilder的區別?
可變性
String 是不可變的
StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在
AbstractStringBuilder 中也是使用字符數組保存字符串,不過沒有使用final和
private 關鍵字修飾,最關鍵的是這個 AbstractstringBuilder 類還提供了很多修改字符串的方法比如 append 方法。
線程安全性
String 中的對象是不可變的,也就可以理解為常量,線程安全。AbstractstringBuilder是StringBuilder 與 StringBuffer 的公共父類,定義了一些字符串的基本操作,如
expandcapacity、 append、insert、indexOf 等公共方法。 StringBuffer對方法加了司步鎖或者對調用的方法加了同步鎖,所以是線程安全的。 StringBuilder并沒有對方法進行加同步鎖,所以是非線程安全的。
性能
每次對String 類型進行改變的時候,都會生成一個新的 String對象,然后將指針指向新的String對象。 StringBuffer 每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象并改變對象引用。相同情況下使用StringBuilder 相比使用 StringBuffer僅能獲得10%~15%左右的性能提升,但卻要冒多線程不安全的風險。
對于三者使用的總結:
1操作少量的數據:適用String
2單線程操作字符串緩沖區下操作大量數據:適用 StringBuilder
3多線程操作字符串緩沖區下操作大量數據:適用 StringBuffer