本文主要針對java反射進行學習,以java.lang.reflect包中的介面和類進行學習和理解。文章目錄如下: 1. java反射概念 2. java反射包介面詳解 3. java發射包中類詳解 4. java反射的應用例子 一:java反射概念 JAVA反射機制是在運行狀態中,對於任意一個類, ...
本文主要針對java反射進行學習,以java.lang.reflect包中的介面和類進行學習和理解。文章目錄如下:
- java反射概念
- java反射包介面詳解
- java發射包中類詳解
- java反射的應用例子
一:java反射概念
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
java反射能起到的作用:
- 在運行中分析類的能力,即動態獲取類的基本情況;
- 通過反射機制訪問java對象的屬性,方法,構造方法等;
主要是為工具構造者提供的便利機制。
二:java反射包中的介面
1:AnnotatedElement
java.lang.reflect.AnnotatedElement介面是所有程式元素(例如java.lang.Class、java.lang.reflect.Method、java.lang.reflect.Constructor等)的父介面。該介面主要是功能是是獲取指定元素上所有類型註解、判斷指定元素上是否有指定的註解。下邊舉例:本文定義一個MyTag註解,然後使用AnnotatedElement介面提供的isAnnotationPresent(Class<? extends Annotation> annotationClass)方法來判斷指定方法上是否有該註解。
定義公共實體類Person
public class Person {
private String name;
private Integer age;
private String address;
public Person() {
// TODO Auto-generated constructor stub
setName("peter");
}
public Person(String name,Integer age,String address) {
this.address=address;
this.age=age;
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@MyTag(name="peter")
public void getInfo()
{
System.out.println("I am student!");
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "Person:"+name+";"+address+";"+age;
}
}
自定義註解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTag {
String name() default "test";
}
測試端
public class AnnotatedElementTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
// TODO Auto-generated method stub
Class<?> person=Class.forName("com.csu.reflect.Person");
boolean result=person.getMethod("getInfo", null).isAnnotationPresent( MyTag.class);
System.out.println(result);
}
}
運行結果:
true
通過上述例子發現,該介面為java反射獲取類元素註解信息提供方法,通過該介面可以方便的獲取類、方法、變數等上邊的註解類型、名稱等。
2:InvocationHandler介面
InvocationHandler介面主要為用戶創建動態代理,即每一個代理都需要實現該介面,它只有一個方法:invoke(Object proxy, Method method, Object[] args)
。
- proxy:在其上調用方法的代理實例;
- method:對應於在代理實例上調用的介面方法的 Method 實例;
- args:包含傳入代理實例上方法調用的參數值的對象數組,如果介面方法不使用參數,則為 null
下麵創建一個動態代理,來說明該介面的使用過程:
創建日誌處理介面及實現
```
public interface LogInfo {
public void recordLog ();
public void getLength();
}
public class RealLogInfo implements LogInfo{
@Override
public void recordLog() {
// TODO Auto-generated method stub
System.out.println("記錄系統運行的日誌!");
}
@Override
public void getLength() {
// TODO Auto-generated method stub
System.out.println("獲取日誌長度!");
}
}
import java.lang.reflect.Method;
public class DynamicLogProxy implements InvocationHandler{
private Object infoObject;
public DynamicLogProxy(Object object) {
// TODO Auto-generated constructor stub
this.infoObject=object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
//對象方法執行前調用一些方法,如spring的AOP
System.out.println("Before happen something!");
method.invoke(infoObject, args);
System.out.println("After happen something!");
return null;
}
}
*測試端:*
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class InvocationHandlerDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//真實對象
LogInfo realInfo=new RealLogInfo();
InvocationHandler handler=new DynamicLogProxy(realInfo);
//通過Proxy的newProxyInstance方法來創建我們的代理對象
LogInfo info=(LogInfo)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realInfo.getClass().getInterfaces(), handler);
System.out.println(info.getClass().getName());
info.recordLog();
info.getLength();
}
}
*運行結果:*
com.sun.proxy.\(Proxy0 Before happen something! 記錄系統運行的日誌! After happen something! -------------------- Before happen something! 獲取日誌長度! After happen something! ``` 從運行結果中發現:info實例獲取的類名稱竟然是\)Proxy0,是的這就是代理的獨特之處,在jvm中對代理類進行了統一的命名管理。同時我們發現,通過代理我們可以在方法運行前後進行一些特殊邏輯處理,Spring AOP正式使用這種思想。
三:java反射包中的類
- AccessibleObject:設置反射過程元素是否通過java安全檢查,預設未false,它是類
Field, Method, Constructor, ReflectPermission
父類; - Array:主要用於動態的創建數字,當反射方法參數是數組時,可以使用Array來賦值。
- Field:主要獲取類中欄位信息
- Method:主要獲取類中方法信息
- Constructor:獲取類中所有構造器函數信息
- Modifier:獲取類元素的許可權訪問標識
通過上述類中方法的調用,通過反射動態的獲取類中所有信息,下麵通過三個實例來說明java反射包中類的使用方法。
實例一:獲取某個類的所有信息
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
*通過反射方法獲取類中詳細信息
*/
public class GetClassInfoByReflect {
/**
* 獲取類中所有構造函數
*/
@SuppressWarnings("rawtypes")
public static void getAllConstructors(Class clazz)
{
Constructor[] constructors=clazz.getConstructors();
for(Constructor c:constructors)
{
String name=c.getName();
System.out.print(" ");
String modifiers=Modifier.toString(clazz.getModifiers());
if(modifiers.length()>0)
System.out.print(modifiers+" ");
System.out.print(name+"(");
Class []paramTypes=c.getParameterTypes();
for(int i=0;i<paramTypes.length;i++)
{
if(i>0)
System.out.print(", ");
System.out.print(paramTypes[i].getName());
}
System.out.println(");");
}
}
/**
* 獲取類中所用方法
* @param clazz
*/
@SuppressWarnings("rawtypes")
public static void getAllMethods(Class clazz)
{
Method[] methods=clazz.getMethods();
for(Method m:methods)
{
Class returntype=m.getReturnType();
String name=m.getName();
System.out.print(" ");
String modifiers=Modifier.toString(m.getModifiers());
if(modifiers.length()>0)
System.out.print(modifiers+" ");
System.out.print(returntype.getName()+" "+name+"(");
Class [] paramTypes=m.getParameterTypes();
for(int i=0;i<paramTypes.length;i++)
{
if(i>0)
System.out.print(",");
System.out.print(paramTypes[i].getName());
}
System.out.println(");");
}
}
/**
* 獲取類中所有欄位信息
* @param clazz
*/
@SuppressWarnings("rawtypes")
public static void getAllFields(Class clazz)
{
Field [] fields=clazz.getDeclaredFields();
for(Field f:fields)
{
Class type=f.getType();
String name=f.getName();
System.out.print(" ");
String modifier=Modifier.toString(f.getModifiers());
if(modifier.length()>0)
System.out.print(modifier+" ");
System.out.println(type.getName()+" "+name+";");
}
}
}
測試端實例:
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
Class clazz=Class.forName("com.csu.reflect.Person");
System.out.println("構造函數");
GetClassInfoByReflect.getAllConstructors(clazz);
System.out.println("類函數");
GetClassInfoByReflect.getAllMethods(clazz);
System.out.println("成員變數");
GetClassInfoByReflect.getAllFields(clazz);
}
}
運行結果:
構造函數
public com.csu.reflect.Person();
public com.csu.reflect.Person(java.lang.String, java.lang.Integer, java.lang.String);
類函數
public java.lang.String toString();
public java.lang.String getAddress();
public java.lang.String getName();
public void setName(java.lang.String);
public java.lang.Integer getAge();
public void getInfo();
public void setAge(java.lang.Integer);
public void setAddress(java.lang.String);
public final void wait(long,int);
public final native void wait(long);
public final void wait();
public boolean equals(java.lang.Object);
public native int hashCode();
public final native java.lang.Class getClass();
public final native void notify();
public final native void notifyAll();
成員變數
private java.lang.String name;
private java.lang.Integer age;
private java.lang.String address;
實例二:使用反射類Array實現所有數組拷貝
public class GenericCopyArray {
/**
* 通用數組拷貝方法
* @param array
* @param length
* @return
*/
@SuppressWarnings("rawtypes")
public static Object copyArray(Object array,int newlength)
{
Class clazz=array.getClass();
if(!clazz.isArray())
return null;
Class type=clazz.getComponentType();
int length=Array.getLength(array);
Object newArray=Array.newInstance(type, newlength);
System.arraycopy(array, 0, newArray, 0, Math.min(length, newlength));
return newArray;
}
}
測試端實例:
import java.util.Arrays;
public class Arraytest {
public static void main(String[] args) {
// TODO Auto-generated method stub
/**
* GenericCopyArray.copyArray不僅可以對象數組,還可以擴展任意類型的數組
*/
int[] a={1,2,3};
a=(int[])GenericCopyArray.copyArray(a, 2);
System.out.println(Arrays.toString(a));
Person person1=new Person("zp", 28, "changsha");
Person person2=new Person("wang", 29, "shandong");
Person person3=new Person("liu", 29, "wuhan");
Person [] persons={person1,person2};
Person []personCopy=(Person[])GenericCopyArray.copyArray(persons,2);
System.out.println("拷貝結果:"+Arrays.toString(personCopy));
//改變拷貝數字的值
personCopy[0]=person3;
System.out.println("改變拷貝結果"+Arrays.toString(personCopy));
System.out.println("原始結果未發生變化:"+Arrays.toString(persons));
}
}
運行結果:
[1, 2]
拷貝結果:[Person:zp;address;28, Person:wang;address;29]
改變拷貝結果[Person:liu;address;29, Person:wang;address;29]
原始結果未發生變化:[Person:zp;address;28, Person:wang;address;29]
通過運行實例發現:通過這種方式不僅能夠拷貝對象數組,而且可以擴展為任意類型數組。
實例三:通過Array給反射調用方法賦值
public class Target {
public void printValue(String[] values)
{
for(String value:values)
{
System.out.println(value);
}
}
}
測試端:
public static void main(String[] args) {
// TODO Auto-generated method stub
Class<Target> clazz =Target.class;
try {
Object object=clazz.newInstance();
Method printValue=clazz.getMethod("printValue", String[].class);
Object array=Array.newInstance(String.class, 2);
Array.set(array, 0, "blue");
Array.set(array, 1, "green");
printValue.invoke(object, array);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
運行結果:
blue
green
引用塊內容
[1]java核心技術 捲I