1. 程式人生 > 其它 >反射(4)

反射(4)

java註解和反射

註解

註解(Annotation)

  • 作用
    • 可以對程式作出解釋(和註釋(comment)相同)
    • 可以被其他程式讀取(編譯器等)
  • 格式:@註釋名,還可以新增一些引數值
    • eg:@SuppressWarnings(value="unchecked")
  • 使用範圍:package、class、method、field等,可以通過反射機制程式設計實現對這些元資料的訪問

內建註解

  • @Override:重寫註解
  • @Deprecated:不鼓勵使用的屬性、類(通常是危險的或者有更好的選擇)
  • @SuppressWarnings:抑制編譯時的警告資訊(需要新增一個引數才能正常使用)
    • @SuppressWarnings("all")
    • @SuppressWarnings("unchecked")
    • @SuppressWarnings(value={"unchecked","deprecation})

元註解

負責註解其他註解

  • java的4個標準元註解(meta-annotation)
    • @Target:描述註解的使用範圍
    • @Retention:表示需要在什麼級別儲存註解資訊,用於描述註解的生命週期(SOURCE(原始碼時有效)<CLASS(class檔案有效)<RUNTIME(執行時有效)(一般定義為RUNTIME))
    • @Documented:該直接將被包含到javadoc中(生成文件註釋)
    • @Inherited:子類可以繼承父類中的註解

自定義註解

@interface 註解名{定義內容}

每個方法實際上是聲明瞭一個配置引數

方法的名稱就是引數的名稱

返回值型別就是引數的型別(返回值只能是基本型別Class、String、enum)

可以通過default來宣告引數的預設值,沒有預設值使用時必須給註解賦值

如果只有一個引數成員,一般引數名為value

註解元素必須要有值

public class Demo01 {
    @Annotation(age=18)
    public void text(){

    }
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation{
    String name() default "";
    int age();
}

反射

反射物件

Class類

一個類在記憶體中只有一個Class物件

一個類被載入後,類的整個結構都會被封裝在Class物件中

獲得Class物件

Person person = new Person();
//通過物件獲得
Class c1 = person.getClass();
//forname獲得,需要丟擲異常
Class c2 = Class.forName("路徑名");
//通過類名獲得
Class c3 = Person.class;
//基本內建型別的包裝類都有一個Type屬性
Class c4 = Integer.TYPE;

類的初始化

  • 類的主動引用(一定會發生類的初始化)

    • main方法
    • new一個類
    • 靜態成員和靜態方法
    • 使用java.lang.reflect包的方法對類進行反射呼叫
    • 初始化類時父類沒有被初始化則先初始化父類
  • 類的被動引用(不會發生類的初始化)

    • 訪問靜態域時,只有真正宣告這個域的類才會初始化(通過子類引用父類的靜態變數不會導致子類初始化)
    • 通過陣列定義類的引用,不會觸發此類的初始化
    • 引用常量不會觸發此類的初始化

類載入器

public static void main(String[] args) throws ClassNotFoundException {
        //獲得系統類載入器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
    
        //獲得系統類載入器的父類載入器(拓展類載入器)
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
    
        //獲得拓展類載入器的父類載入器(根載入器,無法直接獲取)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
    
        //獲得指定類是由那個載入器載入的
        ClassLoader classLoader = Class.forName("路徑").getClassLoader();
        System.out.println(classLoader);
    
        //獲得類載入器可以載入的路徑
        System.out.println(System.getProperty("java.class.path"));
}

類的結構

public static void main(String[] args) throws ClassNotFoundException {
        Class<?> aClass = Class.forName("路徑");
    
        //獲得類名
        System.out.println(aClass.getName());//類名+包名
        System.out.println(aClass.getSimpleName());//類名
    
        //獲得類的屬性
        Field[] fields = aClass.getFields();//只能獲得public屬性
        for (Field field : fields) {
            System.out.println(field);
        }
        Field[] declaredFields = aClass.getDeclaredFields();//能獲得所有屬性
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    
        //獲得類的方法
        Method[] methods = aClass.getMethods();//本類及父類所有的public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        Method[] declaredMethods = aClass.getDeclaredMethods();//本類的所有方法
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    
        //獲得構造器
        Constructor<?>[] constructors = aClass.getConstructors();//本類及父類所有的public構造器
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();//本類的構造器
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
}

通過反射來建立物件

public class Demo04 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //獲得class物件
        Class<?> aClass = Class.forName("com.mixian.opp.Demo03");
        
        //建立物件
        Object o = aClass.newInstance();
        System.out.println(o);
        
        //通過構造器建立物件
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class);
        Object mixian = declaredConstructor.newInstance("mixian");
        System.out.println(mixian);
        
        //通過反射呼叫方法
        Method setName = aClass.getDeclaredMethod("setName", String.class);
        setName.invoke(o,"mixian");//啟用
        
        //通過反射操作屬性
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);//私有屬性不能直接操作,需要關閉程式的安全監測
        name.set(o,"mixian");
    }
}

通過反射獲得註解

public class Demo06 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.mixian.opp.Student");
        //通過反射獲得註解
        AnnotatedType[] annotatedInterfaces = aClass.getAnnotatedInterfaces();
        for (AnnotatedType annotatedInterface : annotatedInterfaces) {
            System.out.println(annotatedInterface);
        }
        //獲得類value的值
        xian annotation = aClass.getAnnotation(xian.class);
        String value = annotation.value();
        System.out.println(value);
        //獲得類指定的註解
        Field age = aClass.getDeclaredField("age");
        xian annotation1 = age.getAnnotation(xian.class);
        System.out.println(annotation1.value());
    }
}
@xian("xian")
class Student{
    @xian("xian")
    private String name;
    @xian("xian")
    private int age;
}
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface xian{
    String value();
}