Java註解和反射04:Class物件的使用
阿新 • • 發佈:2022-05-20
Java註解和反射04:Class物件的使用
有了Class物件,能做什麼
- 建立類的物件:呼叫Class物件的newInstance()方法
- 類必須有一個無參的構造器
- 類的構造器的 訪問許可權需要足夠
- 步驟如下:
- 通過Class類的getDeclaredConstructor(Class ... parameterTypes)取得本類的指定形參型別的構造器
- 向構造器的形參中傳遞一個物件陣列進去,裡面包含了構造器中所有的各個引數
- 通過Constructor例項化物件
呼叫指定的方法
通過反射,呼叫類中的方法,通過Method類完成
- 通過Class類的getMethod(String name,Class...parameterTypes)方法取得一個Method物件,並設定此方法操作時所需要的引數型別
- 之後使用Object invoke(Object obj,Object[] args)進行呼叫,並向方法中傳遞要設定的obj物件的引數資訊
package com.lurenj.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //動態的建立物件,通過反射 public class Test09 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //獲得Class物件 Class c1 = Class.forName("com.lurenj.reflection.User"); //構造一個物件 User user = (User) c1.newInstance();//本質是呼叫了類的無參構造器 System.out.println(user);//User{name='null', id=0, age=0} //通過構造器建立物件 Constructor constructor = c1.getConstructor(String.class, int.class, int.class); User user2 = (User) constructor.newInstance("lurenj", 001, 18); System.out.println(user2);//User{name='lurenj', id=1, age=18} //通過反射呼叫普通方法 User user3 = (User) c1.newInstance(); //通過反射獲取一個方法 Method setName = c1.getDeclaredMethod("setName", String.class); //invoke:啟用的意思 //(物件,”方法的值“) setName.invoke(user3,"lurenj"); System.out.println(user3.getName());//lurenj //通過反射操作屬性 System.out.println("=========================="); User user4 = (User) c1.newInstance(); Field name = c1.getDeclaredField("name"); //不能直接操作私有屬性,我們需要關閉程式的安全檢測,屬性或者方法的setAccessible(true) name.setAccessible(true);//取消安全檢測 name.set(user4,"lurenj"); System.out.println(user4.getName());//lurenj } }
setAccessible
- Method和Field、Constructor物件都有setAccessible()方法
- setAccessible作用是啟動和禁用訪問安全檢查的開關
- 引數值為true則指示反射的物件在使用時應該取消Java語言訪問檢查
- 提高反射的效率。如果程式碼中必須用反射,而該句程式碼需要頻繁的被呼叫,那麼請設定為true
- 使得原本無法訪問的私有成員也可以訪問
- 引數值為false則指示反射的物件應該實施Java語言的訪問檢查
package com.lurenj.reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //分析效能問題 public class Test10 { //普通方式呼叫 public static void test01() { User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方式執行10E次:" + (endTime - startTime) + "ms"); } //反射方式呼叫 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式執行10E次:" + (endTime - startTime) + "ms"); } //反射方式呼叫 關閉檢測 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式關閉檢測執行10E次:" + (endTime - startTime) + "ms"); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test01();//普通方式執行10E次:4ms test02();//反射方式執行10E次:1507ms test03();//反射方式關閉檢測執行10E次:978ms } }
反射操作泛型
- Java採用泛型擦除的機制來引入泛型,Java中的泛型僅僅是給編譯器javac使用的,確保資料的安全性和免去強制型別轉換問題,但是,一旦編譯完成,所有和泛型有關的型別全部擦除
- 為了通過反射操作這些型別,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType幾種型別來代表不能被歸一到Class型別但是又和原始型別齊名的型別
- ParameterizedType:表示一種引數化型別,比如Collection
- GenericArrayType:表示一種元素型別是引數化型別或者型別變數的陣列型別
- TypeVariable:是各種型別變數的公共父介面
- WildcardType:代表一種萬用字元型別表示式
package com.lurenj.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//通過反射獲取泛型
public class Test11 {
public void test01(Map<String,User> map, List<User> list){
}
public Map<String,User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test11.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("#" + genericParameterType);
if (genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
method = Test11.class.getMethod("test02",null);
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
反射操作註解
- getAnnotations
- getAnnotation
package com.lurenj.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
//練習反射操作註解
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.lurenj.reflection.Student2");
//通過反射獲得註解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//獲取註解的value值
Tablelurenj tablelurenj = (Tablelurenj) c1.getAnnotation(Tablelurenj.class);
String value = tablelurenj.value();
System.out.println(value);
//獲得類指定的註解
Field f = c1.getDeclaredField("id");
Filedlurenj annotation = f.getAnnotation(Filedlurenj.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@Tablelurenj("db_student")
class Student2{
@Filedlurenj(columnName = "db_id",type = "int",length = 10)
private int id;
@Filedlurenj(columnName = "db_age",type = "int",length = 10)
private int age;
@Filedlurenj(columnName = "db_name",type = "varchar",length = 10)
private String name;
public Student2() {
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public void setId(int id) {
this.id = id;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//類名的註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablelurenj{
String value();
}
//屬性的註解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Filedlurenj{
String columnName();
String type();
int length();
}