Java之註解與反射

Java之註解與反射

註解(Annotation)簡介

註解(Annotation)是從JDK5.0引入的新技術

Annotation作用:註解(Annotation)可以被其他程序如編譯器等讀取

Annotation格式:@"註釋名",當然可以添加一些參數值(形如:@Retention(RetentionPolicy.RUNTIME)

它是JDK1.5及以後版本引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,註釋。

Annotation註解可以通過反射去讀取

註解的定義

內置註解

@Override 定義在java.lang.Override中,此註釋只適用於修辭方法,表示聲明一個方法打算重寫超類中的另一個方法。

@Deprecated定義在java.lang.Deprecated中,此註釋只適用於修辭方法,屬性,類,表示不支持使用這樣的元素

@SupperWarnings定義在java.lang.SupperWarnings中,用來抑制編譯告警時的警告信息,需要添加一個參數才能正確使用

元註解

元註解的作用就是負責註解其他註解,java定義了4個標準的meta-annotation類型:@Target/@Retention/@Document/@Inherited

元註解中重點爲@Target@Retention

@Target:用於描述註解的作用範圍(比如作用在某個類或某個方法)

@Retention:描述註解的生命週期,對於反射就是可以在什麼時候獲取該註解(SOURCE<CLASS<RUNTIME

自定義註解

使用@interface可以自定義註解。

@interface 註解名{
		//自定義的註解內容
    //如果參數只有一個值,建議寫value
    String value();
}

例子

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class TestAnnotationDemo3 {

    //測試自定義註解
    @MyAnnotation2("qifei")
    @MyAnnotation(name = "wuhu", id = 10)
    public void test(){
        System.out.println("test");
    }
}

@Target(value = {ElementType.TYPE,ElementType.METHOD})  //作用於 方法和類
@Retention(RetentionPolicy.RUNTIME)    //作用於 運行時
@interface MyAnnotation{
    //定義參數
    String[] name() default ""; //參數默認爲空,參數名爲name
    int id();
}

@Target(value = {ElementType.TYPE,ElementType.METHOD})  //作用於 方法和類
@Retention(RetentionPolicy.RUNTIME)    //作用於 運行時
@interface MyAnnotation2{
    //如果參數只有一個值,建議寫value
    String value();
}

反射(Reflection)機制

Java反射(Reflection)是Java非常重要的動態特性,通過使用反射我們不僅可以獲取到任何類的成員方法、成員變量、構造方法等信息,還可以動態創建Java類實例、調用任意的類方法、修改任意的類成員變量值等。註解和反射是各種java web框架的底層實現機制與靈魂。

Class類

反射首先要用到的就是Class類,Class類是一個描述類的類,但是Class本身也是一個類,一個在內存中加載的類在JVM中只會有一個對應的Class的實例話對象,通過Class可以完整的得到一個類中所有被加載的結構。Class類就是反射的根源

獲取Class類實例

1、已知具體的類,通過類的class屬性獲取

Class c = Object.class;

2、已知某個類的實例,通過調用getClass()方法獲取class對象

Person person = new Person();
Class c = person.getClass();

3、已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName()獲取class對象

Class c = Class.forName("com.reflection.demmo");

4、基本內置類型的包裝類的Type屬性獲取class對象

Class c = Integer.TYPE;

例子:

//測試class類的創建方式
public class ReflactionDemo02 {

    public static void main(String[] args) throws ClassNotFoundException {
        Person student = new Student();
        System.out.println("這個人是:" + student.name);

        //獲取Student類的class實例對象
        //1、通過getClass() 獲得
        Class c1 = student.getClass();
        System.out.println(c1.hashCode());

        //2、通過Class類的forName() 獲得
        Class c2 = Class.forName("com.reflaction.Student");
        System.out.println(c2.hashCode());

        //3、通過student類的class屬性獲得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());

        //4、基本內置類型的包裝類的Type屬性
        Class c4 = Integer.TYPE;
        System.out.println(c4.hashCode());

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

    }

}

class Person{
    String name;

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

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

class Teacher extends Person{
    public Teacher(){
        this.name = "老師";
    }
}

這個人是:學生
1627674070
1627674070
1627674070
1360875712
class com.reflaction.Person

具有Class實例對象的數據類型

//所有類型的class對象
public class ReflactionDemo03 {
    public static void main(String[] args) {
        Class c1 = Object.class;    //類
        Class c2 = Runnable.class;  //接口
        Class c3 = String[].class;  //一維數組
        Class c4 = String[][].class;    //二維數組
        Class c5 = Override.class;  //註解
        Class c6 = ElementType.class;   //枚舉
        Class c7 = Integer.class;   //基本數據類型包裝類
        Class c8 = void.class;  //void
        Class c9 = 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);

    }
}
class java.lang.Object
interface java.lang.Runnable
class [Ljava.lang.String;
class [[Ljava.lang.String;
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class

反射獲取類運行時的完整結構

Field()

Field[] fields = c1.getFields();    //getFields 只能找到pubilc屬性
        fields = c1.getDeclaredFields();    //getDeclaredFields 可以找到所有屬性
        for (Field field : fields) {
            System.out.println(field);
        }

Method()

getMethods()獲得本類和繼承類的所有public方法

getDeclaredMethods()獲取本類的所有方法

getMethod("方法名", 參數類型.class)獲得指定的方法

//獲得本類和繼承類的所有public方法
        Method[] methods = c1.getMethods(); 
        for (Method method : methods
             ) {
            System.out.println("getMethods(): " + method);
        }
        
//獲取本類的所有方法
        methods = c1.getDeclaredMethods();  
        for (Method method : methods
             ) {
            System.out.println("getDeclaredMethods(): " + method);
        }
 //獲得指定的方法
        Method setName = c1.getMethod("setName", String.class);
        Method getName = c1.getMethod("getName");

        System.out.println(setName);
        System.out.println(getName);

Constructor()

//獲取所有的構造器
        Constructor[] constructors = c1.getConstructors();      //獲取本類和父類的所有構造方法
        for (Constructor constructor : constructors
             ) {
            System.out.println(constructor);
        }
        System.out.println("=====================================");
        constructors = c1.getDeclaredConstructors();        //獲取本類所有構造方法

        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println("=====================================");
        //獲取指定的構造器
        Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
        System.out.println(constructor);

反射類構造器獲得實例化對象

  1. 反射獲得User類的class對象Class.forName()
  2. 調用有參或無參構造方法實例化對象class.newInstance()
public static void main(String[] args) throws Exception{
        //反射獲得User類的class對象
        Class c1 = Class.forName("com.reflaction.User");
        User user = (User) c1.newInstance();            //調用無參構造實例化對象
        System.out.println(user);

        //獲得有參構造方法
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);

        //通過構造器獲得實例話對象
        User ago = (User) constructor.newInstance("ago", 18, 1);    //有參構造獲得實例化對象
        System.out.println(ago);


    }

User{name='null', age=0, id=0}
User{name='ago', age=18, id=1}

反射獲取調用普通方法

方式1: 反射獲取目標類的class對象(Class.forName()) ==> 獲取有參構造器(class.getDeclaredConstructor()) ==> 獲取目標類實例化對象(constructor1.newInstance(param1, param2, param3 ,...)) ==> 調用方法(實例化對象.Method())


        Class c2 = Class.forName("com.reflaction.User");
        Constructor constructor1 = c2.getDeclaredConstructor(String.class, int.class, int.class);
        User zh1z3ven = (User) constructor1.newInstance("zh1z3ven", 20, 2);
        System.out.println(zh1z3ven.getAge());
        System.out.println(zh1z3ven.getName());
				zh1z3ven.setId(20);
        System.out.println(zh1z3ven.getId());

方式2: 反射獲取目標類class對象(Class.forName()) ==> 獲取指定方法(class.getMethod("方法名", 參數)) ==> 激活執行方法(.invoke(目標對象, 參數))

				Class c2 = Class.forName("com.reflaction.User");

        User user2 = (User) c2.newInstance();
        Method setName = c2.getMethod("setName", String.class);
        setName.invoke(user2, "kfei");
        System.out.println(user2.getName());

反射操作屬性

  1. 獲取class對象
  2. class.getDeclaredField("屬性名") 獲取屬性
  3. .set() 方法設置屬性
  4. 若爲private修飾,出現無權限操作異常,可用.setAccessible(true) 關閉安全檢測,獲取操作權限
				Class c3 = Class.forName("com.reflaction.User");
        User user4 = (User) c3.newInstance();

        Field name = c3.getDeclaredField("name");

        name.setAccessible(true);
        name.set(user4 ,"zgo");
        System.out.println(user4.getName());

Invoke(Object obj, Obj... args)

Object對應原方法返回值,若無返回值,返回null

若原方法爲靜態方法,形參Object obj可爲null

若原方法形參列表爲空,Obj... args可爲null

若原方法聲明爲private,在調用invoke()前,顯示調用方法對象的.setAccessible(true)方法,關閉安全檢測,獲取訪問權限

反射調用Runtime()

import org.apache.commons.io.IOUtils;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class RuntimeExecDemo {
    public static void main(String[] args) throws Exception{

        String command = "ifconfig";
        Class c = Class.forName("java.lang.Runtime");   //獲取Runtime類的class對象
        Constructor constructor = c.getDeclaredConstructor();   //獲取構造器
        constructor.setAccessible(true);   //關閉安全檢測,暴力反射
        Object runtime = constructor.newInstance();     //構造runtime對象
        Method exec = c.getMethod("exec", String.class);    //獲取exec方法
        Process process = (Process) exec.invoke(runtime, command);  //激活執行exec

        //獲取命令回顯結果
        InputStream inputStream = process.getInputStream();     //獲取process輸入流中輸出的數據
        String ifconfig = IOUtils.toString(inputStream, "GBK");     //字節流轉字符流
        System.out.println(ifconfig);      //打印結果


    }
}

反射操作泛型

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 TestFanXingDemo {

    public void test01(Map<String, User> map, List<User> list){
        System.out.println("test01");
    }

    public Map<String, User> test02(){
        System.out.println("test02");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {

        Method method = TestFanXingDemo.class.getMethod("test01", Map.class, List.class);
        method.setAccessible(true);     //關閉安全檢測,暴力反射
        Type[] genericParameterTypes = method.getGenericParameterTypes();   //獲得泛型的參數類型

        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("#genericParameterType: " + genericParameterType);   //遍歷泛型類型

            if (genericParameterType instanceof ParameterizedType){     //判斷泛型參數類型是否是參數化類型
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();   //獲得真實參數信息
                
                //循環遍歷參數
                for (Type actualTypeArgument : actualTypeArguments) {       
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }
    
}

反射操作註解

ORM = Object Relationship Mapping ==> 對象關係映射

類和表對應,類的屬性和表的字段對應,對象和記錄對應

利用註解和反射完成類和表的結構的映射關係

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class TestDemo12 {

    //反射操作註解
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.reflaction.Student2");

        //通過反射獲得全部註解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //獲得註解的value值
        TableStudent tableStudent = (TableStudent) c1.getAnnotation(TableStudent.class);
        String value = tableStudent.value();//獲取註解的value
        System.out.println(value);

        //獲取指定類的註解value
        Field f = c1.getDeclaredField("name");
        FieldStudent annotation = f.getAnnotation(FieldStudent.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());

    }

}

@TableStudent("db_student")
class Student2{
    @FieldStudent(columnName = "db_id", type = "int", length = 10)
    private int id;
    @FieldStudent(columnName = "db_age", type = "int", length = 10)
    private int age;
    @FieldStudent(columnName = "db_name", type = "varchar", length = 3)
    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 TableStudent{
    String value();
}

//屬性的註解
@Target(ElementType.FIELD)   //作用範圍爲類
@Retention(RetentionPolicy.RUNTIME)     //作用爲運行時可獲取
@interface FieldStudent{
    String columnName();
    String type();
    int length();
}

結尾

參考文章:
https://www.cnblogs.com/nice0e3/p/13498308.html
https://www.cnblogs.com/nice0e3/p/13494147.html

關於Process類、反射操作泛型和註解因爲暫時剛需不大且還沒研究透,記錄的較少,後面會另出文章記錄一下。

到此JavaSE部分基本就學完了(除了GUI)後面要開JavaWeb和框架了,沖沖衝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章