java中反射和注解的簡單使用方法
什么反射?
Reflection(反射)是被視為動(dòng)態(tài)語言的關(guān)鍵,反射機(jī)制允許程序在執(zhí)行期借助于Reflection API取得任何類的內(nèi)部信息,并能直接操作任意對(duì)象的內(nèi)部屬性及方法。
加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個(gè)Class類型的對(duì)象(一個(gè)類只有一個(gè)Class對(duì)象),這個(gè)對(duì)象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過這個(gè)對(duì)象看到類的結(jié)構(gòu)。這個(gè)對(duì)象就像一面鏡子,透過這個(gè)鏡子看到類的結(jié)構(gòu),所以,我們形象的稱之為: 反射。

Java反射機(jī)制提供的功能
- 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類
- 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象
- 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法
- 在運(yùn)行時(shí)獲取泛型信息
- 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的成員變量和方法
- 在運(yùn)行時(shí)處理注解
- 生成動(dòng)態(tài)代理
反射相關(guān)的主要API
java.lang.Class: 代表一 個(gè) 類
java.lang.reflect.Method: 代表類 的 方法
java.lang.reflect.Field: 代表類的 成員 變量
java.lang.reflect.Constructor: 代表類 的 構(gòu)造
Class 類
對(duì)象照鏡子后可以得到的信息:某個(gè)類的屬性、方法和構(gòu)造器、某個(gè)類到底實(shí)現(xiàn)了哪些接口。對(duì)于每個(gè)類而言,JRE 都為其保留一個(gè)不變的 Class 類型的對(duì)象。一個(gè) Class 對(duì)象包含了特定某個(gè)結(jié)構(gòu)(class/interface/enum/annotation/primitive type/void/[])的有關(guān)信息
- Class本身也是一個(gè)類
- Class 對(duì)象只能由系統(tǒng)建立對(duì)象
- 一個(gè)加載的類在 JVM 中只會(huì)有一個(gè)Class實(shí)例
- 一個(gè)Class對(duì)象對(duì)應(yīng)的是一個(gè)加載到JVM中的一個(gè).class文件
- 每個(gè)類的實(shí)例都會(huì)記得自己是由哪個(gè) Class 實(shí)例所生成
- 通過Class可以完整地得到一個(gè)類中的所有被加載的結(jié)構(gòu)
- Class類是Reflection的根源,針對(duì)任何你想動(dòng)態(tài)加載、運(yùn)行的類,唯有先獲得相應(yīng)的Class對(duì)象
Class類的常用方法
| 方法名 | 功能說明 |
|---|---|
| static Class forName(String name) | 返回指定類名 name 的 Class 對(duì)象 |
| Object newInstance() | 調(diào)用缺省構(gòu)造函數(shù),返回該Class對(duì)象的一個(gè)實(shí)例 |
| getName() | 返回此Class對(duì)象所表示的實(shí)體(類、接口、數(shù)組類、基本類型 或void)名稱 |
| Class getSuperClass() | 返回當(dāng)前Class對(duì)象的父類的Class對(duì)象 |
| Class [] getInterfaces() | 獲取當(dāng)前Class對(duì)象的接口 |
| ClassLoader getClassLoader() | 返回該類的類加載器 |
| Class getSuperclass() | 返回表示此Class所表示的實(shí)體的超類的Class |
| Constructor[] getConstructors() | 返回一個(gè)包含某些Constructor對(duì)象的數(shù)組 |
| Field[] getDeclaredFields() | 返回Field對(duì)象的一個(gè)數(shù)組 |
| Method getMethod(String name,Class … paramTypes) |
返回一個(gè)Method對(duì)象,此對(duì)象的形參類型為paramType |
獲取Class 類的實(shí)例( 四種方法)
先創(chuàng)建一個(gè)實(shí)體類
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.前提:已知一個(gè)類的全類名,且該類在類路徑下,可通過Class類的靜態(tài)方法forName()獲取,可能拋出 ClassNotFoundException
//1.Class.forName,應(yīng)用場景:多用于配置文件,讀取類全路徑,加載類
String classAllPath="com.chen.pojo.Car";
Class<?> cls1=Class.forName(classAllPath);
輸出結(jié)果:![]()
2.前提:若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程序性能最高
//2.類名.class,應(yīng)用場景:用于參數(shù)傳遞
Class<Car> cls2 = Car.class;
System.out.println(cls2);
輸出結(jié)果:![]()
3.已知某個(gè)類的實(shí)例,調(diào)用該實(shí)例的getClass()方法獲取Class對(duì)象
/3.對(duì)象.getClass(),應(yīng)用場景,有對(duì)象實(shí)例
Car car=new Car();
Class cls3=car.getClass();
System.out.println(cls3);
輸出結(jié)果:![]()
4.其他方式(不做要求)
//4.通過類加載器(4)種來獲取類的Class對(duì)象
//(1)先得到類加載器car
ClassLoader classLoader=car.getClass().getClassLoader();
//(2)通過類加載器得到Class對(duì)象
Class<?> cls4=classLoader.loadClass(classAllPath);
System.out.println(cls4);
//cls1,cls2,cls3,cls4 其實(shí)是同一個(gè)對(duì)象
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類對(duì)象
Class<Integer> integerClass=int.class;
Class<Character> characterClass=char.class;
Class<Boolean> booleanClass=boolean.class;
System.out.println(integerClass);
//6.基本數(shù)據(jù)類型對(duì)應(yīng)的包裝類,可以通過 .TYPE 得到class類對(duì)象
Class<Integer> type1=Integer.TYPE;
Class<Character> type2 = Character.TYPE;//其它包裝類BOOLEAN,DOUBLE,LONG,BYTE
System.out.println(type1);
哪些類型可以有Class 對(duì)象?
(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類對(duì)應(yīng)的Class對(duì)象
//<?>表示不確定的Java類
Class<?> cls=Class.forName(classAllPath);
//2.輸出cls
System.out.println(cls);//顯示cls對(duì)象,是哪個(gè)類的Class對(duì)象 class com.chen.pojo.Car
System.out.println(cls.getClass());//輸出cls運(yùn)行類型 class java.lang.Class
//3.得到包名
System.out.println(cls.getPackage().getName());
//4.得到全類名
System.out.println(cls.getName());
//5.通過cls創(chuàng)建對(duì)象實(shí)例
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對(duì)象,能做什么?
通過反射獲取運(yùn)行時(shí)類類的完整結(jié)構(gòu)
Field 、Method 、Constructor 、Superclass 、Interface 、Annotation(實(shí)現(xiàn)的全部接口 所繼承的父類 全部的構(gòu)造器 全部的方法 全部的Field)
1. 實(shí)現(xiàn)的全部接口
public Class<?>[] getInterfaces()
確定此對(duì)象所表示的類或接口實(shí)現(xiàn)的接口。
2. 所繼承的父類
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的實(shí)體(類、接口、基本類型)的父類的
Class。
3. 全部的構(gòu)造器
public Constructor<T>[] getConstructors()
返回此 Class 對(duì)象所表示的類的所有public構(gòu)造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 對(duì)象表示的類聲明的所有構(gòu)造方法。
Constructor類中:
取得修飾符: public int getModifiers();
取得方法名稱: public String getName();
取得參數(shù)的類型:public Class<?>[] getParameterTypes();
4. 全部的方法
public Method[] getDeclaredMethods()
返回此Class對(duì)象所表示的類或接口的全部方法
public Method[] getMethods()
返回此Class對(duì)象所表示的類或接口的public的方法
Method類中:
public Class<?> getReturnType()取得全部的返回值
public Class<?>[] getParameterTypes()取得全部的參數(shù)
public int getModifiers()取得修飾符
public Class<?>[] getExceptionTypes()取得異常信息
5. 全部的Field
public Field[] getFields()
返回此Class對(duì)象所表示的類或接口的public的Field。
public Field[] getDeclaredFields()
返回此Class對(duì)象所表示的類或接口的全部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ù)數(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對(duì)象
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對(duì)象
Class<?> person=Class.forName("com.chen.Person");
//getDeclaredFields:獲取本類中所有屬性
//規(guī)定說明:默認(rèn)修飾符是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());
//輸出當(dāng)前這個(gè)方法的形參數(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)用運(yùn)行時(shí)類的指定結(jié)構(gòu)
1. 調(diào)用指定方法
通過反射,調(diào)用類中的方法,通過Method類完成。步驟:
1.通過Class類的getMethod(String name,Class…parameterTypes)方法取得一個(gè)Method對(duì)象,并設(shè)置此方法操作時(shí)所需要的參數(shù)類型。
2.之后使用Object invoke(Object obj, Object[] args)進(jìn)行調(diào)用,并向方法中傳遞要設(shè)置的obj對(duì)象的參數(shù)信息。
Object invoke(Object obj, Object … args說明:
1.Object 對(duì)應(yīng)原方法的返回值,若原方法無返回值,此時(shí)返回null
2.若原方法若為靜態(tài)方法,此時(shí)形參Object obj可為null
3.若原方法形參列表為空,則Object[] args為null
4.若原方法聲明為private,則需要在調(diào)用此invoke()方法前,顯式調(diào)用方法對(duì)象的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 類對(duì)應(yīng)的class對(duì)象
Class<?> boossCls=Class.forName("com.chen.Boss");
//2.創(chuàng)建對(duì)象
Object o=boossCls.newInstance();
//3調(diào)用public的hi方法
Method hi=boossCls.getMethod("hi",String.class);
//3.1得到hi方法對(duì)象
Method hi2=boossCls.getDeclaredMethod("hi",String.class);
hi.invoke(o,"hhhh");
hi2.invoke(o,"hhhh2");
//4.調(diào)用private static 方法
//4.1得到say方法對(duì)象
Method say=boossCls.getDeclaredMethod("say", int.class, String.class, char.class);
//4.2因?yàn)閟ay方法private,所以需要爆破,原理和前面講的構(gòu)造器和屬性一樣
say.setAccessible(true);
System.out.println(say.invoke(o,100,"棧說",'男'));
//4.3因?yàn)閟ay方法是static,還可以這樣用,可以傳入null
System.out.println(say.invoke(null,200,"棧說2",'男'));
//5.在反射中,如果方法有返回值,統(tǒng)一返回Object,但是他運(yùn)行類型和方法定義的返回值類型一致
Object invoke = say.invoke(null, 300, "小明", '男');
System.out.println("reVal的運(yùn)行類型="+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);
}
}
運(yùn)行結(jié)果:
hi hhhh
hi hhhh2
100 棧說 男
200 棧說2 男
reVal的運(yùn)行類型=300 小明 男
2.調(diào)用指定屬性
在反射機(jī)制中,可以直接通過Field類操作類中的屬性,通過Field類提供的set()和get()方法就可以完成設(shè)置和取得屬性內(nèi)容的操作。
public Field getField(String name) 返回此Class對(duì)象表示的類或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class對(duì)象表示的類或接口的指定的Field。
在 在Field 中:
public Object get(Object obj) 取得指定對(duì)象obj上此Field的屬性內(nèi)容
public void set(Object obj,Object value) 設(shè)置指定對(duì)象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類對(duì)應(yīng)的class對(duì)象
Class<?> stuClass=Class.forName("com.chen.Student");
//2.創(chuàng)建對(duì)象
Object o=stuClass.newInstance();//o的運(yùn)行類型就是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");
//對(duì)name進(jìn)行爆破
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對(duì)象都有setAccessible()方法。
setAccessible啟動(dòng)和禁用訪問安全檢查的開關(guān)。
參數(shù)值為true則指示反射的對(duì)象在使用時(shí)應(yīng)該取消Java語言訪問檢查。
提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調(diào)用,那么請(qǐng)?jiān)O(shè)置為true。
使得原本無法訪問的私有成員也可以訪問
參數(shù)值為false則指示反射的對(duì)象應(yīng)該實(shí)施Java語言訪問檢查
調(diào)用Class對(duì)象的newInstance()方法
1)類必須有一個(gè)無參數(shù)的構(gòu)造器。
2)類的構(gòu)造器的訪問權(quán)限需要足夠。
例:
package com.chen;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
//演示通過反射機(jī)制創(chuàng)建實(shí)例
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)建實(shí)例
Object o = userClass.newInstance();
System.out.println(o);
//3.通過public的參數(shù)構(gòu)造器創(chuàng)建實(shí)例
/*constructor對(duì)象就是
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)建實(shí)例
//4.1先得到private的構(gòu)造器對(duì)象
Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);
//4.2 創(chuàng)建實(shí)例
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類對(duì)應(yīng)的class對(duì)象
Class<PrivateTest> privateTestClass = PrivateTest.class;
//2.創(chuàng)建對(duì)象實(shí)例
PrivateTest privateTest = privateTestClass.newInstance();
//3.得到name屬性對(duì)象
Field name = privateTestClass.getDeclaredField("name");
//4.爆破name
name.setAccessible(true);
name.set(privateTest,"天龍八部");
//5.得到getName方法對(duì)象
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對(duì)象
* 在控制臺(tái)打印File類的所以構(gòu)造器
* 通過newInstance的方法創(chuàng)建File對(duì)象,并創(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對(duì)象
* 在控制臺(tái)打印File類的所以構(gòu)造器
* 通過newInstance的方法創(chuàng)建File對(duì)象,并創(chuàng)建E:\mynew.yxy文件
* */
//1.class類的forName方法得到File類的class對(duì)象
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的方法對(duì)象
Method createNewFile = fileClass.getMethod("createNewFile");
createNewFile.invoke(file);
//file的運(yùn)行類型就是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 增加了對(duì)元數(shù)據(jù)(MetaData) 的支持, 也就是Annotation(注解)
Annotation 其實(shí)就是代碼里的 特殊標(biāo)記, 這些標(biāo)記可以在編譯, 類加載, 運(yùn)行時(shí)被讀取, 并執(zhí)行相應(yīng)的處理。通過使用Annotation, 程序員可以在不改變?cè)羞壿嫷那闆r下, 在源文件中嵌入一些補(bǔ)充信息。代碼分析工具、開發(fā)工具和部署工具可以通過這些補(bǔ)充信息進(jìn)行驗(yàn)證或者進(jìn)行部署。
Annotation 可以像修飾符一樣被使用, 可用于 修飾包, 類, 構(gòu)造器, 方 方法 法, 成員變量, 參數(shù), 局部變量的聲明, 這些信息被保存在 Annotation的“name=value” 對(duì)中
注解是一種趨勢,一定程度上可以說:框架 = 注解 + 反射 + 設(shè)計(jì)模式。
常見的Annotation
示例一:生成文檔相關(guān)的注解
@author 標(biāo)明開發(fā)該類模塊的作者,多個(gè)作者之間使用,分割
@version 標(biāo)明該類模塊的版本
@see 參考轉(zhuǎn)向,也就是相關(guān)主題
@since 從哪個(gè)版本開始增加的
@param 對(duì)方法中某參數(shù)的說明,如果沒有參數(shù)就不能寫
@return 對(duì)方法返回值的說明,如果方法的返回值類型是void就不能寫
@exception 對(duì)方法可能拋出的異常進(jìn)行說明 ,如果方法沒有用throws顯式拋出的異常就不能寫
其中
@param @return 和 @exception 這三個(gè)標(biāo)記都是只用于方法的。
@param的格式要求:@param 形參名 形參類型 形參說明
@return 的格式要求:@return 返回值類型 返回值說明
@exception的格式要求:@exception 異常類型 異常說明
@param和@exception可以并列多個(gè)
例:
/**
* @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;
}
}
示例二: 在編譯時(shí)進(jìn)行格式查 檢查(JDK 內(nèi)置的三個(gè)基本注解
@Override: 限定重寫父類方法, 該注解只能用于方法
@Deprecated: 用于表示所修飾的元素(類, 方法等)已過時(shí)。通常是因?yàn)樗揎椀慕Y(jié)構(gòu)危險(xiǎn)或存在更好的選擇
@SuppressWarnings: 抑制編譯器警告
例:
public class AnnotationTest{
public static void main(String[] args) {
@SuppressWarnings("unused")
int a = 10;
}
@Deprecated
public void print(){
System.out.println("過時(shí)的方法");
}
@Override
public String toString() {
return "重寫的toString方法()";
}
}
示例三: 跟蹤 代碼依賴性,實(shí)現(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個(gè)標(biāo)準(zhǔn)的meta-annotation類型,分別是:
1. Retention
@Retention: 只能用于修飾一個(gè) Annotation 定義, 用于指定該 Annotation 的生命周期, @Rentention 包含一個(gè) RetentionPolicy 類型的成員變量, 使用
@Rentention 時(shí)必須為該 value 成員變量指定值:
ØRetentionPolicy.SOURCE:在源文件中有效(即源文件保留),編譯器直接丟棄這種策略的注釋
ØRetentionPolicy.CLASS:在class文件中有效(即class保留) , 當(dāng)運(yùn)行 Java 程序時(shí), JVM不會(huì)保留注解。 這是默認(rèn)值
ØRetentionPolicy.RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留),當(dāng) 當(dāng)行 運(yùn)行 Java 程序時(shí), JVM 會(huì) 會(huì)保留注釋。程序 可以通過反射獲取 該注釋。
2. Target
用于修飾 Annotation 定義, 用于指定被修飾的 Annotation 能用于修飾哪些程序元素。 @Target 也包含一個(gè)名為 value 的成員變量。

3. Documented
@Documented: 用于指定被該元 Annotation 修飾的 Annotation 類將被javadoc 工具提取成文檔。默認(rèn)情況下,javadoc是不包括注解的。
Ø定義為Documented的注解必須設(shè)置Retention值為RUNTIME。
4. Inherited
@Inherited: 被它修飾的 Annotation 將具有 繼承性。如果某個(gè)類使用了被
@Inherited 修飾的 Annotation, 則其子類將自動(dòng)具有該注解。
Ø比如:如果把標(biāo)有@Inherited注解的自定義的注解標(biāo)注在類級(jí)別上,子類則可以繼承父類類級(jí)別的注解
Ø實(shí)際應(yīng)用中,使用較少
自定義 Annotation
定義新的 Annotation 類型使用 @interface 關(guān)鍵字
l 自定義注解自動(dòng)繼承了java.lang.annotation.Annotation 接口
l Annotation 的成員變量在 Annotation 定義中以無參數(shù)方法的形式來聲明。其方法名和返回值定義了該成員的名字和類型。我們稱為配置參數(shù)。類型只能
是八種基本數(shù)據(jù)類型、String 類型 、Class 類型 、enum 類型 、Annotation 類型 、以上所有類型的 數(shù)組。
l 可以在定義 Annotation 的成員變量時(shí)為其指定初始值, 指定成員變量的初始值可使用 default 關(guān)鍵字
l 如果只有一個(gè)參數(shù)成員,建議使用 參數(shù)名為value
l 如果定義的注解含有配置參數(shù),那么使用時(shí)必須指定參數(shù)值,除非它有默認(rèn)值。格式是“參數(shù)名 = 參數(shù)值”,如果只有一個(gè)參數(shù)成員,且名稱為value,可以省略“value=”
l 沒有成員定義的 Annotation 稱為 標(biāo)記; 包含成員變量的 Annotation 稱為元數(shù)據(jù) Annotation
注意:自定義注解必須配上注解的信息處理流程才有意義。
例:
package com.chen.annotation;
import java.lang.annotation.*;
//自定義注解
@MyAnnotation2(id=1,name = "s")
public class MyAnnotation {
//注解可以顯示,默認(rèn)值,如果沒有默認(rèn)值,我們就必須給注解賦值
@MyAnnotation2(id=2,name = "小白",age=21,schools ={"中山大學(xué)" } )
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 {"清華大學(xué)","北京大學(xué)"};
}
@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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringMVC異常全局捕獲與錯(cuò)誤響應(yīng)的處理方法
編程式異常處理是通過在代碼中?顯式編寫異常捕獲邏輯(如?try-catch?塊)來管理異常的方式,開發(fā)者需要手動(dòng)處理每一個(gè)可能拋出異常的代碼段,本文給大家介紹SpringMVC異常全局捕獲與錯(cuò)誤響應(yīng)的處理方法,感興趣的朋友一起看看吧2025-03-03
JavaWeb中請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向的區(qū)別以及使用
今天帶大家學(xué)習(xí)JavaWeb的相關(guān)知識(shí),文章圍繞著JavaWeb中請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向的區(qū)別以及使用展開,文中有非常詳細(xì)的介紹,需要的朋友可以參考下2021-06-06
詳解SpringBoot啟動(dòng)項(xiàng)目后執(zhí)行方法的幾種方式
在項(xiàng)目開發(fā)中某些場景必須要用到啟動(dòng)項(xiàng)目后立即執(zhí)行方式的功能,本文主要聊聊實(shí)現(xiàn)立即執(zhí)行的幾種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09

