java中反射和注解的簡單使用方法
什么反射?
Reflection(反射)是被視為動態(tài)語言的關(guān)鍵,反射機制允許程序在執(zhí)行期借助于Reflection API取得任何類的內(nèi)部信息,并能直接操作任意對象的內(nèi)部屬性及方法。
加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過這個對象看到類的結(jié)構(gòu)。這個對象就像一面鏡子,透過這個鏡子看到類的結(jié)構(gòu),所以,我們形象的稱之為: 反射。
Java反射機制提供的功能
- 在運行時判斷任意一個對象所屬的類
- 在運行時構(gòu)造任意一個類的對象
- 在運行時判斷任意一個類所具有的成員變量和方法
- 在運行時獲取泛型信息
- 在運行時調(diào)用任意一個對象的成員變量和方法
- 在運行時處理注解
- 生成動態(tài)代理
反射相關(guān)的主要API
java.lang.Class: 代表一 個 類
java.lang.reflect.Method: 代表類 的 方法
java.lang.reflect.Field: 代表類的 成員 變量
java.lang.reflect.Constructor: 代表類 的 構(gòu)造
Class 類
對象照鏡子后可以得到的信息:某個類的屬性、方法和構(gòu)造器、某個類到底實現(xiàn)了哪些接口。對于每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。一個 Class 對象包含了特定某個結(jié)構(gòu)(class/interface/enum/annotation/primitive type/void/[])的有關(guān)信息
- Class本身也是一個類
- Class 對象只能由系統(tǒng)建立對象
- 一個加載的類在 JVM 中只會有一個Class實例
- 一個Class對象對應的是一個加載到JVM中的一個.class文件
- 每個類的實例都會記得自己是由哪個 Class 實例所生成
- 通過Class可以完整地得到一個類中的所有被加載的結(jié)構(gòu)
- Class類是Reflection的根源,針對任何你想動態(tài)加載、運行的類,唯有先獲得相應的Class對象
Class類的常用方法
方法名 | 功能說明 |
---|---|
static Class forName(String name) | 返回指定類名 name 的 Class 對象 |
Object newInstance() | 調(diào)用缺省構(gòu)造函數(shù),返回該Class對象的一個實例 |
getName() | 返回此Class對象所表示的實體(類、接口、數(shù)組類、基本類型 或void)名稱 |
Class getSuperClass() | 返回當前Class對象的父類的Class對象 |
Class [] getInterfaces() | 獲取當前Class對象的接口 |
ClassLoader getClassLoader() | 返回該類的類加載器 |
Class getSuperclass() | 返回表示此Class所表示的實體的超類的Class |
Constructor[] getConstructors() | 返回一個包含某些Constructor對象的數(shù)組 |
Field[] getDeclaredFields() | 返回Field對象的一個數(shù)組 |
Method getMethod(String name,Class … paramTypes) |
返回一個Method對象,此對象的形參類型為paramType |
獲取Class 類的實例( 四種方法)
先創(chuàng)建一個實體類
package com.chen.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class Car { public String brand="寶馬"; public int price=500000; public String color="白色"; }
1.前提:已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態(tài)方法forName()獲取,可能拋出 ClassNotFoundException
//1.Class.forName,應用場景:多用于配置文件,讀取類全路徑,加載類 String classAllPath="com.chen.pojo.Car"; Class<?> cls1=Class.forName(classAllPath);
輸出結(jié)果:
2.前提:若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程序性能最高
//2.類名.class,應用場景:用于參數(shù)傳遞 Class<Car> cls2 = Car.class; System.out.println(cls2);
輸出結(jié)果:
3.已知某個類的實例,調(diào)用該實例的getClass()方法獲取Class對象
/3.對象.getClass(),應用場景,有對象實例 Car car=new Car(); Class cls3=car.getClass(); System.out.println(cls3);
輸出結(jié)果:
4.其他方式(不做要求)
//4.通過類加載器(4)種來獲取類的Class對象 //(1)先得到類加載器car ClassLoader classLoader=car.getClass().getClassLoader(); //(2)通過類加載器得到Class對象 Class<?> cls4=classLoader.loadClass(classAllPath); System.out.println(cls4);
//cls1,cls2,cls3,cls4 其實是同一個對象 System.out.println(cls1.hashCode()); System.out.println(cls2.hashCode()); System.out.println(cls3.hashCode()); System.out.println(cls4.hashCode());
//5. 基本數(shù)據(jù)(int,char,boolean,float,double,byte,long,short) 按如下方式得到Class類對象 Class<Integer> integerClass=int.class; Class<Character> characterClass=char.class; Class<Boolean> booleanClass=boolean.class; System.out.println(integerClass); //6.基本數(shù)據(jù)類型對應的包裝類,可以通過 .TYPE 得到class類對象 Class<Integer> type1=Integer.TYPE; Class<Character> type2 = Character.TYPE;//其它包裝類BOOLEAN,DOUBLE,LONG,BYTE System.out.println(type1);
哪些類型可以有Class 對象?
(1)class:外部類,成員(成員內(nèi)部類,靜態(tài)內(nèi)部類),局部內(nèi)部類,匿名內(nèi)部類
(2)interface:接口
(3)[]:數(shù)組
(4)enum:枚舉
(5)annotation:注解@interface
(6)primitive type:基本數(shù)據(jù)類型
(7)void
Class<String> cls1=String.class;//外部類 Class<Serializable> cls2=Serializable.class;//接口 Class<Integer[]> cls3 = Integer[].class;//數(shù)組 Class<float[][]> cls4 = float[][].class;//二維數(shù)組 Class<Deprecated> cls5 = Deprecated.class;//注解 //枚舉 Class<Thread.State> cls6 = Thread.State.class; Class<Long> cls7 = long.class; Class<Void> cls8= void.class; Class<Class> cls9 = Class.class; System.out.println(cls1); System.out.println(cls2); System.out.println(cls3); System.out.println(cls4); System.out.println(cls5); System.out.println(cls6); System.out.println(cls7); System.out.println(cls8); System.out.println(cls9);
演示Class類的常用方法
package com.chen; import com.chen.pojo.Car; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; //演示Class類的常用方法 public class Class02 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { String classAllPath="com.chen.pojo.Car"; //1.獲取Car類對應的Class對象 //<?>表示不確定的Java類 Class<?> cls=Class.forName(classAllPath); //2.輸出cls System.out.println(cls);//顯示cls對象,是哪個類的Class對象 class com.chen.pojo.Car System.out.println(cls.getClass());//輸出cls運行類型 class java.lang.Class //3.得到包名 System.out.println(cls.getPackage().getName()); //4.得到全類名 System.out.println(cls.getName()); //5.通過cls創(chuàng)建對象實例 Car car= (Car) cls.newInstance(); System.out.println(car); //6.通過反射獲取屬性 brand Field brand=cls.getField("brand"); System.out.println(brand.get(car)); //7.通過反射給屬性賦值 brand.set(car,"奔馳"); System.out.println(brand.get(car)); //8.獲取所有屬性(字段) Field[] fields=cls.getFields(); for (Field field:fields){ System.out.println(field.getName()); } } }
輸出結(jié)果
有了Class對象,能做什么?
通過反射獲取運行時類類的完整結(jié)構(gòu)
Field 、Method 、Constructor 、Superclass 、Interface 、Annotation(實現(xiàn)的全部接口 所繼承的父類 全部的構(gòu)造器 全部的方法 全部的Field)
1. 實現(xiàn)的全部接口
public Class<?>[] getInterfaces()
確定此對象所表示的類或接口實現(xiàn)的接口。
2. 所繼承的父類
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的實體(類、接口、基本類型)的父類的
Class。
3. 全部的構(gòu)造器
public Constructor<T>[] getConstructors()
返回此 Class 對象所表示的類的所有public構(gòu)造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 對象表示的類聲明的所有構(gòu)造方法。
Constructor類中:
取得修飾符: public int getModifiers();
取得方法名稱: public String getName();
取得參數(shù)的類型:public Class<?>[] getParameterTypes();
4. 全部的方法
public Method[] getDeclaredMethods()
返回此Class對象所表示的類或接口的全部方法
public Method[] getMethods()
返回此Class對象所表示的類或接口的public的方法
Method類中:
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的參數(shù)
public int getModifiers()取得修飾符
public Class<?>[] getExceptionTypes()取得異常信息
5. 全部的Field
public Field[] getFields()
返回此Class對象所表示的類或接口的public的Field。
public Field[] getDeclaredFields()
返回此Class對象所表示的類或接口的全部Field。
Field方法中:
public int getModifiers() 以整數(shù)形式返回此Field的修飾符
public Class<?> getType() 得到Field的屬性類型
public String getName() 返回Field的名稱。
6. Annotation 相關(guān)
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()
7. 泛型相關(guān)
獲取父類泛型類型:Type getGenericSuperclass()
泛型類型:ParameterizedType
獲取實際的泛型類型參數(shù)數(shù)組:getActualTypeArguments()
8. 類所在的包 Package getPackage()
例:
package com.chen; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; //演示如來通過反射獲取類的結(jié)構(gòu)信息 public class ReflectionUtils { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //api_o1(); api_o2(); } //第一組API public static void api_o1() throws ClassNotFoundException, NoSuchMethodException { //得到Class對象 Class<?> person=Class.forName("com.chen.Person"); //getName:獲取全類名 System.out.println(person.getName()); //getSimpleName:獲取簡單類名 System.out.println(person.getSimpleName()); //getFields:獲取所有public修飾的屬性,包含本類以及父類的 Field[] fields=person.getFields(); for(Field field:fields){ System.out.println("本類以及父類的屬性="+field.getName()); } //getDeclaredFields:獲取本類中所有屬性 Field[] declaredFields = person.getDeclaredFields(); for(Field declaredField:declaredFields){ System.out.println("本類中所有屬性="+declaredField.getName()); } //getMethods:獲取所有public修飾的方法,包含本類以及父類的 Method[] methods=person.getMethods(); for(Method method:methods){ System.out.println("本類及父類的方法="+method.getName()); } //getDeclaredMethods:獲取本類中所有的方法 Method[] declareMethods=person.getDeclaredMethods(); for(Method declareMethod:declareMethods){ System.out.println("本類中所有的方法:"+declareMethod); } //getConstructors:獲取所有public修飾的構(gòu)造器,包含本類 Constructor<?>[] constructors = person.getConstructors(); for(Constructor<?> constructor:constructors){ System.out.println("本類的構(gòu)造器="+constructor.getName()); } //getDeclaredConstructors:獲取本類中所有的構(gòu)造器 Constructor<?>[] declaredConstructors=person.getDeclaredConstructors(); for (Constructor<?> declaredConstructor:declaredConstructors){ System.out.println("本類中所有的構(gòu)造器="+declaredConstructor.getName()); System.out.println("本類中所有的構(gòu)造器="+declaredConstructor); } //getPackage:以Package形式返回 包信息 System.out.println(person.getPackage()); //getSuperClass:以Class形式返回父類信息 Class<?> superclass = person.getSuperclass(); System.out.println("以Class形式返回父類信息"+superclass); //getInterfaces:以Class[]形式返回接口信息 Class<?>[] interfaces = person.getInterfaces(); for (Class<?> aninterface:interfaces){ System.out.println("接口信息"+aninterface); } //getAnnotat ions:以Annotation[]形式返回注解信息 Annotation[] annotations=person.getAnnotations(); for (Annotation annotation:annotations){ System.out.println("注解信息="+annotation); } } public static void api_o2() throws ClassNotFoundException, NoSuchMethodException { //得到Class對象 Class<?> person=Class.forName("com.chen.Person"); //getDeclaredFields:獲取本類中所有屬性 //規(guī)定說明:默認修飾符是0,public是1,private是2,protected是4,static是8,final是16,】 public(1)+static(8)=9 Field[] declaredFields = person.getDeclaredFields(); for(Field declaredField:declaredFields){ System.out.println("本類中所有屬性="+declaredField.getName()+"該屬性的修飾符="+declaredField.getModifiers() +" 該屬性的類型="+declaredField.getType()); } //getDeclaredMethods:獲取本類中所有的方法 Method[] declareMethods=person.getDeclaredMethods(); for(Method declareMethod:declareMethods){ System.out.println("本類中所有的方法:"+declareMethod +" 該方法的訪問修飾符="+declareMethod.getModifiers() +" 該方法返回類型="+declareMethod.getReturnType()); //輸出當前這個方法的形參數(shù)組情況 Class<?>[] parameterTypes=declareMethod.getParameterTypes(); for(Class<?> parameterType:parameterTypes){ System.out.println("該方法的形參類型="+parameterType); } } //getDeclaredConstructors:獲取本類中所有的構(gòu)造器 Constructor<?>[] declaredConstructors=person.getDeclaredConstructors(); for (Constructor<?> declaredConstructor:declaredConstructors){ System.out.println("==============="); System.out.println("本類中所有的構(gòu)造器="+declaredConstructor.getName()); System.out.println("本類中所有的構(gòu)造器="+declaredConstructor); Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); for(Class<?> parameterType:parameterTypes){ System.out.println("該構(gòu)造器的形參類型="+parameterType); } } } } interface IA{ } interface IB{ } class A { public String hobby; public void hi(){ } public A() { } } @Deprecated class Person extends A implements IA,IB{ //屬性 public String name; protected int age; String job; private double sal; public Person(){ } public Person(String name) { } private Person(String name,int age){ } //方法 public void m1(String name,int age,double sal){ } private void m2(){ } protected void m3(){ } void m4(){ } public void m5(){ } }
輸出結(jié)果:
com.chen.Person
Person
本類以及父類的屬性=name
本類以及父類的屬性=hobby
本類中所有屬性=name
本類中所有屬性=age
本類中所有屬性=job
本類中所有屬性=sal
本類及父類的方法=m5
本類及父類的方法=m1
本類及父類的方法=hi
本類及父類的方法=wait
本類及父類的方法=wait
本類及父類的方法=wait
本類及父類的方法=equals
本類及父類的方法=toString
本類及父類的方法=hashCode
本類及父類的方法=getClass
本類及父類的方法=notify
本類及父類的方法=notifyAll
本類中所有的方法:public void com.chen.Person.m5()
本類中所有的方法:private void com.chen.Person.m2()
本類中所有的方法:void com.chen.Person.m4()
本類中所有的方法:public void com.chen.Person.m1(java.lang.String,int,double)
本類中所有的方法:protected void com.chen.Person.m3()
本類的構(gòu)造器=com.chen.Person
本類的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=private com.chen.Person(java.lang.String,int)
本類中所有的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=public com.chen.Person(java.lang.String)
本類中所有的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=public com.chen.Person()
package com.chen
以Class形式返回父類信息class com.chen.A
接口信息interface com.chen.IA
接口信息interface com.chen.IB
注解信息=@java.lang.Deprecated()
本類中所有屬性=name該屬性的修飾符=1 該屬性的類型=class java.lang.String
本類中所有屬性=age該屬性的修飾符=4 該屬性的類型=int
本類中所有屬性=job該屬性的修飾符=0 該屬性的類型=class java.lang.String
本類中所有屬性=sal該屬性的修飾符=2 該屬性的類型=double
本類中所有的方法:public void com.chen.Person.m5() 該方法的訪問修飾符=1 該方法返回類型=void
本類中所有的方法:private void com.chen.Person.m2() 該方法的訪問修飾符=2 該方法返回類型=void
本類中所有的方法:void com.chen.Person.m4() 該方法的訪問修飾符=0 該方法返回類型=void
本類中所有的方法:public void com.chen.Person.m1(java.lang.String,int,double) 該方法的訪問修飾符=1 該方法返回類型=void
該方法的形參類型=class java.lang.String
該方法的形參類型=int
該方法的形參類型=double
本類中所有的方法:protected void com.chen.Person.m3() 該方法的訪問修飾符=4 該方法返回類型=void
===============
本類中所有的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=private com.chen.Person(java.lang.String,int)
該構(gòu)造器的形參類型=class java.lang.String
該構(gòu)造器的形參類型=int
===============
本類中所有的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=public com.chen.Person(java.lang.String)
該構(gòu)造器的形參類型=class java.lang.String
===============
本類中所有的構(gòu)造器=com.chen.Person
本類中所有的構(gòu)造器=public com.chen.Person()
調(diào)用運行時類的指定結(jié)構(gòu)
1. 調(diào)用指定方法
通過反射,調(diào)用類中的方法,通過Method類完成。步驟:
1.通過Class類的getMethod(String name,Class…parameterTypes)方法取得一個Method對象,并設(shè)置此方法操作時所需要的參數(shù)類型。
2.之后使用Object invoke(Object obj, Object[] args)進行調(diào)用,并向方法中傳遞要設(shè)置的obj對象的參數(shù)信息。
Object invoke(Object obj, Object … args說明:
1.Object 對應原方法的返回值,若原方法無返回值,此時返回null
2.若原方法若為靜態(tài)方法,此時形參Object obj可為null
3.若原方法形參列表為空,則Object[] args為null
4.若原方法聲明為private,則需要在調(diào)用此invoke()方法前,顯式調(diào)用方法對象的setAccessible(true)方法,將可訪問private的方法
例:
package com.chen; //演示通過反射調(diào)用方法 import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflecAccessMethod { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //1.得到Boss 類對應的class對象 Class<?> boossCls=Class.forName("com.chen.Boss"); //2.創(chuàng)建對象 Object o=boossCls.newInstance(); //3調(diào)用public的hi方法 Method hi=boossCls.getMethod("hi",String.class); //3.1得到hi方法對象 Method hi2=boossCls.getDeclaredMethod("hi",String.class); hi.invoke(o,"hhhh"); hi2.invoke(o,"hhhh2"); //4.調(diào)用private static 方法 //4.1得到say方法對象 Method say=boossCls.getDeclaredMethod("say", int.class, String.class, char.class); //4.2因為say方法private,所以需要爆破,原理和前面講的構(gòu)造器和屬性一樣 say.setAccessible(true); System.out.println(say.invoke(o,100,"棧說",'男')); //4.3因為say方法是static,還可以這樣用,可以傳入null System.out.println(say.invoke(null,200,"棧說2",'男')); //5.在反射中,如果方法有返回值,統(tǒng)一返回Object,但是他運行類型和方法定義的返回值類型一致 Object invoke = say.invoke(null, 300, "小明", '男'); System.out.println("reVal的運行類型="+invoke); } } class Boss{//類 public int age; private static String name; public Boss(){ } private static String say(int n,String s,char c){ return n+" "+s+" " +c; } public void hi(String s){ System.out.println("hi "+s); } }
運行結(jié)果:
hi hhhh
hi hhhh2
100 棧說 男
200 棧說2 男
reVal的運行類型=300 小明 男
2.調(diào)用指定屬性
在反射機制中,可以直接通過Field類操作類中的屬性,通過Field類提供的set()和get()方法就可以完成設(shè)置和取得屬性內(nèi)容的操作。
public Field getField(String name) 返回此Class對象表示的類或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class對象表示的類或接口的指定的Field。
在 在Field 中:
public Object get(Object obj) 取得指定對象obj上此Field的屬性內(nèi)容
public void set(Object obj,Object value) 設(shè)置指定對象obj上此Field的屬性內(nèi)容
例:
package com.chen; import java.lang.reflect.Field; //演示反射操作屬性 public class RefleAccessProperty { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException { //1.得到Student類對應的class對象 Class<?> stuClass=Class.forName("com.chen.Student"); //2.創(chuàng)建對象 Object o=stuClass.newInstance();//o的運行類型就是student System.out.println(o.getClass()); //3.使用反射得到age屬性 Field age = stuClass.getField("age"); age.set(o,22); System.out.println(o); System.out.println(age.get(o)); //4.使用反射操作name屬性 Field name = stuClass.getDeclaredField("name"); //對name進行爆破 name.setAccessible(true); name.set(o,"小黑"); System.out.println(o); System.out.println(name.get(o)); } } class Student{//類 public int age=20; private static String name; public Student(){ } @Override public String toString() { return "Student{" + "age=" + age + " name=" + name + '}'; } }
輸出結(jié)果:
class com.chen.Student
Student{age=22 name=null}
22
Student{age=22 name=小黑}
小黑
關(guān)于setAccessible
Method和Field、Constructor對象都有setAccessible()方法。
setAccessible啟動和禁用訪問安全檢查的開關(guān)。
參數(shù)值為true則指示反射的對象在使用時應該取消Java語言訪問檢查。
提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調(diào)用,那么請設(shè)置為true。
使得原本無法訪問的私有成員也可以訪問
參數(shù)值為false則指示反射的對象應該實施Java語言訪問檢查
調(diào)用Class對象的newInstance()方法
1)類必須有一個無參數(shù)的構(gòu)造器。
2)類的構(gòu)造器的訪問權(quán)限需要足夠。
例:
package com.chen; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; //演示通過反射機制創(chuàng)建實例 public class ReflecCreateInstance { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //1.先獲取User類 Class<?> userClass = Class.forName("com.chen.User"); //2.通過public的無參構(gòu)造器創(chuàng)建實例 Object o = userClass.newInstance(); System.out.println(o); //3.通過public的參數(shù)構(gòu)造器創(chuàng)建實例 /*constructor對象就是 public User(string name){ this.name=name; } * */ Constructor<?> constructor = userClass.getConstructor(String.class); Object hh = constructor.newInstance("hh"); System.out.println("hh="+hh); //4.通過非public的有參構(gòu)造器創(chuàng)建實例 //4.1先得到private的構(gòu)造器對象 Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class); //4.2 創(chuàng)建實例 constructor1.setAccessible(true);//爆破,所有反射可以訪問private構(gòu)造器 Object user2=constructor1.newInstance(100,"小明"); System.out.println("user2="+user2); } } class User{ private int age=10; private String name="hello"; public User(){ } public User(String name){ this.name=name; } private User(int age,String name){ this.age=age; this.name=name; } @Override public String toString() { return "User{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
輸出結(jié)果:
User{age=10, name='hello'}
hh=User{age=10, name='hh'}
user2=User{age=100, name='小明'}
綜合案例:
例1:
/*定義PrivateTest類,有私有name屬性,并且屬性值為helloKitty
* 提供getName的公有方法
* 創(chuàng)建PrivateTest的類,利用Class類得到私有的name屬性,修改私有的name屬性值,并調(diào)用getName()的方法打印name屬性值*/
package com.chen; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class HomeWork01 { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException { /*定義PrivateTest類,有私有name屬性,并且屬性值為helloKitty * 提供getName的公有方法 * 創(chuàng)建PrivateTest的類,利用Class類得到私有的name屬性,修改私有的name屬性值,并調(diào)用getName()的方法打印name屬性值*/ //1.得到PrivateTest類對應的class對象 Class<PrivateTest> privateTestClass = PrivateTest.class; //2.創(chuàng)建對象實例 PrivateTest privateTest = privateTestClass.newInstance(); //3.得到name屬性對象 Field name = privateTestClass.getDeclaredField("name"); //4.爆破name name.setAccessible(true); name.set(privateTest,"天龍八部"); //5.得到getName方法對象 Method getName = privateTestClass.getMethod("getName"); Object invoke = getName.invoke(privateTest); System.out.println("name屬性值"+invoke); } } class PrivateTest{ private String name="hellokitty"; public String getName(){ return name; } }
例2
/*
* 利用class類的forName方法得到File類的cass對象
* 在控制臺打印File類的所以構(gòu)造器
* 通過newInstance的方法創(chuàng)建File對象,并創(chuàng)建E:\mynew.yxy文件
* */
package com.chen; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class HomeWork02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { /* * 利用class類的forName方法得到File類的class對象 * 在控制臺打印File類的所以構(gòu)造器 * 通過newInstance的方法創(chuàng)建File對象,并創(chuàng)建E:\mynew.yxy文件 * */ //1.class類的forName方法得到File類的class對象 Class<?> fileClass = Class.forName("java.io.File"); //2.得到所有的構(gòu)造器 Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors(); //遍歷輸出 for (Constructor<?> declaredConstructor:declaredConstructors){ System.out.println("file構(gòu)造器="+declaredConstructor); } //3.指定的得到public java.io.File(java.lang.String) Constructor<?> declaredConstructor = fileClass.getDeclaredConstructor(String.class); String fileAllPath="D:\\mynew.txt"; Object file=declaredConstructor.newInstance(fileAllPath); //4.得到createNewFile的方法對象 Method createNewFile = fileClass.getMethod("createNewFile"); createNewFile.invoke(file); //file的運行類型就是File System.out.println(file.getClass()); System.out.println("創(chuàng)建文件成功"+fileAllPath); } }
輸出結(jié)果:
file構(gòu)造器=public java.io.File(java.lang.String,java.lang.String)
file構(gòu)造器=public java.io.File(java.lang.String)
file構(gòu)造器=private java.io.File(java.lang.String,java.io.File)
file構(gòu)造器=public java.io.File(java.io.File,java.lang.String)
file構(gòu)造器=public java.io.File(java.net.URI)
file構(gòu)造器=private java.io.File(java.lang.String,int)
class java.io.File
創(chuàng)建文件成功D:\mynew.txt
注解
什么是注解?
從 JDK 5.0 開始, Java 增加了對元數(shù)據(jù)(MetaData) 的支持, 也就是Annotation(注解)
Annotation 其實就是代碼里的 特殊標記, 這些標記可以在編譯, 類加載, 運行時被讀取, 并執(zhí)行相應的處理。通過使用Annotation, 程序員可以在不改變原有邏輯的情況下, 在源文件中嵌入一些補充信息。代碼分析工具、開發(fā)工具和部署工具可以通過這些補充信息進行驗證或者進行部署。
Annotation 可以像修飾符一樣被使用, 可用于 修飾包, 類, 構(gòu)造器, 方 方法 法, 成員變量, 參數(shù), 局部變量的聲明, 這些信息被保存在 Annotation的“name=value” 對中
注解是一種趨勢,一定程度上可以說:框架 = 注解 + 反射 + 設(shè)計模式。
常見的Annotation
示例一:生成文檔相關(guān)的注解
@author 標明開發(fā)該類模塊的作者,多個作者之間使用,分割
@version 標明該類模塊的版本
@see 參考轉(zhuǎn)向,也就是相關(guān)主題
@since 從哪個版本開始增加的
@param 對方法中某參數(shù)的說明,如果沒有參數(shù)就不能寫
@return 對方法返回值的說明,如果方法的返回值類型是void就不能寫
@exception 對方法可能拋出的異常進行說明 ,如果方法沒有用throws顯式拋出的異常就不能寫
其中
@param @return 和 @exception 這三個標記都是只用于方法的。
@param的格式要求:@param 形參名 形參類型 形參說明
@return 的格式要求:@return 返回值類型 返回值說明
@exception的格式要求:@exception 異常類型 異常說明
@param和@exception可以并列多個
例:
/** * @author shkstart * @version 1.0 * @see Math.java */ public class JavadocTest { /** * 程序的主方法,程序的入口 * @param args String[] 命令行參數(shù) */ public static void main(String[] args) { } /** * 求圓面積的方法 * @param radius double 半徑值 * @return double 圓的面積 */ public static double getArea(double radius){ return Math.PI * radius * radius; } }
示例二: 在編譯時進行格式查 檢查(JDK 內(nèi)置的三個基本注解
@Override: 限定重寫父類方法, 該注解只能用于方法
@Deprecated: 用于表示所修飾的元素(類, 方法等)已過時。通常是因為所修飾的結(jié)構(gòu)危險或存在更好的選擇
@SuppressWarnings: 抑制編譯器警告
例:
public class AnnotationTest{ public static void main(String[] args) { @SuppressWarnings("unused") int a = 10; } @Deprecated public void print(){ System.out.println("過時的方法"); } @Override public String toString() { return "重寫的toString方法()"; } }
示例三: 跟蹤 代碼依賴性,實現(xiàn)替代配置文件功能
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException { }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doGet(request, response);
} }
JDK 中的元注解
JDK 的元 Annotation 用于修飾其他 Annotation 定義
RetentionTargetDocumentedInherited
JDK5.0提供了4個標準的meta-annotation類型,分別是:
1. Retention
@Retention: 只能用于修飾一個 Annotation 定義, 用于指定該 Annotation 的生命周期, @Rentention 包含一個 RetentionPolicy 類型的成員變量, 使用
@Rentention 時必須為該 value 成員變量指定值:
ØRetentionPolicy.SOURCE:在源文件中有效(即源文件保留),編譯器直接丟棄這種策略的注釋
ØRetentionPolicy.CLASS:在class文件中有效(即class保留) , 當運行 Java 程序時, JVM不會保留注解。 這是默認值
ØRetentionPolicy.RUNTIME:在運行時有效(即運行時保留),當 當行 運行 Java 程序時, JVM 會 會保留注釋。程序 可以通過反射獲取 該注釋。
2. Target
用于修飾 Annotation 定義, 用于指定被修飾的 Annotation 能用于修飾哪些程序元素。 @Target 也包含一個名為 value 的成員變量。
3. Documented
@Documented: 用于指定被該元 Annotation 修飾的 Annotation 類將被javadoc 工具提取成文檔。默認情況下,javadoc是不包括注解的。
Ø定義為Documented的注解必須設(shè)置Retention值為RUNTIME。
4. Inherited
@Inherited: 被它修飾的 Annotation 將具有 繼承性。如果某個類使用了被
@Inherited 修飾的 Annotation, 則其子類將自動具有該注解。
Ø比如:如果把標有@Inherited注解的自定義的注解標注在類級別上,子類則可以繼承父類類級別的注解
Ø實際應用中,使用較少
自定義 Annotation
定義新的 Annotation 類型使用 @interface 關(guān)鍵字
l 自定義注解自動繼承了java.lang.annotation.Annotation 接口
l Annotation 的成員變量在 Annotation 定義中以無參數(shù)方法的形式來聲明。其方法名和返回值定義了該成員的名字和類型。我們稱為配置參數(shù)。類型只能
是八種基本數(shù)據(jù)類型、String 類型 、Class 類型 、enum 類型 、Annotation 類型 、以上所有類型的 數(shù)組。
l 可以在定義 Annotation 的成員變量時為其指定初始值, 指定成員變量的初始值可使用 default 關(guān)鍵字
l 如果只有一個參數(shù)成員,建議使用 參數(shù)名為value
l 如果定義的注解含有配置參數(shù),那么使用時必須指定參數(shù)值,除非它有默認值。格式是“參數(shù)名 = 參數(shù)值”,如果只有一個參數(shù)成員,且名稱為value,可以省略“value=”
l 沒有成員定義的 Annotation 稱為 標記; 包含成員變量的 Annotation 稱為元數(shù)據(jù) Annotation
注意:自定義注解必須配上注解的信息處理流程才有意義。
例:
package com.chen.annotation; import java.lang.annotation.*; //自定義注解 @MyAnnotation2(id=1,name = "s") public class MyAnnotation { //注解可以顯示,默認值,如果沒有默認值,我們就必須給注解賦值 @MyAnnotation2(id=2,name = "小白",age=21,schools ={"中山大學" } ) public void test(){ } @MyAnnotation3("小黑") public void test2(){ } } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ //注解的參數(shù):參數(shù)類型+參數(shù)名(); String name() default ""; int age() default 0; int id() ; String[] schools() default {"清華大學","北京大學"}; } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{ //注解的參數(shù):參數(shù)類型+參數(shù)名(); String value() ; }
最后通過反射獲取注解信息:
package com.chen.annotation; import java.lang.annotation.*; import java.lang.reflect.Field; import java.lang.reflect.Method; //注解和反射 public class AnnotationAndReflect { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class<?> aClass = Class.forName("com.chen.annotation.Student"); //通過反射獲得注解 Annotation[] annotations = aClass.getAnnotations(); for(Annotation annotation:annotations){ System.out.println(annotation); } //獲得注解的value的值 TableStudent tableAnnotation = aClass.getAnnotation(TableStudent.class); String value = tableAnnotation.value(); System.out.println(value); //獲得類指定的注解 Field f= aClass.getDeclaredField("name"); FieldStudent annotation = f.getAnnotation(FieldStudent.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); System.out.println("---------------"); Field f2= aClass.getDeclaredField("age"); FieldStudent annotation2 = f2.getAnnotation(FieldStudent.class); System.out.println(annotation2.columnName()); System.out.println(annotation2.type()); System.out.println(annotation2.length()); System.out.println("---------------"); Field f3= aClass.getDeclaredField("id"); FieldStudent annotation3 = f3.getAnnotation(FieldStudent.class); System.out.println(annotation3.columnName()); System.out.println(annotation3.type()); System.out.println(annotation3.length()); } } @TableStudent("db_student") class Student{ @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 = 5) private String name; public Student() { } public Student(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 "Student{" + "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(); }
輸出結(jié)果
@com.chen.annotation.TableStudent(value=db_student)
db_student
db_name
varchar
5
---------------
db_age
int
10
---------------
db_id
int
10
總結(jié)
到此這篇關(guān)于java中反射和注解的簡單使用方法的文章就介紹到這了,更多相關(guān)java反射和注解使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java?socket實現(xiàn)局域網(wǎng)聊天
這篇文章主要為大家詳細介紹了java?socket實現(xiàn)局域網(wǎng)聊天,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05spring boot實戰(zhàn)教程之shiro session過期時間詳解
這篇文章主要給大家介紹了關(guān)于spring boot實戰(zhàn)教程之shiro session過期時間的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧。2017-10-10JSON中fastjson、jackson、gson如何選擇
在Java中,JSON的解析方式很多,例如fastjson(阿里)、Gson(谷歌)、jackjson等,本文主要介紹了JSON中fastjson、jackson、gson如何選擇,具有一定的參考價值,感興趣的可以了解一下2021-12-12MyBatis-Plus中如何使用ResultMap的方法示例
本文主要介紹了MyBatis-Plus中如何使用ResultMap,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11