Java之註解和反射

什麼是註解

  • Annotation是JDK5.0引入的技術
  • Annonation的作用:
    • Annonation不是程序本身,可以對程序作出解釋
    • 可以被其他程序(比如編譯器等)讀取
  • Annotation的格式
    • @SuppressWarings(value=“unchecked”)
  • Annotation在哪裏使用
    • 可以附加在package class method field等上面,相當於給他們添加了額外的輔助信息,我們可以通過反射機制編程實現對這些元數據的訪問
/**
 * @Description: 什麼是註解
 * @Date: 2020-05-20 23:25
 **/
public class Test01 extends Object{
   //Override是一個註解
    @Override
    public String toString() {
        return super.toString();
    }
}

元註解

  • 元註解的作用是負責註解其他註解的註解,Java定義了四個標準的meta-annotation類型,他們被用來提供對其他annotation類型作說明。
  • 這些類型和他們所支持的類在java.lang.annotation中可以找到
    • @Target 用於描述註解的使用範圍(即被描述的註解可以用在什麼地方)
    • @Retention 表示需要在什麼級別保存該註釋信息,用於描述註解的生命週期(SOURCE<CLASS<RUNTIME
    • @Documented 說明該註解將被包含在javadoc中
    • @Inherited 說明子類可以繼承父類中的該註解
/**
 * @Description: 測試元註解
 * @Date: 2020-05-21 09:43
 **/
@MyAnnotation
public class Test02 {

    @MyAnnotation
    public void test() {

    }
}

//定義一個註解
//Target表示註解用在什麼地方
@Target(value = {ElementType.METHOD, ElementType.TYPE})
//Retention表示註解在什麼是你有效 SOURCE<CLASS<RUNTIME
@Retention(value = RetentionPolicy.RUNTIME)
//Document表示是否將註解生成在Javadoc中
@Documented
//Inherited可以被子類繼承
@Inherited
@interface MyAnnotation {
}

自定義註解

  • 使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation接口
  • 分析
    • @interface用來聲明一個註解,格式:public @interface 註解名{定義內容}
    • 其中每一個方法實際上是聲明瞭一個配置參數
    • 方法的名稱就是參數的名稱
    • 返回值類型就是參數的類型(返回值只能是基本類型 Class Stirng enum)
    • 可以通過default來聲明參數的默認值
    • 如果只有一個參數成員,一般參數名是value
    • 註解元素必須要有值,我們定義註解元素時,經常使用空字符串,0作爲默認值
/**
 * @Description: 自定義註解
 * @Date: 2020-05-21 10:19
 **/
public class Test03 {
    //註解可以顯式賦值 沒默認值的時候必須顯式賦值
    @MyAnnotation02(name = "XXX", schools = {"DUT","USTC"})
    public void test() {

    }
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation02 {
    //註解的參數 參數類型+參數名();
    String name() default "";

    int age() default 0;

    int id() default -1;//如果默認值爲-1 代表不存在

    String[] schools() default "家裏蹲";
}

反射機制

Reflection是Java被視爲準動態語言的關鍵,反射機制允許程序在執行期藉助於Reflection API取得任何類的內部信息,並能直接操作任意對象的內部屬性及方法。
加載完類之後,在堆內存的方法區中就產生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結構信息。我們可以通過這個對象看到類的結構。

正常方式:引入需要的包類名稱–>通過new實例化–>取得實例化對象
反射方式:實例化對象–>getClass()方法–>得到完整的包類名稱

反射機制的應用

  • 在運行時判斷任意一個對象所屬的類
  • 在運行時構造任意一個類的對象
  • 在運行時判斷任意一個類所具有的成員變量和方法
  • 在運行時獲取泛型信息
  • 在運行時調用任意一個對象的成員變量和方法
  • 在運行時處理註解
  • 生成動態代理
public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //通過反射獲取類的Class對象
        Class c1 = Class.forName("com.wang.reflection.User");
        Class c2 = Class.forName("com.wang.reflection.User");
        //一個類在內存中只有一個Class對象
        //一個類被加載後,類的整個結構都會被封裝在Class對象中
        System.out.println(c1.hashCode()); //1639705018
        System.out.println(c2.hashCode()); //1639705018
    }
}

//實體類 pojo entity
class User {
    private String name;
    private int id;
    private int age;

    public User() {
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}
/**
 * @Description: 測試Class類的創建方式有哪些
 * @Date: 2020-05-21 11:13
 **/
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println(person.name);  //Student

        //方式一 通過對象獲得
        Class c1 = person.getClass();

        //方式二 forName獲得
        Class c2 = Class.forName("com.wang.reflection.Student");

        System.out.println(c1.hashCode());  //1639705018
        System.out.println(c2.hashCode());  //1639705018

        //方式三 通過類名.class獲得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());  //1639705018

        //方式四 基本內置類型的包裝類都有一個Type屬性
        Class c4 = Integer.TYPE;

        //獲得父類的類型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);
    }
}

class Person {
    String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }
}

class Student extends Person {
    public Student() {
        this.name = "Student";
    }
}

class Teacher extends Person {
    public Teacher() {
        this.name = "Teacher";
    }
}
/**
 * @Description: 所有類型的Class
 * @Date: 2020-05-21 11:39
 **/
public class Test04 {
    public static void main(String[] args) {
        Class c1 = Object.class;//類
        Class c2 = Comparable.class;//接口
        Class c3 = String[].class;//一維數組
        Class c4 = int[][].class;//二維數組
        Class c5 = Override.class;//註解
        Class c6 = ElementType.class;//枚舉
        Class c7 = Integer.class;//基本數據類型包裝類
        Class c8 = int.class;//基本數據類型
        Class c9 = void.class;//void
        Class c10 = Class.class;//Class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);
        System.out.println(c10);

    }
}

Java內存
類的加載過程
類的加載預ClassLoader的理解:

  • 加載:將class文件字節碼內容加載到內存中,並將這些靜態數據轉換成方法區的運行時數據結構,然後生成一個代表這個類的java.lang.Class對象
  • 鏈接:將Java類的二進制代碼合併到JVM運行狀態之中的過程
    • 驗證:確保加載的類信息符合JVM規範,沒有安全方面的問題
    • 準備:正式爲類變量(static)分配內存並設置類變量默認初始值的階段,這些內存都將在方法區中進行分配
    • 解析:虛擬機常量池內的符號引用(常量名)替換爲直接引用(地址)的過程
  • 初始化:
    • 執行類構造器()方法的過程。類構造器()方法是由編譯器自動收集類中所有類變量的賦值動作和靜態代碼塊中的語句合併產生的。(類構造器是構造類信息的,不是構造該類對象的構造器)
    • 當初始化一個類的時候,如果發現其父類還沒有進行初始化,則需要先觸發其父類的初始化
    • 虛擬機會保證一個類的()方法在多線程環境中被正確加鎖和同步
public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException {
        //獲取系統類的加載器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader); //sun.misc.Launcher$AppClassLoader

        //獲取系統類加載器的父類加載器->擴展類加載器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent); //sun.misc.Launcher$ExtClassLoader

        //獲取擴展類加載器的父類加載器-->根加載器(C/C++)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1); //null

        ClassLoader classLoader = Class.forName("com.wang.reflection.Student").getClassLoader();
        System.out.println(classLoader); //sun.misc.Launcher$AppClassLoader

        classLoader = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader); //jdk內部類是根加載器加載 null

        //如何獲得系統類加載器可以加載的路徑
        String property = System.getProperty("java.class.path");
        System.out.println(property);
        /*
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/charsets.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/deploy.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/dnsns.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jaccess.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/localedata.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/nashorn.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunec.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/zipfs.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/javaws.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jce.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfr.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfxswt.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jsse.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/management-agent.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/plugin.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/resources.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/rt.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/ant-javafx.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/dt.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/javafx-mx.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/jconsole.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/packager.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/sa-jdi.jar:
        /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/tools.jar:
        /Users/wangyinghao/Projects/IdeaProjects/coding-practise/out/production/kuangshen-annotation-study:
        /Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
         */

        //雙親委派機制
    }
}
/**
 * @Description: 獲得類的信息
 * @Date: 2020-05-21 21:40
 **/
public class Test08 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c1 = Class.forName("com.wang.reflection.User");

        //獲得類的名字
        System.out.println(c1.getName()); //獲得包名+類名 com.wang.reflection.User
        System.out.println(c1.getSimpleName());//獲得類名 User

        //獲得類的屬性
        System.out.println("===============");
        Field[] fields = c1.getFields(); //獲取public的屬性
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("===============");
        fields = c1.getDeclaredFields();//找到全部屬性
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("===============");
        //獲得類的方法
        Method[] methods = c1.getMethods(); //獲得本類及其父類的全部public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        methods = c1.getDeclaredMethods(); //獲得本類的所有方法
        for (Method method : methods) {
            System.out.println(method);
        }

        //獲得指定方法
        //重載
        Method getName = c1.getMethod("getName");
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        Constructor[] constructors = c1.getConstructors();
        constructors = c1.getDeclaredConstructors();

        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
    }
}
/**
 * @Description: 通過反射動態創建對象
 * @Author: wangyinghao_sx
 * @Date: 2020-05-21 22:20
 **/
public class Test09 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class<?> c1 = Class.forName("com.wang.reflection.User");

        //構造一個對象
        User user = (User) c1.newInstance(); //本質是調用了類的無參構造

        //通過構造器創建對象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user1 = (User) constructor.newInstance("A", 10, 10);

        //通過反射調用普通方法
        User user2 = (User) c1.newInstance();
        //通過反射獲取一個方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user2, "B");
        System.out.println(user2.getName());

        //通過反射操作屬性
        User user3 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有屬性 需要關閉程序的安全檢測 name.setAccessible(true);
        name.setAccessible(true);
        name.set(user3, "C");
        System.out.println(user3.getName());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章