1. 程式人生 > >Java面試題整理一(反射)

Java面試題整理一(反射)

問題:簡述Java中的反射使用

答:

1.作用:

可以通過配置檔案來動態配置和載入類,以實現軟體工程理論裡所提及的類與類,模組與模組之間的解耦。反射最經典的應用是spring框架。

2. 定義
反射簡單來說,就是動態載入物件,並對物件進行剖析。在Java中的反射機制是指在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;

對於任意一個物件,都能夠呼叫它的任意一個方法,這種動態獲取資訊以及動態呼叫物件方法的功能稱為Java語言的反射機制


2.1 動態性質
執行時生成物件例項;
執行期間呼叫方法;
執行時更改屬性
2.2 Java反射機制能實現的功能
在執行時判斷任意一個物件所屬的類
在執行時構造任意一個類的物件
在執行時判斷任意一個類所具有的方法和屬性
在執行時呼叫任意一個物件的方法
生成動態代理
2.3 Java反射應用場合
在Java程式中許多物件在執行時都會出現兩種型別:編譯時型別

執行時型別
編譯時的型別由宣告該物件時使用的型別決定,執行時的型別由實際賦給物件的型別決定
如:Person p =new Student();
編譯時型別為Person,而執行時為Student

除此之外,程式在執行時還可能接收到外部傳入的一個物件,該物件的編譯時型別為Object,但程式又需要呼叫該物件執行時型別的方法。為了這些問題程式需要在執行時發現物件和類的真實資訊。然而,如果編譯時根本無法預知該物件和類可能屬於哪些類,程式只依靠執行時資訊來發現該物件和類的真實資訊,此時就必須使用反射

3. JAVA反射API

反射API用來生成在當前JAVA虛擬機器中的類、介面或者物件的資訊。
Class類:反射的核心類,可以獲取類的屬性,方法等內容資訊。
Field類:Java.lang.reflect.表示類的屬性,可以獲取和設定類的中屬性值。
Method類:Java.lang.reflect。表示類的方法,它可以用來獲取類中方法的資訊或者執行方法
Construcor類:Java.lang.reflect。表示類的構造方法。

下面舉例示意:

第一種方式通過類的全路徑來實現

新建一個待反射的Person類

package com.test.Reflect;

public class Person {
	private String name;
    private String gender;
    private int age;
    
    private Person() {
    //
    }
    public Person(String name, String gender, int age) {
        super();
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    //getter、和setter方法
    private String getName() {
        return name;
    }
    private void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public String toString(){
        return "姓名:"+name+"年齡: "+age;
    }
}
第一個Demo查詢類的資訊並輸出
package com.test.Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javax.swing.JOptionPane;

/**
 * 通過使用者輸入類的全路徑,來獲取該類的成員方法和屬性
 * Declared獲取全部不管是私有和公有
 * 1.獲取訪問類的Class物件
 * 2.呼叫Class物件的方法返回訪問類的方法和屬性資訊
 **/

public class ReflectDemo1 {

    /*
     * 構造方法
     */
    public ReflectDemo1(){
        //使用者輸入類的全路徑徑
        //使用String元件
        String classpsth=JOptionPane.showInputDialog(null,"輸入類的全路徑");
        //使用Class.forName方法根據輸入的類的全路徑 返回該類的Class物件
        try {
            Class cla = Class.forName(classpsth);
            //利用Class物件的cla的自審,返回方法物件集合
            Method [] method=cla.getDeclaredMethods(); //返回所有的方法
            System.out.println("========獲取方法資訊============");
            for (Method meth : method) {
                //遍歷method陣列,並輸出方法資訊
                System.out.println(meth.toString());
            }
            System.out.println("========獲取出方法資訊結束============");
            //獲取屬性利用Class物件的cla的自審,返回成員屬性物件集合
             Field [] field=cla.getDeclaredFields();
                System.out.println("========獲取成員屬性資訊============");
                for (Field f : field) {
                    System.out.println(f.toString());
                }
                System.out.println("========獲取成員屬性資訊結束============");
            //獲取屬性利用Class物件的cla的自審,返回構造方法集合
                Constructor [] constructor=cla.getDeclaredConstructors();
                System.out.println("========獲取成員構造方法資訊============");
                for (Constructor constru : constructor) {
                    System.out.println(constru.toString());
                }
                System.out.println("========獲取成員構造方法資訊結束============");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("路徑輸入錯誤!");
        }
    }
}

最後是測試類
package com.test.Reflect;
/**
 * 測試類
 * @author Admin
 *
 */
public class TestReflection {
	public static void main(String[] args) {
        ReflectDemo1 rd=new ReflectDemo1();

    }
}

執行後會有一個簡單的彈窗用來輸入類的全路徑:com.test.Reflect.Person

輸出結果為:
========獲取方法資訊============
public java.lang.String com.test.Reflect.Person.toString()
private java.lang.String com.test.Reflect.Person.getName()
private void com.test.Reflect.Person.setName(java.lang.String)
public java.lang.String com.test.Reflect.Person.getGender()
public void com.test.Reflect.Person.setGender(java.lang.String)
public void com.test.Reflect.Person.setAge(int)
public int com.test.Reflect.Person.getAge()
========獲取出方法資訊結束============
========獲取成員屬性資訊============
private java.lang.String com.test.Reflect.Person.name
private java.lang.String com.test.Reflect.Person.gender
private int com.test.Reflect.Person.age
========獲取成員屬性資訊結束============
========獲取成員構造方法資訊============
private com.test.Reflect.Person()
public com.test.Reflect.Person(java.lang.String,java.lang.String,int)
========獲取成員構造方法資訊結束============

第二種方式 物件的getClass()

首先還是用上面的Person類,只不過把建構函式的屬性修改為 default

public class Person {
	private String name;
    private String gender;
    private int age;
    
    Person() {
    //
    }
    public Person(String name, String gender, int age) {
        super();
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    //getter、和setter方法
    private String getName() {
        return name;
    }
    private void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public String toString(){
        return "姓名:"+name+"年齡: "+age;
    }

ReflectDemo類基本上不變,只是cla的傳值方式變了,改成    Class cla=p.getClass();

public ReflectDemo2(Person p){
	        Class cla=p.getClass();
	        //利用Class物件的cla的自審,返回方法物件集合
	        Method [] method=cla.getDeclaredMethods(); //返回所有的方法
	        System.out.println("========獲取方法資訊============");
	        for (Method meth : method) {
	            //遍歷method陣列,並輸出方法資訊
	            System.out.println(meth.toString());
	        }
	        System.out.println("========獲取出方法資訊結束============");
	        //獲取屬性利用Class物件的cla的自審,返回成員屬性物件集合
	         Field [] field=cla.getDeclaredFields();
	            System.out.println("========獲取成員屬性資訊============");
	            for (Field f : field) {
	                System.out.println(f.toString());
	            }
	            System.out.println("========獲取成員屬性資訊結束============");
	        //獲取屬性利用Class物件的cla的自審,返回構造方法集合
	            Constructor [] constructor=cla.getDeclaredConstructors();
	            System.out.println("========獲取成員構造方法資訊============");
	            for (Constructor constru : constructor) {
	                System.out.println(constru.toString());
	            }
	            System.out.println("========獲取成員構造方法資訊結束============");
	    }

測試類如下:
public class TestReflection {
	public static void main(String[] args) {
//        ReflectDemo1 rd=new ReflectDemo1();
        Person person = new Person();
        ReflectDemo2 reflectDemo2 = new ReflectDemo2(person);
    }
}
結果跟上面的輸出結果一樣

========獲取方法資訊============
public java.lang.String com.test.Reflect.Person.toString()
private java.lang.String com.test.Reflect.Person.getName()
private void com.test.Reflect.Person.setName(java.lang.String)
public java.lang.String com.test.Reflect.Person.getGender()
public void com.test.Reflect.Person.setGender(java.lang.String)
public int com.test.Reflect.Person.getAge()
public void com.test.Reflect.Person.setAge(int)
========獲取出方法資訊結束============
========獲取成員屬性資訊============
private java.lang.String com.test.Reflect.Person.name
private java.lang.String com.test.Reflect.Person.gender
private int com.test.Reflect.Person.age
========獲取成員屬性資訊結束============
========獲取成員構造方法資訊============
com.test.Reflect.Person()
public com.test.Reflect.Person(java.lang.String,java.lang.String,int)
========獲取成員構造方法資訊結束============

第三種方式就是直接使用.class屬性

只需要直接將類名.class賦值給Class cla,就可以繼續向上面一樣輸出類的資訊了。這裡就不贅述了。

Class cla=Person.class;

畢竟會使用只是最簡單的要求,理解其使用的環境才會是自己可以靈活的使用。之後如果有更深的體會再進行補充。