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

Java反射機制提供的功能
- 在運行時判斷任意一個對象所屬的類
- 在運行時構造任意一個類的對象
- 在運行時判斷任意一個類所具有的成員變量和方法
- 在運行時獲取泛型信息
- 在運行時調用任意一個對象的成員變量和方法
- 在運行時處理注解
- 生成動態(tài)代理
反射相關的主要API
java.lang.Class: 代表一 個 類
java.lang.reflect.Method: 代表類 的 方法
java.lang.reflect.Field: 代表類的 成員 變量
java.lang.reflect.Constructor: 代表類 的 構造
Class 類
對象照鏡子后可以得到的信息:某個類的屬性、方法和構造器、某個類到底實現(xiàn)了哪些接口。對于每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。一個 Class 對象包含了特定某個結構(class/interface/enum/annotation/primitive type/void/[])的有關信息
- Class本身也是一個類
- Class 對象只能由系統(tǒng)建立對象
- 一個加載的類在 JVM 中只會有一個Class實例
- 一個Class對象對應的是一個加載到JVM中的一個.class文件
- 每個類的實例都會記得自己是由哪個 Class 實例所生成
- 通過Class可以完整地得到一個類中的所有被加載的結構
- Class類是Reflection的根源,針對任何你想動態(tài)加載、運行的類,唯有先獲得相應的Class對象
Class類的常用方法
| 方法名 | 功能說明 |
|---|---|
| static Class forName(String name) | 返回指定類名 name 的 Class 對象 |
| Object newInstance() | 調用缺省構造函數(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);
輸出結果:![]()
2.前提:若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠,程序性能最高
//2.類名.class,應用場景:用于參數(shù)傳遞
Class<Car> cls2 = Car.class;
System.out.println(cls2);
輸出結果:![]()
3.已知某個類的實例,調用該實例的getClass()方法獲取Class對象
/3.對象.getClass(),應用場景,有對象實例
Car car=new Car();
Class cls3=car.getClass();
System.out.println(cls3);
輸出結果:![]()
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:外部類,成員(成員內部類,靜態(tà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());
}
}
}
輸出結果
有了Class對象,能做什么?
通過反射獲取運行時類類的完整結構
Field 、Method 、Constructor 、Superclass 、Interface 、Annotation(實現(xiàn)的全部接口 所繼承的父類 全部的構造器 全部的方法 全部的Field)
1. 實現(xiàn)的全部接口
public Class<?>[] getInterfaces()
確定此對象所表示的類或接口實現(xiàn)的接口。
2. 所繼承的父類
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的實體(類、接口、基本類型)的父類的
Class。
3. 全部的構造器
public Constructor<T>[] getConstructors()
返回此 Class 對象所表示的類的所有public構造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 對象表示的類聲明的所有構造方法。
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 相關
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()
7. 泛型相關
獲取父類泛型類型: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;
//演示如來通過反射獲取類的結構信息
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修飾的構造器,包含本類
Constructor<?>[] constructors = person.getConstructors();
for(Constructor<?> constructor:constructors){
System.out.println("本類的構造器="+constructor.getName());
}
//getDeclaredConstructors:獲取本類中所有的構造器
Constructor<?>[] declaredConstructors=person.getDeclaredConstructors();
for (Constructor<?> declaredConstructor:declaredConstructors){
System.out.println("本類中所有的構造器="+declaredConstructor.getName());
System.out.println("本類中所有的構造器="+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:獲取本類中所有的構造器
Constructor<?>[] declaredConstructors=person.getDeclaredConstructors();
for (Constructor<?> declaredConstructor:declaredConstructors){
System.out.println("===============");
System.out.println("本類中所有的構造器="+declaredConstructor.getName());
System.out.println("本類中所有的構造器="+declaredConstructor);
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for(Class<?> parameterType:parameterTypes){
System.out.println("該構造器的形參類型="+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(){
}
}
輸出結果:
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()
本類的構造器=com.chen.Person
本類的構造器=com.chen.Person
本類中所有的構造器=com.chen.Person
本類中所有的構造器=private com.chen.Person(java.lang.String,int)
本類中所有的構造器=com.chen.Person
本類中所有的構造器=public com.chen.Person(java.lang.String)
本類中所有的構造器=com.chen.Person
本類中所有的構造器=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
===============
本類中所有的構造器=com.chen.Person
本類中所有的構造器=private com.chen.Person(java.lang.String,int)
該構造器的形參類型=class java.lang.String
該構造器的形參類型=int
===============
本類中所有的構造器=com.chen.Person
本類中所有的構造器=public com.chen.Person(java.lang.String)
該構造器的形參類型=class java.lang.String
===============
本類中所有的構造器=com.chen.Person
本類中所有的構造器=public com.chen.Person()
調用運行時類的指定結構
1. 調用指定方法
通過反射,調用類中的方法,通過Method類完成。步驟:
1.通過Class類的getMethod(String name,Class…parameterTypes)方法取得一個Method對象,并設置此方法操作時所需要的參數(shù)類型。
2.之后使用Object invoke(Object obj, Object[] args)進行調用,并向方法中傳遞要設置的obj對象的參數(shù)信息。
Object invoke(Object obj, Object … args說明:
1.Object 對應原方法的返回值,若原方法無返回值,此時返回null
2.若原方法若為靜態(tài)方法,此時形參Object obj可為null
3.若原方法形參列表為空,則Object[] args為null
4.若原方法聲明為private,則需要在調用此invoke()方法前,顯式調用方法對象的setAccessible(true)方法,將可訪問private的方法
例:
package com.chen;
//演示通過反射調用方法
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調用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.調用private static 方法
//4.1得到say方法對象
Method say=boossCls.getDeclaredMethod("say", int.class, String.class, char.class);
//4.2因為say方法private,所以需要爆破,原理和前面講的構造器和屬性一樣
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);
}
}
運行結果:
hi hhhh
hi hhhh2
100 棧說 男
200 棧說2 男
reVal的運行類型=300 小明 男
2.調用指定屬性
在反射機制中,可以直接通過Field類操作類中的屬性,通過Field類提供的set()和get()方法就可以完成設置和取得屬性內容的操作。
public Field getField(String name) 返回此Class對象表示的類或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class對象表示的類或接口的指定的Field。
在 在Field 中:
public Object get(Object obj) 取得指定對象obj上此Field的屬性內容
public void set(Object obj,Object value) 設置指定對象obj上此Field的屬性內容
例:
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 +
'}';
}
}
輸出結果:
class com.chen.Student
Student{age=22 name=null}
22
Student{age=22 name=小黑}
小黑
關于setAccessible
Method和Field、Constructor對象都有setAccessible()方法。
setAccessible啟動和禁用訪問安全檢查的開關。
參數(shù)值為true則指示反射的對象在使用時應該取消Java語言訪問檢查。
提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調用,那么請設置為true。
使得原本無法訪問的私有成員也可以訪問
參數(shù)值為false則指示反射的對象應該實施Java語言訪問檢查
調用Class對象的newInstance()方法
1)類必須有一個無參數(shù)的構造器。
2)類的構造器的訪問權限需要足夠。
例:
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的無參構造器創(chuàng)建實例
Object o = userClass.newInstance();
System.out.println(o);
//3.通過public的參數(shù)構造器創(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的有參構造器創(chuàng)建實例
//4.1先得到private的構造器對象
Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class);
//4.2 創(chuàng)建實例
constructor1.setAccessible(true);//爆破,所有反射可以訪問private構造器
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 + '\'' +
'}';
}
}
輸出結果:
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屬性值,并調用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屬性值,并調用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類的所以構造器
* 通過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類的所以構造器
* 通過newInstance的方法創(chuàng)建File對象,并創(chuàng)建E:\mynew.yxy文件
* */
//1.class類的forName方法得到File類的class對象
Class<?> fileClass = Class.forName("java.io.File");
//2.得到所有的構造器
Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors();
//遍歷輸出
for (Constructor<?> declaredConstructor:declaredConstructors){
System.out.println("file構造器="+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);
}
}
輸出結果:
file構造器=public java.io.File(java.lang.String,java.lang.String)
file構造器=public java.io.File(java.lang.String)
file構造器=private java.io.File(java.lang.String,java.io.File)
file構造器=public java.io.File(java.io.File,java.lang.String)
file構造器=public java.io.File(java.net.URI)
file構造器=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 可以像修飾符一樣被使用, 可用于 修飾包, 類, 構造器, 方 方法 法, 成員變量, 參數(shù), 局部變量的聲明, 這些信息被保存在 Annotation的“name=value” 對中
注解是一種趨勢,一定程度上可以說:框架 = 注解 + 反射 + 設計模式。
常見的Annotation
示例一:生成文檔相關的注解
@author 標明開發(fā)該類模塊的作者,多個作者之間使用,分割
@version 標明該類模塊的版本
@see 參考轉向,也就是相關主題
@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 內置的三個基本注解
@Override: 限定重寫父類方法, 該注解只能用于方法
@Deprecated: 用于表示所修飾的元素(類, 方法等)已過時。通常是因為所修飾的結構危險或存在更好的選擇
@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的注解必須設置Retention值為RUNTIME。
4. Inherited
@Inherited: 被它修飾的 Annotation 將具有 繼承性。如果某個類使用了被
@Inherited 修飾的 Annotation, 則其子類將自動具有該注解。
Ø比如:如果把標有@Inherited注解的自定義的注解標注在類級別上,子類則可以繼承父類類級別的注解
Ø實際應用中,使用較少
自定義 Annotation
定義新的 Annotation 類型使用 @interface 關鍵字
l 自定義注解自動繼承了java.lang.annotation.Annotation 接口
l Annotation 的成員變量在 Annotation 定義中以無參數(shù)方法的形式來聲明。其方法名和返回值定義了該成員的名字和類型。我們稱為配置參數(shù)。類型只能
是八種基本數(shù)據(jù)類型、String 類型 、Class 類型 、enum 類型 、Annotation 類型 、以上所有類型的 數(shù)組。
l 可以在定義 Annotation 的成員變量時為其指定初始值, 指定成員變量的初始值可使用 default 關鍵字
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();
}
輸出結果
@com.chen.annotation.TableStudent(value=db_student)
db_student
db_name
varchar
5
---------------
db_age
int
10
---------------
db_id
int
10
總結
到此這篇關于java中反射和注解的簡單使用方法的文章就介紹到這了,更多相關java反射和注解使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaWeb中請求轉發(fā)和請求重定向的區(qū)別以及使用
今天帶大家學習JavaWeb的相關知識,文章圍繞著JavaWeb中請求轉發(fā)和請求重定向的區(qū)別以及使用展開,文中有非常詳細的介紹,需要的朋友可以參考下2021-06-06
詳解SpringBoot啟動項目后執(zhí)行方法的幾種方式
在項目開發(fā)中某些場景必須要用到啟動項目后立即執(zhí)行方式的功能,本文主要聊聊實現(xiàn)立即執(zhí)行的幾種方法,具有一定的參考價值,感興趣的可以了解一下2023-09-09

