1. 程式人生 > 其它 >Java註解和反射04:Class物件的使用

Java註解和反射04:Class物件的使用

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();
}