類的調用(調用類中的成員)
★ 構造類對象
使用構造器新建對象。根據指定的參數類型找到相應的構造函數,傳入相應參數調用執行,以創建一個新的對象實例。
★ 調用方法
根據方法名稱執行方法。根據方法名與參數類型匹配指定的方法,傳入相應參數與對象進行調用執行。若是靜態方法,則不需傳入具體對象。
★ 獲取與設置屬性值
根據屬性名稱讀取與修改屬性的值,訪問非靜態屬性需傳入對象爲參數。
代碼示例:
package cn.hncu.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
/*
一道面試題:創建(獲得)一個類對象有幾種方式?
new, 克隆 , 反序列化, 類反射
*/
public class ReflectOperateObj {
//private static final String className="cn.hncu.reflect.Student";
private static final String className="cn.hncu.reflect.Person";
@Test//使用構造器新建對象,最核心的代碼: Constructor con= c.getConstructor(paramTypes); con.newInstance(args);
public void operateConstructor(){
try {
//Person p = new Person(); //寫死了
Class c = Class.forName(className);
//1空參構造方法
//簡便方式new一個空參對象
Object obj = c.newInstance();//選用空參構造方法新建一個對象
System.out.println(obj);
//常規方式:先拿到對應構造器的對象,然後利用該構造器對象(代表那個構造函數)調用newInstance()方法造出對象
Constructor con = c.getConstructor(null);//獲取空參構造方法
Object obj2 = con.newInstance(null);
System.out.println(obj2);
//2 非空參構造方法
//只能常規方法:必須先通過形參獲得對應的構造方法,然後通過實參調用該構造方法
//public Person(String name, int age)
//Person p = new Person("Jack",22);
//2.1獲取指定的構造器--通過形參
Class parameterTypes[] = new Class[2];
parameterTypes[0] = String.class;
parameterTypes[1] = Integer.TYPE;
Constructor con2= c.getConstructor(parameterTypes);
//2.2調用該構造器來new對象---通過實參
Object params[] = new Object[2];//調用構造方法是要傳入的參數
params[0]=new String("Jack");
params[1]=new Integer(24);
Object obj3 = con2.newInstance(params);
System.out.println(obj3);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test//調用普通方法---最核心的代碼: Method m = c.getMethod(name,paramTypes); m.invoke(obj,args);
public void callMethod(){
try {
Class c = Class.forName(className);
//1調用空參方法---Person p = new Person(); p.toString();
//1.1先獲得該Method對象---通過形參
Method m = c.getMethod("toString", null);
//1.2再讓該Method對象執行---通過實參
Object p = c.newInstance();
Object returnValue = m.invoke(p, null);//執行方法---p.toString()
System.out.println(">>>> "+ returnValue);
System.out.println("----------------");
//2調用非空參方法
//2.1先獲得該Method對象---通過形參
Class parameterTypes[] = new Class[2];
parameterTypes[0] = int.class;//參數類型爲int--OK
//parameterTypes[0] = Integer.TYPE;//參數類型爲int--OK
//下句小細節:因爲這是一個純粹的類,裏面沒有拆箱功能,無法當作int類型。但如果sum()中的第一個參數就是Integer類型,那麼下句OK
//parameterTypes[0] = Integer.class;//參數類型爲int--ERROR
parameterTypes[1] = int.class;
Method m2 = c.getDeclaredMethod("sum", parameterTypes);
//2.2再讓該Method對象執行---通過實參 p.sum(100,200);
Object p2 = c.newInstance();
Object args[] = new Object[2];
args[0] = 1;
args[1] =100;
Object res = m2.invoke(p2, args);
System.out.println("res: " + res);
//3 調用靜態方法
Method m3 = c.getMethod("aa", null);
m3.invoke(null, null);//靜態方法的調用不需要對象,類名可以省略,所以傳入null就行。至於方法的實參,同前
} catch (Exception e) {
e.printStackTrace();
}
}
@Test//訪問屬性(成員變量、類變量)----最核心代碼: Field fld = c.getFild(name); 專用setter-getter方法:fld.setDouble(p,value);fld.getDouble(p) 通用setter-getter方法:fld.set(p,value);fld.get(p)
//Person p = new Person(); p.value=11.22;
public void AccessField(){
try {
Class c = Class.forName(className);
//獲取Field對象
Field fld = c.getField("value");
//操縱該Field對象,以進行讀寫屬性值
Object p = c.newInstance();
//通用的setter-getter方法
//fld.set(p,11.22);//設置值
//double x = (Double)fld.get(p) + 100;//獲取值
//專用的setter-getter方法
fld.setDouble(p, 22.33);
double x = fld.getDouble(p) + 100;//獲取值
System.out.println(x);
} catch (Exception e) {
e.printStackTrace();
}
}
//暴力訪問---訪問類中的私有成員(構造器、普通方法、屬性)---這三者的公共父類AccessibleObject中的方法setAccessible(boolean flag)可以打開私有訪問權限
@Test//強行訪問私有方法: private int sum(int n)
public void AccessBlood(){
try {
Class c = Class.forName(className);
Method m = c.getDeclaredMethod("sum", int.class);
m.setAccessible(true);//暴力訪問,打開訪問權限。---其實是調用父類AccessibleObject中的該方法
Object res = m.invoke(c.newInstance(), 100);
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
}