java反射詳解

本文主要針對java反射進行學習,以java.lang.reflect包中的接口和類進行學習和理解。文章目錄以下:java

  1. java反射概念spring

  2. java反射包接口詳解數組

  3. java發射包中類詳解安全

  4. java反射的應用例子app


一:java反射概念

JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
java反射能起到的做用:
- 在運行中分析類的能力,即動態獲取類的基本狀況;
- 經過反射機制訪問java對象的屬性,方法,構造方法等;
- 主要是爲工具構造者提供的便利機制。jvm

二: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)方法來判斷指定方法上是否有該註解。ide

public class Person {
private String name;
private Integer age;
private String address;
public Person() {// TODO Auto-generated constructor stubsetName("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!");
    }
    @Overridepublic String toString() {// TODO Auto-generated method stubreturn "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 stubClass<?> 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{@Overridepublic void recordLog() {// TODO Auto-generated method stubSystem.out.println("記錄系統運行的日誌!");
    }@Overridepublic void getLength() {// TODO Auto-generated method stubSystem.out.println("獲取日誌長度!");
    }

}
import java.lang.reflect.Method;public class DynamicLogProxy implements InvocationHandler{private Object infoObject;public DynamicLogProxy(Object object) {// TODO Auto-generated constructor stubthis.infoObject=object;
    }@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stub//對象方法執行前調用一些方法,如spring的AOPSystem.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反射包中的類

  1. AccessibleObject:設置反射過程元素是否經過java安全檢查,默認未false,它是類Field, Method, Constructor, ReflectPermission 父類;

  2. Array:主要用於動態的建立數字,當反射方法參數是數組時,可使用Array來賦值。

  3. Field:主要獲取類中字段信息

  4. Method:主要獲取類中方法信息

  5. Constructor:獲取類中全部構造器函數信息

  6. 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 stubClass 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 exceptione.printStackTrace();
    }
    }

運行結果:

blue
green

引用塊內容 [1]java核心技術 卷I

相關文章
相關標籤/搜索