Java基礎(四):java反射機制

NO IMAGE

反射是什麼

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠獲取這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取類信息以及動態調用對象內容就稱為java語言的反射機制。【翻譯於 官方文檔】

反射的作用

  • 在運行時判斷任意一個對象所屬的類;
  • 在運行時構造任意一個類的對象;
  • 在運行時判斷任意一個類所具有的成員變量和方法;
  • 在運行時調用任意一個對象的方法;

new和反射創建的區別

從結果來說沒有區別。

new:靜態編譯,只能用於編譯期就能確定的類型,而且需要import相應的包。

反射:動態編譯,在運行時可以確定類型並創建其對象,能夠實現一些更為動態的效果。

反射的實現

我們知道,要使用一個類,就要先把它加載到虛擬機中,生成一個Class對象。這個class對象就保存了這個類的一切信息。 反射機制的實現,就是獲取這個Class對象,通過Class對象去訪問類、對象的元數據以及運行時的數據。有三種方法獲得類的Class對象:

  • Class.forName(String className)
  • className.class
  • 實例對象.getClass()

什麼是class類

在面向對象的世界裡,萬物皆對象。類是對象,類是java.lang.Class類的實例對象。另外class類只有java虛擬機才能new出來,任何一個類都是Class 類的實例對象,這實例對象有三種表達方式:

public class Person {
}
public class PersonClassTest {
public static void main(String[] args) {
try {
Person p = new Person();
//方式1
Class p1 = Person.class;
//方式2
Class p2 = p.getClass();
//方式3
Class p3 = Class.forName("com.java.xiaoxin.Person");
//可以通過類的類型創建該類的實例對象
Person person = (Person) p1.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}

反射涉及的API

反射首先獲取Class對象;然後獲取Method類和Field類;最後通過Method和Field類進行具體的方法調用或屬性訪問。

1.在運行時獲取對象所屬類的類名等信息
對象名.getClass().getName();
public class PersonClassTest {
public static void main(String[] args) {
String name = Person.class.getName();
System.out.println(name);//com.java.xiaoxin.Person
}
}
2.在運行時,通過創建class對象,獲取自己的父類信息
 Class<?> clazz = Class.forName(當前類);
Class<?> parentClass = clazz.getSuperclass();
parentClass.getName();//獲得父類名
public class PersonClassTest {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("com.java.xiaoxin.Person");
Class<?> parentClass = clazz.getSuperclass();
parentClass.getName();
System.out.println(parentClass.getName());//java.lang.Object
}catch (Exception e){
e.printStackTrace();
}
}
}
3.通過反射機制創建一個類的對象
1:反射創建class對象
2:Classname 對象=classname.newInstance(參數);
public class PersonClassTest {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.java.xiaoxin.Person");
Person person = (Person) clazz.newInstance();
}catch (Exception e){
e.printStackTrace();
}
}
}
4.獲取類的全部方法,存於一個數組中
//創建class對象
Class<?> clazz = Class.forName(ClassName);
// 返回聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 
Method[] method1 = clazz.getDeclaredMethods();
//返回可被訪問的公共方法      
Method[] method2 = clazz.getMethods();
public class PersonClassTest {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.java.xiaoxin.Person");
/**
* 一個成員方法就是一個method對象
* getMethod()所有的 public方法,包括父類繼承的 public
* getDeclaredMethods()獲取該類所有的方法,包括private ,但不包括繼承的方法。
*/
Method[] methods = clazz.getMethods();//獲取方法
//獲取所以的方法,包括private ,c.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
//得到方法的返回類型
Class returnType = methods[i].getReturnType();
System.out.print(returnType.getName());
//得到方法名:
System.out.print(methods[i].getName() + "(");
Class[] parameterTypes = methods[i].getParameterTypes();
for (Class class1 : parameterTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

輸出:

voidwait()
voidwait(long,int,)
voidwait(long,)
booleanequals(java.lang.Object,)
java.lang.StringtoString()
inthashCode()
java.lang.ClassgetClass()
voidnotify()
voidnotifyAll()
5.獲取類的全部字段,存於一個數組中
Class<?> clazz = Class.forName(classname);
// 取得本類已聲明的所有字段,包括私有的、保護的
Field[] field = clazz.getDeclaredFields();
// 取得本類中可訪問的所有公共字段
Field[] filed1 = clazz.getFields();
public class Person {
private String name;
public int age;
}
public class PersonClassTest {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.java.xiaoxin.Person");
Field[] field = clazz.getDeclaredFields();
Field[] filed1 = clazz.getFields();
for(Field f:field){
//獲取成員變量的類型
Class filedType=f.getType();
System.out.println(filedType.getName()+"-->"+f.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

輸出:

java.lang.String-->name
int-->age
6.方法反射的操作

獲取一個方法:需要獲取方法的名稱和方法的參數才能決定一個方法。

方法的反射操作:

method.invoke(對象,參數列表);
public class Person {
private String name;
public int age;
public void say(String name,int age){
System.out.print(name+"今年"+age+"歲");
}
}
public class PersonClassTest {
public static void main(String[] args) {
try {
Person person=new Person();
Class clazz=person.getClass();
Method method=clazz.getMethod("say",new Class[]{String.class,int.class});
//也可以 Method method=c.getMethod("add",String.class,int.class);
//方法的反射操作
method.invoke(person,"小新",18);
} catch (Exception e) {
e.printStackTrace();
}
}
}

輸出:

小新今年18歲

參考資料

www.cnblogs.com/huangdabing…

www.fangzhipeng.com/javaintervi…

相關文章

關於import和require的一點理解

我的前端知識梳理VUE篇

基礎知識梳理~ES6解構賦值

Vue.js命名風格指南