[java学习笔记]-注解和反射
[java學習筆記]-注解和反射
- 注解
- 元注解
- 自定義注解
- 反射
- 獲取其他的類
- 類型的Class對象
- 類加載內存分析
- 分析類的初始化
- 類加載器的作用
- 創建運行時類的對象
- 動態創建對象執行的方法
- 性能對比分析
- 獲取泛型信息
- 獲取注解信息
注解
@Override 規則和約束@Deprecated 危險的方法,過時的方法@SuppressWarnings 抑制編譯時的警告信息@Override
public class Test1 {//@Override是重寫的注解@Overridepublic String toString() {return super.toString();} }@Deprecated
//Deprecated不推孝程序員使用,但是可以使用。或者存在更好的方式 @Deprecated public static void test(){System.out.println("Deprecated"); }@SuppressWarnings
@SuppressWarnings("all") public void test1(){List list = new ArrayList(); }元注解
@Documented @Target() @Retention() @Inherited定義一個注解
//定義一個注解 public @interface MyAnnotation{ }把注解的范圍限制在方法和類中
//類注解 @MyAnnotation public class Test2 {//方法注解@MyAnnotationpublic void test(){} }//定義一個注解 @Target(value = {ElementType.METHOD,ElementType.TYPE}) @interface MyAnnotation{ } //Retention表示我們的注解在什么地方還有效。 //runtime>class>source @Retention(value = RetentionPolicy.RUNTIME) @interface MyAnnotation{ }//Documented表示是否將我們的注解生成在JAVAdoc中 @Documented//子類可以繼承父類的注解 @Inherited自定義注解
關鍵字 @interface多參數
public class Test2 {//注解可以顯示賦值,如果沒有默認值,我們就必須給注解賦值@MyAnnotation(name = "Muz1")public void test(){} }@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation{//注解的參數: 參數類型 + 參數名();String name() default "";int age() default 0;int id() default -1;//如果默認值為-1,代表不存在,indexof,如果找不到就返回-1String[] schools() default {"牛馬大學","說唱帶專"} }單參數
public class Test2 {//注解可以顯示賦值,如果沒有默認值,我們就必須給注解賦值@MyAnnotation("Muz1")public void test(){} }@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation{String[] value(); }參數名是 value() 可以省略注解參數
反射
Reflection (反射)是Java被視為動態語言的關鍵,反射機制允許程序在執行期借助于Reflection API取得任何類的內部信息,并能直接操作任意對象的內部屬性及方法
Class c = Class.forName("java.lang.String");加載完類之后,在堆內存的方法區中就產生了已個Class類型的對象(一個類只有一個Class對象) ,這個對象就包含了完整的類的結構信息。我們可以通過這個對象看到類的結構。這個對象就像一面鏡子, 透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射
獲取一個簡單反射
//Test.java//反射 public class Test {public static void main(String[] args) throws ClassNotFoundException {//通過反射獲取類的Class對象Class c1 = Class.forName("com.Reflection.User");System.out.println(c1);} } //實體類 pojo entity class User{private String name;private int id;private int age;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;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", id=" + id +", age=" + age +'}';} }可以看到這個類有很多方法
獲取其他的類
//Test.java public class Test {public static void main(String[] args) throws ClassNotFoundException {//通過反射獲取類的Class對象Class c1 = Class.forName("com.Reflection.User");System.out.println(c1);Class c2 = Class.forName("com.Reflection.User");Class c3 = Class.forName("com.Reflection.User");Class c4 = Class.forName("com.Reflection.User");System.out.println(c2.hashCode());System.out.println(c3.hashCode());System.out.println(c4.hashCode());} }......一個類在內存中只有一個Class
一個類被加載后,類的整個結構都會被封裝在Class對象中。
測試class類的創建方式有哪些
package com.Reflection; //測試Class類的創建方式有哪些 public class Test1 {public static void main(String[] args) throws ClassNotFoundException {Person person = new Student();System.out.println("這個人是:"+person.name);//方式一: 通過對象獲得Class c1 = person.getClass();System.out.println(c1.hashCode());//方式二: forName獲得Class c2 = Class.forName("com.Reflection.Student");System.out.println(c2.hashCode());//方式三: 通過類名.class獲得Class c3 = Student.class;System.out.println(c3.hashCode());//方式四: 基本內置類型的包裝類都有一個Type屬性Class c4 = Integer.TYPE;System.out.println(c4);//獲得父類類型Class c5 = c1.getSuperclass();System.out.println(c5);} }class Person{public String name;public Person() {this.name = name;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';} } class Student extends Person{public Student() {this.name="學生";} } class Teacher extends Person{public Teacher() {this.name="老師";} }類型的Class對象
//Test2.javapackage com.Reflection; 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; //voidClass c9 = Class.class; //ClassSystem.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("void: " + c8);System.out.println("Class: " + c9);} }類加載內存分析
小測試
//Test3.java package com.Reflection; public class Test3 {public static void main(String[] args) {A a = new A();System.out.println(A.m);} } class A{static {System.out.println("A類靜態代碼塊初始化");m = 300;}static int m = 100;public A() {System.out.println("A類的無參構造器初始化");} } 1.加載到內存,會產生一個類對應的class對象 2.鏈接,鏈接結束后 m = 0 3.初始化<clinit>(){System.out.println("A類靜態代碼塊初始化");m = 300;m = 100;}m = 100;分析類的初始化
Demo
然后在main方法中加入
public static void main(String[] args) {//1.主動引用Son son = new Son(); }輸出
反射
public static void main(String[] args) throws ClassNotFoundException {//反射也會產生主動引用Class.forName("com.Reflection.Son"); }輸出
不會產生類的引用方法
public static void main(String[] args) {//不會產生類的引用方法System.out.println(Son.b); }數組
public static void main(String[] args) {Son[] array = new Son[5]; }常量
public static void main(String[] args) {System.out.println(Son.M); }類加載器的作用
類加載器
package com.Reflection; public class Test5 {public static void main(String[] args) throws ClassNotFoundException {//獲取系統類的加載器ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();System.out.println(systemClassLoader);//獲取系統類加載器的父類加載器-->拓展類加載器ClassLoader parent = systemClassLoader.getParent();System.out.println(parent);//獲取系統類加載器的父類加載器-->根加載器(C/C++)ClassLoader parent1 = parent.getParent();System.out.println(parent1);//測試當前類是哪個加載器ClassLoader c1 = Class.forName("com.Reflection.Test5").getClassLoader();System.out.println(c1);//測試JDK內置的類是誰加載的ClassLoader c2 = Class.forName("java.lang.Object").getClassLoader();System.out.println(c2);//如何獲得系統加載器可以加載的路徑System.out.println(System.getProperty("java.class.path"));} }創建運行時類的對象
之前的 User類
//Test6.java //獲得類的信息 public class Test6 {public static void main(String[] args) throws ClassNotFoundException {Class c1 = Class.forName("com.Reflection.User");//獲得類的名字System.out.println(c1.getName());System.out.println(c1.getSimpleName());} }獲得類的屬性
//Test6.java public class Test6 {public static void main(String[] args) throws ClassNotFoundException {Class c1 = Class.forName("com.Reflection.User");//獲得類的屬性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);} } //Test6.java public class Test6 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {Class c1 = Class.forName("com.Reflection.User");//獲得類的方法//獲得本類及其父類的全部public方法Method[] methods = c1.getMethods();for (Method method : methods) {System.out.println("正常的: " + method);}//獲得本類的所有方法methods = c1.getDeclaredMethods();for (Method method : methods) {System.out.println("getDeclaredMethods: " + method);}} }獲得指定的方法
//Test6.java public class Test6 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {Class c1 = Class.forName("com.Reflection.User");//獲得指定的方法Method getNames = c1.getMethod("getName", null);Method setNames = c1.getMethod("setName", String.class);System.out.println(getNames);System.out.println(setNames);} }動態創建對象執行的方法
通過反射動態的創建對象
//Test7.java//通過反射動態的創建對象 public class Test7 {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {//獲得Class對象Class c1 = Class.forName("com.Reflection.User");//構造一個對象User user = (User)c1.newInstance(); //本質上調用了類的無參構造器System.out.println(user);} }把User類的無參構造器刪除
再次運行報錯
使用newInstance()函數創建函數,必須有無參構造器
通過構造器創建對象
//Test7.java //通過構造器創建對象 Constructor c2 = c1.getDeclaredConstructor(String.class, int.class, int.class); Object muz1 = c2.newInstance("Muz1", 1, 0); System.out.println(muz1);通過反射調用普通方法
//通過反射調用普通方法 User user = (User)c1.newInstance(); //通過反射獲取一個方法 Method setName = c1.getDeclaredMethod("setName", String.class); setName.invoke(user,"Muz1"); System.out.println(user.getName());通過反射操作屬性
//通過反射操作屬性 User user1 = (User)c1.newInstance(); Field name = c1.getDeclaredField("name"); name.set(user1,"Muz12"); System.out.println(user1.getName());輸出報錯,因為 User類里面都是 private 方法
添加一行代碼
//name.setAccessible(true);User user1 = (User)c1.newInstance(); Field name = c1.getDeclaredField("name");//不能直接操作私有屬性,需要關閉程序安全檢測 name.setAccessible(true);name.set(user1,"Muz12"); System.out.println(user1.getName());成功輸出
性能對比分析
Demo
三種方式的性能表現
package com.Reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //分析性能問題 public class Test8 {//普通方式public static void test1(){User user = new User();long startTime = System.currentTimeMillis();for(int i = 0; i < 1000000000; i++){user.getName();}long endTime = System.currentTimeMillis();System.out.println("普通方式執行10億次"+(endTime-startTime)+"ms");}//反射方式public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName", null);long startTime = System.currentTimeMillis();for(int i = 0; i < 1000000000; i++){getName.invoke(user,null);}long endTime = System.currentTimeMillis();System.out.println("反射方式執行10億次"+(endTime-startTime)+"ms");}//反射方式,關閉檢測public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User user = new User();Class c1 = user.getClass();Method getName = c1.getDeclaredMethod("getName", null);getName.setAccessible(true);long startTime = System.currentTimeMillis();for(int i = 0; i < 1000000000; i++){getName.invoke(user,null);}long endTime = System.currentTimeMillis();System.out.println("反射方式,關閉檢測執行10億次"+(endTime-startTime)+"ms");}public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {test1();test2();test3();} }獲取泛型信息
Demo
//Test9.java package com.Reflection; 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 Test9 {public void test1(Map<String,User> map, List<User> list){System.out.println("test1");}public Map<String,User> test2(){System.out.println("test2");return null;}public static void main(String[] args) throws NoSuchMethodException {Method method = Test9.class.getMethod("test1", Map.class, List.class);Type[] genericParameterTypes = method.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {System.out.println("#"+genericParameterType);if(genericParameterType instanceof ParameterizedType){Type[] actualTypeArguments = ((ParameterizedType)genericParameterType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}System.out.println("========================================");method = Test9.class.getMethod("test2",null);Type genericReturnType = method.getGenericReturnType();if(genericReturnType instanceof ParameterizedType){Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}} }獲取注解信息
Demo
//Test10.javapackage com.Reflection; import java.lang.annotation.*; //聯系反射操作注解 public class Test10 {public static void main(String[] args) throws ClassNotFoundException {Class c1 = Class.forName("com.Reflection.Student2");//通過反射獲得注解Annotation[] annotations = c1.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);}} }@AbbMuz1("db_Student") class Student2{@BbbMuz1(columnName = "db_id",type = "int" ,length = 10)private int id;@BbbMuz1(columnName = "db_age",type = "int" ,length = 10)private int age;@BbbMuz1(columnName = "db_name",type = "varchar" ,length = 10)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 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;}@Overridepublic String toString() {return "Student2{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';} }//類名注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface AbbMuz1{String value(); } //屬性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface BbbMuz1{String columnName();String type();int length(); }獲得注解輸出
獲得注解value的值
在main方法中添加
//獲得注解value的值 AbbMuz1 annotation = (AbbMuz1)c1.getAnnotation(AbbMuz1.class); String value = annotation.value(); System.out.println(value);獲得類指定的注解
在main方法中添加
//獲得類指定的注解 Field f = c1.getDeclaredField("name"); BbbMuz1 annotation1 = f.getAnnotation(BbbMuz1.class); System.out.println(annotation1.columnName()); System.out.println(annotation1.type()); System.out.println(annotation1.length());總結
以上是生活随笔為你收集整理的[java学习笔记]-注解和反射的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于类的符号输入过程第二篇
- 下一篇: 离职的一些感悟