TwentyFiveDay-java 反射機制,註解
資源繫結器,便於獲取屬性配置檔案中的內容
使用一下這種方式的時候,屬性配置檔案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屬性!");
}
}