1.Object有多少個函數?
Object有九個函數:
- final Class <? extends Object> getClass()返回一個對象的運行時類,例如下面的代碼:
`
public class ObjectTest<T> extends Object{
public static void main(String[] args) {
Object a = new ObjectTest<String>();
Object b = new ObjectTest<Integer>();
System.out.println(a.getClass());
System.out.println(b.getClass());
System.out.println((new ObjectTest<String>()).getClass());
System.out.println(a.hashCode());
System.out.println(b.hashCode());
}
}
返回結果相同,getClass都是返回ObjectTest,都是相同的。 - int hashCode:Java程序運行期間,在同一個對象對此調用此函數,必須返回相同值,前提是equals比較所用信息沒有被修改。如果equals方法判定兩個對象相等,那么hashCode生成相同的整數結果。如果equals判定不相等,hashCode一定產生不同整數結果。Object類定義的hashCode方法確實會針對不同的對象返回不同值,一般是通過將該對象的內部地址轉換為一個整數來實現。
- boolean equals,自反對稱傳遞。
- Object clone() throws CloneNotSupportedException,必須要將Clonable接口實現才能調用,否則拋出異常。Clonable接口本身并無內容,只是表明此對象可以使用Clone函數。
- toString
- finalize()方法,JVM內存回收時調用,如果子類覆蓋了,對象一定要執行一次內存回收。
- wait 導致當前線程等待,直到該對象的notify或notifyAll被執行。即申請持有鎖。
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
該方法必須同步執行的,否則會拋出IllegalMonitorStateException。 - notify 隨機選擇一個對象,解除阻塞狀態,告知鎖解除。智能在同步方法或同步方法塊中執行,且調用者必須持有鎖。
- notifyall 通知所有線程。其余與上者相同。
2.JVM的垃圾回收機制介紹?
見第四條OOM發生。
3.介紹GNU?操作系統加載?
4.Object的HashCode如果不實現的話返回值是什么?
由地址轉換的hash值。
1.做了什么項目?了解什么框架?
2.數據庫范式定義?
參考:http://www.cnblogs.com/zhanht/p/5401699.html
參考:http://blog.csdn.net/qingking520/article/details/52937728
第一范式(1NF):屬性(實體所具有的某一特性)不可分。
第二范式(2NF):滿足第一范式,并且,一定要有一個主鍵,非主屬性完全依賴于主鍵。一個屬性在候選碼中出現就是主屬性。與之相對的就是非主屬性。完全指不是部分,而是全部。
第三范式(3NF):首先是 2NF,另外非主鍵列必須直接依賴于主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴于非主鍵列 B,非主鍵列 B 依賴于主鍵的情況。依賴傳遞。即依賴是唯一的。
BC范式(BCNF):符合3NF,并且,主屬性不依賴主屬性。
第四范式:要求把同一表內多對多關系刪除。
第五范式:從最終結構建立原始結構。
3.排序算法?
4.Java內存溢出?
簡述下個人思路:JVM運行時數據區域包括線程私有的本地方法棧、虛擬機棧、程序計數器,線程共享的方法區和堆。會發生OOM的公有本地方法棧(棧可以動態擴展,否則StackOverFlowError)、虛擬機棧(棧可以動態擴展)、方法區(包括方法區和運行時常量池)、堆(大頭)。
什么時候發生OOM(主要以堆來闡述),當堆(新生代,主要是Eden)沒有足夠的內存時發起一次MinorGC(針對新生代,復制法,其余還有標記-清楚、標記-整理),使用可達性分析(Python計數法);如果晉升導致老年代滿了,則觸發一次MajorGC(老年代)。永久代滿了使用FullGC(清理整個空間,包括永久代)。執行完了發現還沒有內存,才OOM。
5.線程與進程的區別?
線程調度的單位,進程是資源分配的單位。
6.為什么要序列化?什么場景用到?有哪些方法?弊端?
序列化:將一個對象編碼成一個字節流,稱作將該對象序列化;相反的過程稱為反序列化。
應用場景:對象被序列化后,其編碼就能從一臺虛擬機傳輸到另外一臺虛擬機,或者存儲到磁盤上。
如何實現:
- 實現Serializable接口
將Java對象根據屬性值轉換為字節序列,transient。static關鍵字則沒辦法實例化,舉例(HashMap的modCount)。場景,持久化、網絡傳輸、進程通信、緩存等。Serializable實際上就是用了一個獨立于你實現構造函數之外的構造函數去創建
弊端:1.大端小端2.破壞單例。
付出的代價(隱含了可能的失敗): - 如果沒有顯示化聲明私有靜態的final的long域下的UID,則系統會更具類的實現自動生成該標識,那么,當修改類的時候,可能造成發布版本的變化。
- 增加了出現Bug和安全漏洞的可能性。通常情況下對象是利用構造器來創建的,序列化機制是一種語言之外的對象創建機制。因此反序列化具備與其他構造器相同的特點,由于沒有顯示的構造器,很可能導致疏忽構造過程的規約。
- 加大測試負擔。
- 盡量不使用自定義序列化形式,使用默認序列化形式將出很多狀況,具體詳見《Effective Java》第75條。
- 序列化植入代碼,引用指向本對象可變的引用,導致程序發生不可逆轉的變化,《Effective Java》第76條。
- 反序列化破壞單例模式,詳情見《Effective Java》第77條。
7.java反射機制的實現原理
所謂反射機制就是java語言運行時擁有一項自觀的能力。通過這種能力可以徹底了解自身的情況為下一步的動作做準備,Java反射機制的實現主要借四個類:class、Constructor、Field、Method。
反射是指在運行時能查看一個類的狀態及特征,并能進行動態管理的功能。
反射的應用場景:在Java程序中許多對象在運行時都會出現兩種類型:編譯時類型和運行時類型。編譯時的類型由聲明該對象時使用的類型決定,運行時的類型由實際賦給對象的類型決定
如:Person p =new Student();
編譯時類型為Person,而運行時為Student。
除此之外,程序在運行時還可能接收到外部傳入的一個對象,該對象的編譯時類型為Object,但程序又需要調用該對象運行時類型的方法。為了這些問題程序需要在運行時發現對象和類的真實信息。然而,如果編譯時根本無法預知該對象和類可能屬于哪些類,程序只依靠運行時信息來發現該對象和類的真實信息,此時就必須使用反射。
7.1 java的類裝載系統與反射
其實也是一個java類加載和對象初始化過程。
java虛擬機中有兩種類裝載器:啟動類裝載器和自定義類裝載器。前者是jvm的一部分,后者是java程序的一部分,不同的裝載器放在不同的命名空間中。
反射是以免鏡子,能夠在鏡子中看到這個類中“所有”的東西。
有三種方法可以在程序中獲得class:
- 使用Class中的forname()靜態方法獲得class對象。
- 得到該類的一個對象使用(Object九大方法之一)getClass獲得。
- 運行時已經知道類名,使用類名.class獲得。
而反射在JVM中的實現如下: - 一、Class.forName的實現:在JDK中,可以發現最終調用的是native方法forName0(),它在C中調用的實際是findClassFromClassLoader(),原理與ClassLoader的流程(加載、連接)一樣。
- 二、getDeclaredFields0的實現:在JDK源碼中,可以知道class.getDeclaredFields()方法實際調用的是native方法getDeclaredFields0(),它主要實現步驟如下:
1.根據Class結構體信息,獲取field_count與fields[]字段,這個字段早已在load過程中被放入了
2.根據field_count的大小分配內存、創建數組。
3.將數組進行forEach循環,通過fields[]中的信息依次創建對象。
4.返回數組指針。 - 三、Method.invoke的實現:
1.創建Frame
2.如果對象flag為native,交給native_handler進行處理
3.在frame中執行java代碼
4.彈出Frame
5.返回執行結果的指針 - 四、class.newInstance的實現:
1.檢測權限、預分配空間大小等參數
2.創建Object對象,并malloc分配空間
3.通過Method.invoke調用構造函數(<init>())
4.返回Object指針
(tips:java類加載將將.class中的二進制流文件轉化為方法區(內存)中的Class對象)
7.2 JavaRTTI與反射
RTTI(Run-Time Type Identification,通過運行時類型識別)的含義就是在運行時識別一個對象的類型,其對應的類是Class對象,每個java里面的類都對應一個Class對象(在編寫并且編譯后),這個對象被保存在這個類的同名class文件里。
類加載器在類被第一次靜態調用(見java類加載)時會把那個對應的Class對象加載到內存中。
根據上文可以知道,獲取Class獨享有三種方法。通過Class對象用戶可以在運行時動態得到大量關于這個類的信息,包括接口,父類,方法,靜態成員,甚至是像newInstance()方法這樣的一個實現“虛擬構造器”的一種方式。所謂的虛擬構造器,就是聲明“我不知道你的確切類型,至少在編譯期不知道,但是我就是要正確的創建你的一個對象”。
RTTI的核心:Class對象、instanceof關鍵字、強制類型裝換。
RTTI的限制?顯然它在編譯時必須知道一個非常重要的東西:類名(全類名)
Java中有時候在編譯器為程序生成代碼很久之后才會出現要處理的那個類,那么這個時候怎么才能處理這個類呢,即在編譯的時候根本無法獲知這個對象所屬的類。答案就是利用Java的反射機制。Java的反射與RTTI的區別就在于編譯時不需要知道任何事情,匿名對象的信息在運行時確定下來就可以。
8.Java是如何處理整型的溢出和下溢的?
Java更具類型的大小,將計算結果中的對應低階字節存儲到對應的值里。