1.什么是反射
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠獲取這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取類信息以及動態調用對象內容就稱為java語言的反射機制。
2.反射的作用
-
在運行時判斷任意一個對象所屬的類;
-
在運行時構造任意一個類的對象;
-
在運行時判斷任意一個類所具有的成員變量和方法;
-
在運行時調用任意一個對象的方法;
3.反射的實現
我們知道,要使用一個類,就要先把它加載到虛擬機中,生成一個Class對象。這個class對象就保存了這個類的一切信息。
反射機制的實現,就是獲取這個Class對象,通過Class對象去訪問類、對象的元數據以及運行時的數據。
有三種方法獲得類的Class對象:Class.forName(String className)、className.class、實例對象.getClass();
4.什么是 Java 序列化?什么情況下需要序列化?
Java 序列化是為了保存各種對象在內存中的狀態,並且可以把保存的對象狀態再讀出來。
以下情況需要使用 Java 序列化:
- 想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;
- 想用套接字在網絡上傳送對象的時候;
- 想通過RMI(遠程方法調用)傳輸對象的時候。
5.動態代理是什么?有哪些應用?
動態代理是運行時動態生成代理類。
動態代理的應用有 spring aop、hibernate 數據查詢、測試框架的后端 mock、rpc,Java注解對象獲取等。
6.怎么實現動態代理?
JDK 原生動態代理和 cglib 動態代理。JDK 原生動態代理是基於接口實現的,而 cglib 是基於繼承當前類的子類實現的。
7.為什么要使用克隆對象?
在java中,我們使用對象的時候直接去new一個對象就好了,為什么還要克隆對象呢?
當我們new一個對象之后是要對該對象進行初始化的,不然這個對象是空的沒有內容。而使用克隆,則會得到一個原對象以及原對象里面包含的內容。例如,你有一個User對象,里面的包含了相關的屬性。此時你想要修改里面的某一屬性,但又不想破壞原對象里面的數據,此時就可以克隆User這個對象,然后在克隆的這個User對象上進行修改操作。除此,如果你在操作完之后判斷一下屬性是否更改成功,則使用克隆的對象和原對象做一下對比即可。
8.如何克隆一個對象?
8.1淺復制
淺克隆就是把原對象中的一些屬性值克隆過來。使用clone()方法進行淺克隆。但注意:必須要在被克隆類上實現Cloneable接口,並重寫clone方法。若不沒有實現該接口,則會拋出CloneNotSupportedException異常!
package interview; public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stub User user = new User(); user.setName("張三"); user.setAge(18); System.out.println("原對象(user)的屬性值:"); System.out.println("姓名為:" + user.getName() + ",年齡為:" + user.getAge()+"\n"); // 對user對象進行克隆 User user1 = (User) user.clone(); // 查看一下克隆對象中的屬性值 System.out.println("克隆后user1對象中的屬性值:"); System.out.println("姓名為:" + user1.getName() + ",年齡為:" + user1.getAge()+"\n"); // 結果和原對象中屬性值相同 // 對user1對象進行修改 user1.setName("李四"); // 查看修改后的結果 System.out.println("user1對象進行修改后的屬性值:"); System.out.println("姓名為:" + user1.getName() + ",年齡為:" + user1.getAge()+"\n"); System.out.println("user1對象進行修改后user對象的屬性值:"); System.out.println("姓名為:" + user.getName() + ",年齡為:" + user.getAge()+"\n"); } } class User implements Cloneable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } }

從結果上可以看出,克隆對象user1和原對象user在修改屬性數據時,兩個對象之間的數據互不受影響。
那么如果后期需要調整代碼,需要在原有的user對象中添加一個引用類型Address字段,那么克隆的user1對象會能受到影響嗎?能和原對象user中的數據一致嗎?
看下面代碼演示,在原有基礎代碼上加入一個Address的類,並分別在User類和Address類中加入重寫Object的方法。注意:User類中的引用address字段的權限修飾符為public,否則無法運行!
package interview; public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stub // 創建原對象,並為原對象中的屬性進行賦值,然后打印出結果 Address address = new Address("中國", "山東"); User user = new User("張三", 18, address); System.out.println("原對象(user)的屬性值:"); System.out.println("姓名為:" + user.getName() + ",年齡為:" + user.getAge() + ",地址為:" + user.getAddress() + "\n"); // 對user對象進行克隆 User user1 = (User) user.clone(); // 查看一下克隆對象中的屬性值 System.out.println("克隆后user1對象中的屬性值:"); System.out.println("姓名為:" + user1.getName() + ",年齡為:" + user1.getAge() + ",地址為:" + user1.getAddress() + "\n"); // 對user1對象進行修改 user1.setName("李四"); user1.getAddress().setCity("北京"); // 查看修改后的結果 System.out.println("user1對象進行修改后的屬性值:"); System.out.println("姓名為:" + user1.getName() + ",年齡為:" + user1.getAge() +",地址為:" + user1.getAddress() + "\n"); System.out.println("user1對象進行修改后user對象的屬性值:"); System.out.println("姓名為:" + user.getName() + ",年齡為:" + user.getAge() + ",地址為:" + user.getAddress() + "\n"); } } class User implements Cloneable { private String name; private int age; private Address address; public User(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } // 定義一個address類 class Address { private String country; private String city; public Address(String country, String city) { this.country = country; this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() { return "Address [country=" + country + ", city=" + city + "]"; } }

從結果上看,user1在克隆完后修改了姓名和地址值,修改后和原對象對比,發現姓名和地址的確發生了改變。但再次查看原對象的結果時,發現原對象的姓名值雖沒變,但地址值卻隨着user1對象的改變而改變了!這樣的話反而失去了克隆的意義。那么為什么會出現這種情況呢?因為淺克隆只是克隆原對象中的引用類型指向,並非克隆了原對象中的全部數據。
3.2 深克隆
深克隆和淺克隆的區別在於:淺克隆只克隆了原對象的引用類型的指向。深克隆則是克隆了原對象的所有。也就是說像上面案例所示,如果使兩個對象之間互不影響,則使用深克隆。
深克隆的使用:在引用類型所在的類使其實現Cloneable接口,並使用public修飾符重寫Clone()方法。
package interview; public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stub // 創建原對象,並為原對象中的屬性進行賦值,然后打印出結果 Address address = new Address("中國", "山東"); User user = new User("張三", 18, address); System.out.println("原對象(user)的屬性值:"); System.out.println("姓名為:" + user.getName() + ",年齡為:" + user.getAge() + ",地址為:" + user.getAddress() + "\n"); // 對user對象進行克隆 User user1 = (User) user.clone(); // 查看一下克隆對象中的屬性值 System.out.println("克隆后user1對象中的屬性值:"); System.out.println("姓名為:" + user1.getName() + ",年齡為:" + user1.getAge() + ",地址為:" + user1.getAddress() + "\n"); // 對user1對象進行修改 user1.setName("李四"); user1.getAddress().setCity("北京"); // 查看修改后的結果 System.out.println("user1對象進行修改后的屬性值:"); System.out.println("姓名為:" + user1.getName() + ",年齡為:" + user1.getAge() + ",地址為:" + user1.getAddress() + "\n"); System.out.println("user1對象進行修改后user對象的屬性值:"); System.out.println("姓名為:" + user.getName() + ",年齡為:" + user.getAge() + ",地址為:" + user.getAddress() + "\n"); } } class User implements Cloneable { private String name; private int age; private Address address; public User(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub // 這一步返回的這個user對象還只是一個淺克隆, User user = (User) super.clone(); // 然后克隆的過程中獲得這個克隆的user,然后調用這個getAddress()這個方方法得到這個Addrress對象。然后實現克隆。在設置到這個user中的Address。 // 這樣實現了雙層克隆使得那個Address對象也得到了復制。 user.setAddress((Address) user.getAddress().clone()); return user; } } // 定義一個address類 class Address implements Cloneable { private String country; private String city; public Address(String country, String city) { this.country = country; this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() { return "Address [country=" + country + ", city=" + city + "]"; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } }

9.如何實現對象克隆?
- 實現 Cloneable 接口並重寫 Object 類中的 clone() 方法。
- 實現 Serializable 接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆。
