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類
第一個Demo查詢類的資訊並輸出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; } }
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;
畢竟會使用只是最簡單的要求,理解其使用的環境才會是自己可以靈活的使用。之後如果有更深的體會再進行補充。