反射
57. 什么是反射?
反射主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力
Java反射:
在Java運行時環境中,對於任意一個類,能否知道這個類有哪些屬性和方法?對於任意一個對象,能否調用它的任意一個方法
Java反射機制主要提供了以下功能:
-
在運行時判斷任意一個對象所屬的類。
-
在運行時構造任意一個類的對象。
-
在運行時判斷任意一個類所具有的成員變量和方法。
-
在運行時調用任意一個對象的方法。
58. 什么是 java 序列化?什么情況下需要序列化?
簡單說就是為了保存在內存中的各種對象的狀態(也就是實例變量,不是方法),並且可以把保存的對象狀態再讀出來。雖然你可以用你自己的各種各樣的方法來保存object states,但是Java給你提供一種應該比你自己好的保存對象狀態的機制,那就是序列化。
什么情況下需要序列化:
a)當你想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;
b)當你想用套接字在網絡上傳送對象的時候;
c)當你想通過RMI傳輸對象的時候;
59. 動態代理是什么?有哪些應用?
動態代理:
當想要給實現了某個接口的類中的方法,加一些額外的處理。比如說加日志,加事務等。可以給這個類創建一個代理,故名思議就是創建一個新的類,這個類不僅包含原來類方法的功能,而且還在原來的基礎上添加了額外處理的新類。這個代理類並不是定義好的,是動態生成的。具有解耦意義,靈活,擴展性強。
動態代理的應用:
-
Spring的AOP
-
加事務
-
加權限
-
加日志
60. 怎么實現動態代理?
首先必須定義一個接口,還要有一個InvocationHandler(將實現接口的類的對象傳遞給它)處理類。再有一個工具類Proxy(習慣性將其稱為代理類,因為調用他的newInstance()可以產生代理對象,其實他只是一個產生代理對象的工具類)。利用到InvocationHandler,拼接代理類源碼,將其編譯生成代理類的二進制碼,利用加載器加載,並將其實例化產生代理對象,最后返回。
對象拷貝
61. 為什么要使用克隆?
想對一個對象進行處理,又想保留原有的數據進行接下來的操作,就需要克隆了,Java語言中克隆針對的是類的實例。
62. 如何實現對象克隆?
有兩種方式:
1). 實現Cloneable接口並重寫Object類中的clone()方法;
2). 實現Serializable接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆,代碼如下:
1 import java.io.ByteArrayInputStream; 2 import java.io.ByteArrayOutputStream; 3 import java.io.ObjectInputStream; 4 import java.io.ObjectOutputStream; 5 import java.io.Serializable; 6 7 public class MyUtil { 8 9 private MyUtil() { 10 throw new AssertionError(); 11 } 12 13 @SuppressWarnings("unchecked") 14 public static <T extends Serializable> T clone(T obj) throws Exception { 15 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 16 ObjectOutputStream oos = new ObjectOutputStream(bout); 17 oos.writeObject(obj); 18 19 ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); 20 ObjectInputStream ois = new ObjectInputStream(bin); 21 return (T) ois.readObject(); 22 23 // 說明:調用ByteArrayInputStream或ByteArrayOutputStream對象的close方法沒有任何意義 24 // 這兩個基於內存的流只要垃圾回收器清理對象就能夠釋放資源,這一點不同於對外部資源(如文件流)的釋放 25 } 26 }
下面是測試代碼:
1 import java.io.Serializable; 2 3 /** 4 * 人類 5 * @author nnngu 6 * 7 */ 8 class Person implements Serializable { 9 private static final long serialVersionUID = -9102017020286042305L; 10 11 private String name; // 姓名 12 private int age; // 年齡 13 private Car car; // 座駕 14 15 public Person(String name, int age, Car car) { 16 this.name = name; 17 this.age = age; 18 this.car = car; 19 } 20 21 public String getName() { 22 return name; 23 } 24 25 public void setName(String name) { 26 this.name = name; 27 } 28 29 public int getAge() { 30 return age; 31 } 32 33 public void setAge(int age) { 34 this.age = age; 35 } 36 37 public Car getCar() { 38 return car; 39 } 40 41 public void setCar(Car car) { 42 this.car = car; 43 } 44 45 @Override 46 public String toString() { 47 return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; 48 } 49 50 }
1 /** 2 * 小汽車類 3 * @author nnngu 4 * 5 */ 6 class Car implements Serializable { 7 private static final long serialVersionUID = -5713945027627603702L; 8 9 private String brand; // 品牌 10 private int maxSpeed; // 最高時速 11 12 public Car(String brand, int maxSpeed) { 13 this.brand = brand; 14 this.maxSpeed = maxSpeed; 15 } 16 17 public String getBrand() { 18 return brand; 19 } 20 21 public void setBrand(String brand) { 22 this.brand = brand; 23 } 24 25 public int getMaxSpeed() { 26 return maxSpeed; 27 } 28 29 public void setMaxSpeed(int maxSpeed) { 30 this.maxSpeed = maxSpeed; 31 } 32 33 @Override 34 public String toString() { 35 return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; 36 } 37 38 }
1 class CloneTest { 2 3 public static void main(String[] args) { 4 try { 5 Person p1 = new Person("郭靖", 33, new Car("Benz", 300)); 6 Person p2 = MyUtil.clone(p1); // 深度克隆 7 p2.getCar().setBrand("BYD"); 8 // 修改克隆的Person對象p2關聯的汽車對象的品牌屬性 9 // 原來的Person對象p1關聯的汽車不會受到任何影響 10 // 因為在克隆Person對象時其關聯的汽車對象也被克隆了 11 System.out.println(p1); 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } 15 } 16 }
注意:基於序列化和反序列化實現的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可以檢查出要克隆的對象是否支持序列化,這項檢查是編譯器完成的,不是在運行時拋出異常,這種是方案明顯優於使用Object類的clone方法克隆對象。讓問題在編譯的時候暴露出來總是好過把問題留到運行時。
63. 深拷貝和淺拷貝區別是什么?
-
淺拷貝只是復制了對象的引用地址,兩個對象指向同一個內存地址,所以修改其中任意的值,另一個值都會隨之變化,這就是淺拷貝(例:assign())
-
深拷貝是將對象及值復制過來,兩個對象修改其中任意的值另一個值不會改變,這就是深拷貝(例:JSON.parse()和JSON.stringify(),但是此方法無法復制函數類型)
