最常見的Java面試題及答案匯總(四)


反射

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(),但是此方法無法復制函數類型)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM