java面試(反射)05


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 接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆。

 


免責聲明!

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



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