Java注解與反射 【b站狂神視頻筆記】


概述

Annotation的作用

  • 不是程序本身,可以對程序作出結束(與注釋comment無異)
  • 可以備其他程序(比如編譯器)讀取

Annotation的格式

  • 注解是以 @注釋名 在代碼中存在的,還可以添加一些參數值,例如 @SuppressWarnings(value = “unchecked”)

Annotation在哪里使用?

  • 可以附加在package,class,method,field上面,相當於添加額外的輔助信息,可以通過反射機制編程實現對這些元數據的訪問

內置注解

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

  • @Deprecated 定義在java.lang.Deprecated 中,此注釋可以用於修飾方法、屬性、類,表示不鼓勵程序員使用這樣的元素,通常是因為它很危險或者存在更好的選擇

  • @SuppressWarnings 定義在 java.lang.SuppressWarnings 中,用來抑制編譯時的警告信息,與前兩個有所不同的是需要添加一個參數才能正常使用,這些參數都是定義好的

    @SuppressWarnings("all")
    @SuppressWarnings("unchecked")
    @SuppressWarnings(value = {"unchecked", "deprecation"})
    ...
    

元注解

元注解的作用就是負責注解其他注解,java定義了4個標准的meta-annotation類型,他們被用來提供對其他annotation類型作說明

☆ @Target //用於描述注解的適用范圍
☆ @Retention //表示在什么級別保存該注釋信息,用於描述注解的生命周期(source < class  < RUNTIME)
@Document // 說明該注解將被包含在javadoc中
@Inherited // 說明子類可以繼承父類中的該注解

自定義注解

使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口

分析:

  1. @interface用來聲明一個注解,格式 public @inteface 注解名 { content }
  2. 其中的每一個方法實際上是聲明了一個配置參數
  3. 方法的名稱就是參數的名稱
  4. 返回值類型就是參數的類型(返回值只能是基本類型 class、String、 enum)
  5. 可以通過default來聲明參數的默認值
  6. 如果只有一個參數成員,一般參數名為value
  7. 注解元素必須要有值,我們定義注解元素時,經常使用空字符串、0作為默認值
package com.company.annotation;

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

// 自定義注解
public class test1 {
    // 注解可以顯示賦值 如果沒有默認值,就必須給注解賦值
    @MyAnnotation(name = "oho", age = 19)
    public void test(){

    }
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    // 注解的參數: 參數類型 + 參數名();
    // String value(); 此時上面的引用可以不需要 value = "xxx"
    String name() default "";
    int age() default 0;
    int id() default -1;// 如果默認值為-1,代表不存在

    String[] schoold() default "TshinghuaU";
}

反射機制

image-20210205160302755

image-20210205160611782

package com.company.annotation;

public class reflection {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.company.annotation.User");
        System.out.println(c1);
        Class c2 = Class.forName("com.company.annotation.User");
        Class c3 = Class.forName("com.company.annotation.User");
        Class c4 = Class.forName("com.company.annotation.User");

        // 一個類在內存中只有一個class對象
        // 一個類被加載后,類的整個結構都會被封裝在class對象中
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());

    }
}
// 實體類 : 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 +
                '}';
    }
}


// 運行結果
/*
	class com.company.annotation.User
	284720968
	284720968
	284720968
*/

Class 類

image-20210205161444723

image-20210205161813044

image-20210205161824996

獲取Class類的實例

image-20210205161949703

package com.company.annotation;

public class refClass {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("this is :" + person.name);

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

        // 方式二: forname獲得
        Class c2 = Class.forName("com.company.annotation.Student");
        System.out.println(c2);

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

        // 方法四 :基本內置類型的包裝類都有一個Type屬性
        Class c4 = Integer.TYPE;
        System.out.println(c4);

        // 獲得父類類型
        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 = "Stu";
    }
}class Teacher extends Person{
    public Teacher(){
        this.name = "Teac";
    }
}
package com.company.annotation;

import java.lang.annotation.ElementType;

// 所有類型的 Class
public class test2 {
    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 = 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
        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());
    }
}

Java 內存分析

image-20210206150037827

類初始化

image-20210206150543375

package com.company.annotation;
// 測試類聲明時候會被初始化
public class test3 {
    static {
        System.out.println("Main 被加載");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        // 1. 主動引用
        Son son = new Son();
        // 2. 反射也會產生主動引用
        Class.forName("com.company.annotation.Son");
        // 不會產生類的引用方法
        System.out.println(Son.b);
        Son[] array = new Son[100];
    }
}

class Father{
    static int b = 2;
    static {
        System.out.println("父類被加載");
    }
}
class Son extends Father{
    static {
        System.out.println("子類被加載");
        m = 300;

    }

    static  int m = 100;
    static final int M = 1;
}

獲得運行時類的完整結構

package com.company.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 獲取類的信息
public class test4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.company.annotation.User");

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

        // 獲得類的屬性
        System.out.println("------------");
        Field[] fields = c1.getFields(); // 只能找到public屬性

        fields = c1.getDeclaredFields(); // 找到全部的屬性

        for (Field field : fields){
            System.out.println(field);
        }

        // 獲得指定屬性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        // 獲得類的方法
        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("getDeclaredMethods:" + method);
        }

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

        // 獲得指定的構造器
        System.out.println("--------------");
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }
        constructors  = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }

        // 獲得指定的構造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定的:" + declaredConstructor);
    }
}

有了Class對象后續操作

image-20210207143717111

package com.company.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test5 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException {
        // 獲得class對象
        Class c1 = Class.forName("com.company.annotation.User");

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

        // 通過構造器創建對象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User)constructor.newInstance("快樂哥", 001, 20);
        System.out.println(user2);

        // 通過反射調用普通方法
        User user3 = (User)c1.newInstance();
        // 通過反射獲取一個方法
        Method setName = c1.getDeclaredMethod("setName", String.class);

        // (對象, “方法的值”)
        setName.invoke(user3, "olao");
        System.out.println(user3.getName());

        // 通過反射操作屬性
        System.out.println("---------------------");
        User user4 = (User)c1.newInstance();
        Field name = c1.getDeclaredField("name");

        //不能直接操作私有屬性,我們需要關閉程序的安全監測,
        // 開啟訪問權限
        name.setAccessible(true);
        name.set(user4, "oila");
        System.out.println(user4.getName());
    }
}

反射操作泛型

image-20210207144938177

通過反射操作注解 (練習ORM)

image-20210207145409967

package com.company.annotation;

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

public class orm {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.company.annotation.Stu");

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

        // 獲得注解的value的值
        TableStu tableStu = (TableStu)c1.getAnnotation(TableStu.class);
        String value = tableStu.value();
        System.out.println(value);


        // 獲得類指定注解
        Field f = c1.getDeclaredField("name");
        FieldStu annotation = f.getAnnotation(FieldStu.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
}

@TableStu("db_stu")
class Stu{
    @FieldStu(columnName = "db_id", type = "int", length = 10)
    private int id;
    @FieldStu(columnName = "db_age", type = "int", length = 10)
    private int age;
    @FieldStu(columnName = "db_name", type = "varchar", length = 3)
    private String name;

    public Stu() {
    }

    public Stu(int id, int age, String name) {
        this.id = id;
        this.age = age;
        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;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Stu{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

// 類名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableStu{
    String value();
}

// 屬性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldStu{
    String columnName();
    String type();
    int length();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM