教面試官ReentrantLock源碼
803
2025-03-31
第一章,Java開發(fā)中通用的方法和準則
public class Person implements Serializable{ //流標識符(Stream Unique Identfier)類的版本定義,可以顯示定義可以隱式定義 private static final long serialVersionUID = 55799L; private String name; public Person() { // TODO Auto-generated constructor stub } public String getName() { return name; } public void setName(String name) { this.name = name; } } public class Producer { public static void main(String[] args) { //序列化 Person person =new Person(); person.setName("李瑞龍"); SerializationUtils.writeObject(person); System.out.println("序列化成功!!"); } } public class SerializationUtils { private static String FILE_NAME = "C:/LIRUILONG.bin"; /* * 序列化 * */ public static void writeObject(Serializable s) { try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE_NAME)); oos.writeObject(s); oos.close(); }catch(Exception e){ e.printStackTrace(); } } public SerializationUtils() { // TODO Auto-generated constructor stub } /* * 反序列化 * @return obj */ public static Object readObject() { Object obj = null; try { ObjectInput input = new ObjectInputStream(new FileInputStream(FILE_NAME)); obj = input.readObject(); input.close(); }catch(Exception e) { e.printStackTrace(); } return obj; } } public class Consumer { public static void main(String[] args)throws Exception { //反序列化 Person p = (Person)SerializationUtils.readObject(); System.out.println("name="+p.getName()); } }
當序列化和反序列化的版本不一致時,反序列化會報一個InvalidClassException異常,原因是類版本發(fā)生變化,JVM不能把數(shù)據(jù)流轉(zhuǎn)換為實例對象,JVM通過SerialVersionUID(流標識符),即類的版本定義的,可以顯示定義可以隱式定義(編譯器自動申明),JVM反序列化時,會比較數(shù)據(jù)流中的SerialVersionUID與類中的SerialVersionUID是否相同,不相同拋出異常。依靠顯示申明,改變一端的Person后可以運行。即顯示申明SerialVersionUID可以避免對象不一致。但盡量不要以這種方式向JVM"撒謊"。
(保存在磁盤上的對象文件包括兩部分:
1,類文件描述信息:包括類路徑,繼承關系,訪問權(quán)限,變量描述,變量訪問權(quán)限,方法簽名,返回值,以及變量 的關聯(lián)關系類信息。
2,非瞬態(tài)(trtansient)和非靜態(tài)(static)的的實例變量值。
反序列化時final變量在一下情況不會被賦值:通過構(gòu)造函數(shù)賦值,通過方法返回值賦值,final修飾的屬性不是基本類型
private void writeObject(ObjectOutputStream out)throws IOException{ //告訴JVM按照默認的規(guī)則寫入對象,慣例的寫法是寫在第一句 out.defaultWriteObject(); //寫入相應的值 out.writeInt(salary.getBasePay()); } private void readObject(ObjectInputStream in)throws IOException,ClassNotFoundException{ //告訴JVM按照默認規(guī)則讀入對象,也寫在第一句 in.defaultReadObject(); //獨處相應的值 salary = new Salary(in.readInt(),0); }
在序列化類中增加writeObject和readObject兩個方法,使用序列化的獨有機制,序列化回調(diào),Java調(diào)用ObjectOutputStream類把一個對象轉(zhuǎn)換為流數(shù)據(jù)時,會通過反射(Reflection)檢查被序列化的類是否有writeObject方法,并且檢查其是否為私有,無返回值的特性,若有,則會委托該方法進行對象序列化,若沒有,則由ObjectOutputStream按照默認規(guī)則繼續(xù)序列化,在反序列化的時候也會檢查是否有私有方法readObject。如果有會通過該方法讀取屬性。
腳本語言可以隨時發(fā)布而不用重新部署,即腳本語言改變,也能提供不間斷的業(yè)務服務。
public class main { public main() { // TODO Auto-generated constructor stub } public static void main(String[] args)throws Exception { // TODO Auto-generated method stub //獲取JAVacript的執(zhí)行引擎(engine)。 ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript"); //建立上下文變量 Bindings bind = engine.createBindings(); bind.put("factor", 1); //綁定上下文,作用域為當前引擎范圍。 engine.setBindings(bind, ScriptContext.ENGINE_SCOPE); Scanner input = new Scanner(System.in); while(input.hasNextInt()) { int first = input.nextInt(); int sec = input.nextInt(); System.out.println("輸入?yún)?shù)為:"+first+","+sec); //執(zhí)行js代碼 engine.eval(new FileReader("C:/model.js")); //是否可調(diào)用方法 if(engine instanceof Invocable) { Invocable in = (Invocable)engine; Double result = (Double)in.invokeFunction("formula",first,sec); System.out.println("運行結(jié)果:"+result.intValue()); } } } }
public interface Bindings extends Map
慎用動態(tài)編譯(注意:在框架中謹慎使用,不要在要求高性能的項目中使用,動態(tài)編譯要考慮安全問題,記錄動態(tài)編譯過程)
避免instanceof非預期的結(jié)果。(instanceof操作符的左右必須有繼承或?qū)崿F(xiàn)關系)
"String" instanceof String //返回值為true new String() instanceof String //返回值為true new Object() instanceof String //false(可以編譯) 'A' instanceof Character //編譯不通過,A為基本類型,Character為封裝類,前邊必須為對象。 null instanceof String //false,特殊規(guī)則,如果左操作數(shù)是null,結(jié)果就直接返回false,不在運運算右操作數(shù), (String)null instanceof String //false,null是一個萬用類型,可以說它沒有類型,即使類型轉(zhuǎn)換也是null。 new Date() instanceof String //編譯不通過,沒有繼承實現(xiàn)關系。 T(T為泛型String類變量) instanceof Date; //通過,false,T被編譯為Object類,傳遞String類的值,所以 "Object instanceof Date";
assert
對于final修飾的基本類型和String類型,編譯器會認為他是穩(wěn)定態(tài)(Immutable Status),所以編譯期間之間把值編譯到字節(jié)碼中,避免運行期引用(Run-time-reference),提高代碼執(zhí)行效率對于final修飾的基本類型和String類型,編譯器會認為他是穩(wěn)定態(tài)(Immutable Status),所以編譯期間之間把值編譯到字節(jié)碼中,避免運行期引用(Run-time-reference),提高代碼執(zhí)行效率,對于final類來講編譯器認為它是不穩(wěn)定的,在編譯期建立則是引用關系,即到final修飾一個類或?qū)嵗龝r,不重新編譯也會是最新值。
第二章,基本類型
i%2 == 1?"奇數(shù)":"偶數(shù)";//輸入-1為偶數(shù) public static int remainder(int dividend,int divisor){ return dividend - dividend/divisor*divisor; }
public static Integer valueOf(int){ final int offset= 128; if(i>=-128&&i<=127){ return IntegerCache[i+offset];} return new Ingeger(i); } static final Integer cache[] = new Integer[-(-128)+127+1]; static{ for(int i =0; i < cache.length;i++) cache[i] = new Integer(i-128) }
在java中,隨機數(shù)的產(chǎn)生取決于種子,隨機數(shù)和種子之間的關系(種子不同,產(chǎn)出的隨機數(shù)不同,種子相同,即使實例不同也產(chǎn)生相同的隨機數(shù))
public static void main(String[] args) { //Random r= new Random();默認種子 Random r= new Random(1000);//設置種子 for(int i=1;i<4;i++) { System.out.println("隨機數(shù)字為:"+r.nextInt()); } }
獲得隨機數(shù):Math.random()方法,通過java.util.Random;
第三章,類對象及方法
靜態(tài)變量是類加載時被分配到數(shù)據(jù)區(qū)(Data Area)的,它在內(nèi)存中只有一個拷貝,不會被分配多次,其后的所有賦值操作都是值改變,地址則保持不變。JVM初始化變量是先聲明空間,然后在賦值(int i= 12;==>int i ; i =12;)
靜態(tài)變量在類初始化時首先被加載的,JVM會查找類中所有的靜態(tài)申明,然后分配空間,只是完成地址空間分配,還沒有賦值,之后會根據(jù)類中的靜態(tài)賦值(包括靜態(tài)類型賦值和靜態(tài)塊賦值)的先后順序執(zhí)行。變量先申明后使用。
實例對象有兩個類型:表面類型(Apparent Type)和實際類型(Actual Type),表面類型是聲明時的類型,實際類型是對象產(chǎn)生時的類型,對于非靜態(tài)方法,它是根據(jù)對象的實際類型來執(zhí)行的,對于靜態(tài)方法來說,不依賴實例對象,通過類名訪問,通過對象訪問靜態(tài)方法,JVM會通過對象的表面類型查找到靜態(tài)方法的入口,然后執(zhí)行,
在子類中構(gòu)建與父類相同的方法名,輸入?yún)?shù),輸出參數(shù),訪問權(quán)限(權(quán)限可以擴大),并且父類子類都是靜態(tài)方法,此種行為稱之為隱藏(Hide),它與覆寫有兩點不同。
1,表現(xiàn)形式不同:隱藏用于靜態(tài)方法,覆寫用于非靜態(tài),@OVerride可以用于覆寫(寫上自動檢測是否合要求),不能用于隱藏。
2,職責不同:隱藏的目的是為了拋棄父類靜態(tài)方法,重現(xiàn)子類方法,覆寫是為了將父類的行為增強或減弱。
public class Base { //父類靜態(tài)方法 public static void doSomething() { System.out.println("我是父類的靜態(tài)方法"); } //父類非靜態(tài)方法 public void doAnything() { System.out.println("我是父類的非靜態(tài)方法"); } } public class Sub extends Base{ //子類同名,同參數(shù)的靜態(tài)方法 public static void doSomething() { System.out.println("我是子類的靜態(tài)方法"); } //覆寫父類的非靜態(tài)方法 @Override public void doAnything() { System.out.println("我是子類的非靜態(tài)方法"); } } public class Client1 { public static void main(String[] args) { Base base1 = new Sub(); Sub base = new Sub(); base.doAnything(); base1.doSomething(); base.doSomething(); } } //結(jié)果 //我是子類的非靜態(tài)方法 //我是父類的靜態(tài)方法 //我是子類的靜態(tài)方法
代碼塊(Code Block):{}包裹的數(shù)據(jù)體,實現(xiàn)特定算法,一般不能單獨運行,要有運行主體,java 中有四種:
1,普通代碼塊:方法名后面{ }部分。
2,靜態(tài)代碼塊:在類中使用static修飾的{ },用于靜態(tài)變量的初始化和對象創(chuàng)建前的環(huán)境初始化。類中的靜態(tài)塊會在整個類加載過程中的初始化階段執(zhí)行,而不是在類加載過程中的加載階段執(zhí)行。初始化階段是類加載過程中的最后一個階段,該階段就是執(zhí)行類構(gòu)造器
3,同步代碼塊:使用synchronized修飾的{ },表示同一時間只能有一個線程進入到該方法塊,一種多線程保護機制。
4,構(gòu)造代碼塊:在類中沒有人任何前綴和后綴的{ },編譯器會把構(gòu)造代碼塊插入到構(gòu)造函數(shù)的最前端。
在通過new關鍵字生成一個實例時會先執(zhí)行構(gòu)造代碼塊,然后在執(zhí)行其他構(gòu)造函數(shù)代碼,依托于構(gòu)造函數(shù)運行,不是在構(gòu)造函數(shù)之前運行。應用:
1,初始化實例變量(Instance Variable):如果每個構(gòu)造函數(shù)都需要初始化變量,可以通過構(gòu)造代碼塊實現(xiàn)。
2,初始化實例環(huán)境:當一個對象必須在適的場景才能存在,jee中要產(chǎn)生HTTP Request,必須要建立HTTP session ,可以在創(chuàng)建HTTP Request時通過構(gòu)造代碼塊檢查HTTP Session是否存在,不存在就創(chuàng)建。
java中的嵌套類(Nesetd Class):分為兩種,靜態(tài)內(nèi)部類(也叫靜態(tài)嵌套類,Static Nested Class)和內(nèi)部類(Inner Class),
靜態(tài)內(nèi)部類:加強了類的封裝性,提高了代碼的可讀性。
靜態(tài)內(nèi)部類不持有外部類的引用(普通內(nèi)部類可以訪問外部類的方法,屬性,即使是private類型也可以訪問,靜態(tài)內(nèi)部類只可以訪問外部類的靜態(tài)方法和靜態(tài)屬性),靜態(tài)內(nèi)部類不依賴外部類(普通內(nèi)部類與外部類之間是相互依賴的關系,內(nèi)部類實例不能脫離外部類實例,同生同死,一起聲明,一起被拉圾回收器回收,靜態(tài)內(nèi)部類可以獨立存在,即使外部類消亡,靜態(tài)內(nèi)部類還是可以存在),普通內(nèi)部不能聲明static的方法和變量(常量可以修飾,靜態(tài)內(nèi)部類沒有限制)
//聲明一個ArrayList對象。 List la = new ArrayList(); //一個繼承了ArrayList的匿名類的聲明和賦值,沒有任何覆寫方法。 List lb = new ArrayList(){}; //在上面的基礎上增加了構(gòu)造函數(shù)塊。可以有多個。 List lc = new ArrayList(){{}{}};
enum Ops{ADD,SUB } public class Calculator { private int i,j,result; public Calculator() { } public Calculator(int i,int j) { this.i =i; this.j = j; } protected void setOperator(Ops _op) { result = _op.equals(Ops.ADD)?i+j:i-j; } public int getResult() { return result; } public static void main(String[] args) { //定義一個匿名內(nèi)部類,使用構(gòu)造代碼塊初始化 Calculator c1 = new Calculator(1,2) { { setOperator(Ops.ADD); } }; System.out.println(c1.getResult()); } }
//父親 public interface Father { public int strong(); } //母親 public interface Mother { public int Kind(); } //父親實現(xiàn)類 public class FatherImpl implements Father { @Override public int strong() { return 8; } } //母親實現(xiàn)類 public class MotherImpl implements Mother{ @Override public int Kind() { return 8; } } //兒子 public class Son extends FatherImpl implements Mother{ @Override public int strong() { return super.strong()+1; } @Override public int Kind() { return new MotherSpecial().Kind(); } public class MotherSpecial extends MotherImpl { public int kind() { return super.Kind() -1; } } }
public class UtilsClass{ private UtilsClass(){ throw new Error("不要實例化我哎"); } }
一個類在實現(xiàn)了Cloneable接口就表示它具備了被拷貝的能力,如果在覆寫clone()方法就會完全具備拷貝能力。拷貝在內(nèi)存中進行,所以在性能方面比直接通過new生成對象要快的多,存在缺陷:淺拷貝(Shadow Clobe,也稱影子拷貝)存在對象屬性拷貝不徹底的問題。拷貝規(guī)則:
1,基本類型拷貝其值,。
2,實例對象,拷貝地址引用,就是說此時新拷貝的對象與原有對象共享該實例變量,不受訪問權(quán)限的限制。
3,String字符串,拷貝的也是地址,但是在修改時,會從字符串池(String Pool)中重新生成字符串,原有的字符串保持不變
public class Person implements Cloneable{ //姓名 private String name; //父親 private Person father; public Person(String name) { this.name = name; } public Person(String name,Person parent) { this.name = name; this.father = parent; } //getter與setter方法省略 public Person clone() { Person p = null; try { p = (Person)super.clone(); //p.setFather(new Person(p.getFather().getName())實現(xiàn)深拷貝 }catch(CloneNotSupportedException e) { e.printStackTrace(); } return p; } } public class Client2 { public static void main(String[] args) { Person f = new Person("父親"); Person s1 = new Person("大兒子",f); Person s2 = s1.clone(); s2.setName("小兒子"); //s2.getFather().setName("干爹"); System.out.println(s1.getName()+"的父親為:"+s1.getFather().getName()); System.out.println(s2.getName()+"的父親為:"+s2.getFather().getName()); } }
被拷貝的類只要實現(xiàn)Serializable接口,不需要任何實現(xiàn),需要加上SerialVersionUID常量,使用需要注意:
1,對象的內(nèi)部屬性都是可序列化的。
2,注意方法和屬性的特殊修飾符。final,static變量的序列化問題會被 引入到拷貝對象中,瞬態(tài)變量(trtansient)不能進行序列化。可一采用Apache下的commons工具包中的SerializationUtils類。
public class CloneUtils { //拷貝一個對象 //@SuppressWarnings。該批注的作用是給編譯器一條指令,告訴它對被批注的代碼元素內(nèi)部的某些警告保持靜默。 /* * 關鍵字 用途 deprecation 使用了不贊成使用的類或方法時的警告 unchecked 執(zhí)行了未檢查的轉(zhuǎn)換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合保存的類型。 fallthrough 當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告。 path 在類路徑、源文件路徑等中有不存在的路徑時的警告。 serial 當在可序列化的類上缺少 serialVersionUID 定義時的警告。 finally 任何 finally 子句不能正常完成時的警告。 all 關于以上所有情況的警告。 @SuppressWarnings 批注允許您選擇性地取消特定代碼段(即,類或方法)中的警告。其中的想法是當您看到警告時, 您將調(diào)查它,如果您確定它不是問題,您就可以添加一個 @SuppressWarnings 批注,以使您不會再看到警告。 雖然它聽起來似乎會屏蔽潛在的錯誤,但實際上它將提高代碼安全性,因為它將防止您對警告無動于衷 — 您看到的每一個警告都將值得注意。 */ @SuppressWarnings("unchecked") public static
HashMap的底層處理機制是以數(shù)組的方式保存Map條目的,鏈表保存val,依據(jù)傳入元素的hashCode方法返回的哈希值決定數(shù)組下標,如果該位置已有Map條目了,且與傳入的鍵值相等則不要處理,若不相等則則覆蓋,如果數(shù)組位置沒有條目則插入。并加入到Map條目的鏈表中。即在檢查相等時也是由哈希嗎確定位置。
哈希碼:由Object方法本地生成,確保每一個對象有一個哈希碼(哈希算法,輸入任意L,通過一定算法f(L),將其轉(zhuǎn)化為非可逆的輸出,一對一,多對一成立),重寫hashCode方法:
public int hashCode(){ return new HashCodeBuilder().append(),toHashCode();//HashCodeBuilder哈希碼生成工具。 }
Java JVM
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。