1. 程式人生 > 其它 >TwentyFiveDay-java 反射機制,註解

TwentyFiveDay-java 反射機制,註解

1、資源繫結器

資源繫結器,便於獲取屬性配置檔案中的內容

使用一下這種方式的時候,屬性配置檔案xxx.properties必須放在類路徑下

ResourceBundle bundle=ResourceBundle.getBundle("類路徑下的檔名")

//再寫路徑的時候。路徑後面的副檔名不能寫(tempfile03中寫了user=username)
ResourceBundle bundle =ResourceBundle.getBundle("tempfile03");
String name=bundle.getString("user");
System.out.println(name);//username

2、類載入器(瞭解)

1>、什麼是類載入器?

專門負責載入類的命令/工具

2>、類載入器的種類

啟動類載入器,擴充套件類載入器,應用類載入器

3>、假設有這樣一段程式碼

String s="asd";

程式碼在開始執行之前,會將所需要的類全部載入到JVM中。通過類載入器載入,看到以上程式碼類載入器會找String.class檔案,找到就載入,那麼是怎樣載入的呢?

a、首先通過"啟動類載入器"載入。

注意:啟動類載入器專門載入jre下的rt.jar,jdk11以後都找不到jre檔案了,rt.jar中都是JDK最核心的類庫。

b、如果通過啟動類載入器載入不到,就會用擴充套件類載入器載入jre下lib中的ext

c、如果擴充套件類載入器載入不到,則會通過應用類載入器,會專門載入classpath中的jar包(class檔案)

4>、java為了保證類載入安全,使用了雙親委派機制,優先從啟動類載入器載入,成為”父“,”父“無法載入到,再從擴充套件類載入器載入,稱”母“,雙親委派,如果都載入不到,才會考慮從應用類載入器中載入,直到載入到為止。

3、使用反射機制獲取Field

public static void main(String[] args) {
​
    try {
        //獲取屬性之前,需要獲取類
        Class cname = Class.forName("TwentyFiveDay.StudentClass");
        //獲取類名
        String name = cname.getName();
        System.out.println(name);//TwentyFiveDay.StudentClass
        //獲取簡易類名
        String sname=cname.getSimpleName();
        System.out.println(sname);//StudentClass
        //獲得類的屬性名
        Field[] fields = cname.getDeclaredFields();
        //測一下fields的長度
        System.out.println(fields.length);//4
​
        for (Field field : fields) {
            //遍歷輸出類屬性的修飾符 field.getModifiers()返回的是整型數字,代表的是修飾符的編號
            int i=field.getModifiers();
            //Modifier.toString(int i)方法把修飾符編號轉換成對應的修飾符
            String modifier= Modifier.toString(i);
            System.out.println(modifier);
            //遍歷輸出類屬性的型別 field.getType()返回的是class型別的
            System.out.println(field.getType().getSimpleName()+" ");
            //遍歷輸出類的屬性名
            System.out.println(field.getName()+" ");//sno sname sclass age
        }
​
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

4、使用反射機制給屬性賦值,獲取屬性的值

public static void main(String[] args) throws Exception{
    //使用new物件的方式
    StudentClass studentClass=new StudentClass();
    studentClass.age=12;
    System.out.println(studentClass.age);
    //使用反射機制獲取物件,並給物件的屬性賦值
        //第一步獲取StudentClass類
      Class student=Class.forName("TwentyFiveDay.StudentClass");
      //第二步給類建立一個物件
        Object stu=student.newInstance();//底層呼叫無參構造方法建立物件
        //第三步獲取stu物件的其中一個公有屬性
        Field sno = student.getDeclaredField("sno");
        //給sno賦值 .set(物件,值)方法
        sno.set(stu,123);
        //獲取stu屬性sno的值
        Object o = sno.get(stu);
        System.out.println(o);
        //獲取私有屬性
        Field sname = student.getDeclaredField("sname");
        //私有屬性的獲取必須打破封裝 這個是反射機制的缺點,打破封裝外部也可以訪問,不安全
        sname.setAccessible(true);
        //賦值
        sname.set(stu,"jack");
        //獲取
        System.out.println(sname.get(stu));
}

5、通過反射機制呼叫方法

public static void main(String[] args) throws Exception{
    //new物件來呼叫方法
    userServiceClass user=new userServiceClass();
    boolean result=user.UserRegister("adim","123");
    System.out.println(result?"登入成功":"登陸失敗");//登入成功
    //使用反射機制來呼叫方法
        //第一步獲取userServiceClass類
      Class userService=Class.forName("TwentyFiveDay.userServiceClass");
      //第二步建立物件
        Object users=userService.newInstance();
        //第三步獲取方法
       Method Register=userService.getDeclaredMethod("UserRegister", String.class, String.class);
       //第四步呼叫方法
        Object o = Register.invoke(users, "adim", "123");
        System.out.println(o);//true
   
}

6、通過反射機制例項化物件

public static void main(String[] args) throws Exception{
    //new物件來呼叫有參構造方法
    AnimalClass animalClass=new AnimalClass();
    AnimalClass animalClass1=new AnimalClass(001,"erha",2);
    System.out.println(animalClass1);//AnimalClass{no=1, name='erha', age=2}
    //通過反射機制來呼叫有參構造方法
    
        //第一步獲取AnimalClass類
        Class animal=Class.forName("TwentyFiveDay.AnimalClass");
        //第二步呼叫無參構造建立物件
        Object animalObj=animal.newInstance();
        //呼叫有參構造的步驟一:獲取有參構造方法名
        Constructor constructor = animal.getDeclaredConstructor(int.class, String.class, int.class);
        //第二步:建立物件
        Object bosi = constructor.newInstance(01, "bosi", 2);
        System.out.println(bosi);//AnimalClass{no=1, name='bosi', age=2}
   
}

7、通過反射機制獲取父類及介面

public static void main(String[] args) throws Exception{
    //第一步獲取這個類
    Class string=Class.forName("java.lang.String");
    //第二步獲取父類
    Class superclass = string.getSuperclass();
    System.out.println(superclass.getName());
    //第三步獲取介面陣列
    Class[] interfaces=string.getInterfaces();
    for (Class anInterface : interfaces) {
        System.out.println(anInterface.getName());
    }
}

8、註解

註解:又叫做註釋,英文單詞是:Annotation,它是引用型別,會編譯為.class檔案

註解可以出現在任何地方,註解上,方法上,類上,變數上,列舉,介面....

註解格式:修飾符 @interface 註解名{}

**需要掌握的Java.lang包下的註解:

@Deprecated的程式元素是程式設計師不鼓勵使用的程式元素,通常是因為它是危險的,或者因為存在更好的替代方法。作用:表示被標註的東西已過時

@Override 表示方法宣告旨在覆蓋超型別中的方法宣告,@Override:只能註解方法,這個註解是給編譯器參考的,和執行階段沒有關係,凡是有這個註解,編譯器都會進行檢查,如果這個方法不是重寫父類的方法,編譯器報錯。

**元註解:用來標註註解型別的註解

常用元註解:Target Retention

關於Target:用來標註”被標註的註解“只能出現在什麼位置

@Target(ElementType.METHOD) :表示被標註的註解只能出現在方法上

關於Retention:用來標註”被標註的註解“最終儲存在哪裡

@Retention(RetentionPolicy.SOURCE):表示被標註的註解最終儲存在java原始檔中

@Retention(RetentionPolicy.CLASS):表示被標註的註解儲存在class檔案中

@Retention(RetentionPolicy.RUNTIME):表示被標註的註解儲存在class檔案中,並且可以讓反射機制讀取到

9、自定義註解

//自定義註解MyAnnotation

public @interface MyAnnotation {
    //註解裡可以寫屬性,看著像方法,我們稱之為屬性
    String name();
    //可以給屬性賦預設值 這樣在給其他方法或類註釋的時候可不寫
    int age() default 1;
}

//自定義註解MyAnnotation01

註解裡的屬性型別都可以有哪些 可以是:byte,short,int,long,float,double,boolean,char,String,Class,enum型別及它們的陣列形式

public @interface MyAnnotation01 {
    Weather[] value();
}

//enum列舉

public enum Weather {
    SNOW,SUN,RAIN,CLOUDY
}

//自定義註解MyAnnotation02

使用元註解,標註 MyAnnotation02註解只能標註類與方法

@Target({ElementType.METHOD,ElementType.TYPE})//省略了value,只允許該註解標註方法與類
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation02 {
    String[] value();
}

//測試註解類AnnotationTest01

//自定義的註解,裡面可以有屬性,但是若不是default了值,就需要寫出來如name屬性,age已經設定了預設值可不寫
@MyAnnotation(name="自定義註解",age=2)
public class AnnotationTest01 {
    //@Override
    public String toString() {
        return "AnnotationTest01{}";
    }
    //@Deprecated//表示已過時
    public static void method(){
​
    }
}

//測試註解類A

class A{
    //註解裡只有value一個屬性,可以省略”value=“,value屬性是一個列舉陣列型別,寫法如下:
    @MyAnnotation01({Weather.CLOUDY,Weather.RAIN})
    public static void main(String[] args) {
        AnnotationTest01.method();//已過時
    }
}

10、使用反射機制獲取註解

前提是這個註解已被Retention(RetentionPolicy.RUNTIME)註釋,才可以用反射機制讀取到

程式碼:

//建立一個類,被MyAnnotation02註釋

@MyAnnotation02({"註解"})
public class AnnotationTest02 {
    public static void main(String[] args) {
​
    }
}

//通過反射機制獲取AnnotationTest02上的註解

public static void main(String[] args) {
    try {
        //第一步獲取類
        Class annotation=Class.forName("TwentyFiveDay.AnnotationTest02");
        //判斷AnnotationTest01有沒有MyAnnotation02註解(這個註解必須是反射機制可以讀取的!!!)
        if(annotation.isAnnotationPresent(MyAnnotation02.class)){
            //獲取MyAnnotation02的物件an
            MyAnnotation02 an = (MyAnnotation02)annotation.getAnnotation(MyAnnotation02.class);
            //獲取註解物件的屬性
            String[] value = an.value();
            System.out.println(value[0]);//註解
        }
​
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

11、註解作用的練習

自定義一個ID註解,這能標註類,作用是被標註的類必須有整型id屬性,若是沒有則報錯“此類必須有整型id屬性”;

//@ID

//這個註解只能標註類
@Target(ElementType.TYPE)
//這個註解可以被反射機制讀取
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {
}

//user類

@ID
public class UserClass {
    //int id;
    String name;
}

//自定義異常類

//沒有id整型屬性異常
public class HasnotIDException extends RuntimeException {
    public HasnotIDException() {
    }
    public HasnotIDException(String s){
        super(s);
    }
}

//規定ID註解作用類

public static void main(String[] args) throws Exception {
    //獲取UserClass類
    Class user=Class.forName("TwentySixDay.UserClass");
    //給個預設布林型
    boolean b=false;
    //屬性集
    Field[] fields=user.getDeclaredFields();
    //判斷有沒有@ID註釋
    if(user.isAnnotationPresent(ID.class)) {
        //有註釋,則遍歷屬性集
        for (Field field : fields) {
            //判斷有沒有整型id屬性
            if("id".equals(field.getName())&&"int".equals(field.getType().getSimpleName())){
                //如果走到這,則程式正常
                b=true;
            }
        }
    }
    if(!b){
        throw new HasnotIDException("此類必須有整型id屬性!");
    }
}