您的位置:首页 > 编程语言 > Java开发

JAVA之反射

2017-04-09 00:18 411 查看
        Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时通过反射机制取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现于interfaces(例如Cloneable),也包括fields和methods的所有信息,并可在运行时改变fields内容或调用methods。

        Java反射机制允许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。

一、相关API:

        在java.lang.reflect包中可以找到相关的API,常用的类和接口有:

        1、Member接口:获取类相关的成员信息,包括成员所在类的class对象,变量或方法的修饰符和名称等信息;

        2、AccessibleObject类:是域(field)对象、方法(method)对象、构造函数(constructor)对象的基类。它提供了将反射的对象标记为在使用时取消默认Java 语言访问控制检查的能力。

        3、Array类:提供动态创建和访问Java数组的方法。

        4、Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。

        5、Field类:提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)变量或实例变量。

        6、Method类:提供关于类或接口的单个方法,以及对它的动态访问权限。反射的方法可能是类方法或实例方法(包括抽象方法)。

        7、Modifier类:提供了对类、变量、方法的访问修饰符进行解码。

        8、Proxy类:提供创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

二、应用:

        1、获取类的class对象:

                ①可以调用对象的.getClass()方法,但原生类的变量不能调用此方法,比如int、boolean等:

public class Test{
public static void main(String args[]){
String str = new String();
System.out.println(str.getClass());
}
}

                ②可以调用类的.class()方法,原生类也可以调用此方法,比如int、boolean等:

public class Test{
public static void main(String args[]){
System.out.println(String.class);
}
}                ③可以调用Class类的静态方法.forName()

public class Test{
public static void main(String args[]){
try {
System.out.println(Class.forName("java.lang.String"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

                ④原始包装类可以使用字段.Type

public class Test{
public static void main(String args[]){
System.out.println(Integer.TYPE);
}
}

        如果要获取布尔型的Class对象,可以使用如下方法,区别如下:

public class Test{
public static void main(String args[]){
//boolean b = true;
//System.out.println(b.getClass());   原始类的变量不能调用.getClass()方法
Class<?> c1=Boolean.TYPE;             //返回原始类型boolean
System.out.println(c1);
Class<?> c2=boolean.class;            //返回原始类型boolean
System.out.println(c2);
Class<?> c3=Boolean.class;            //返回class java.lang.Boolean
System.out.println(c3);
}
}

        2、创建对象:

                       ①使用Class对象的newInstance()方法,此方法只适用于无参数的构造方法:

public class Test{
public static void main(String args[]){
Class<?> clazz = String.class;
try {
Object str = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}

               ②使用Constructor对象的newInstance()方法:

                   1>如果是无参的构造方法:

import java.lang.reflect.*;

public class Test{
public static void main(String args[]){
Class<?> clazz = String.class;
try {
Constructor<?> c = clazz.getConstructor();
try {
Object str = c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
                   2>如果是有参的构造方法:
import java.lang.reflect.*;

public class Test{
public static void main(String args[]){
Class<?> clazz = String.class;
try {
Constructor<?> c = clazz.getConstructor(String.class);
try {
Object str = c.newInstance("Hello World");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}

        3、获取类的Fields(变量):

               ①public Field[] getFields():返回对应类/接口以及其所有父类/父接口的所有的公共变量;

               ②public Field getField(String name):返回对应类/接口以及其所有父类/父接口中指定名称的公共变量;

               ③public Field[] getDeclaredFields():返回对应类/接口中定义的所有的变量,但不包括继承来的变量;

               ④public Field getDeclaredField(String name):返回对应类/接口中定义过的指定名称的变量,但不包括继承来的变量;

假如有两个类有继承关系:

Test1:

public class Test1 {
private String a;
public String b;
}

Test2:

public class Test2 extends Test1 {
private String c;
public String d;
}通过反射获取变量时:
import java.lang.reflect.Field;

public class Test{
public static void main(String args[]){
Test2 t = new Test2();
Class<?> clazz = t.getClass();
Field[] fields1 = clazz.getFields();
for(Field f:fields1){
System.out.println(f.getName());    //取到b,d,无序
}
try {
System.out.println(clazz.getField("b")); //public java.lang.String Test1.b(能取到b,d,但取不到a,c)
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
Field[] fields2 = clazz.getDeclaredFields();
for(Field f:fields2){
System.out.println(f.getName());     //取到c,d,无序
}
try {
System.out.println(clazz.getDeclaredField("d")); //public java.lang.String Test2.d(能取到c,d,取不到a,b)

} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}


        由此可见getFields和getDeclaredFields区别:

        ①getFields():返回对应类/接口以及其所有父类/父接口的所有的public变量;

        ②getDeclaredFields():返回类/接口中定义的所有变量,不包括父类中的。

        4、设置和获取类的Fields(变量)的值:获取Class对象的Field对象后调用Field类中类似set(Object o,Object value)方法。

import java.lang.reflect.*;

public class Test{
public int a;
public String b;

public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public static void main(String args[]){
Class<?> clazz = Test.class;
try {
Object t = clazz.newInstance();
try {
Field f1 = clazz.getField("a");
Field f2 = clazz.getField("b");
try {
f1.setInt(t, 100);
f2.set(t, "Hello World");
int a = f1.getInt(t);
System.out.println(a);
String b = f2.get(t).toString();
System.out.println(b);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}        5、获取类的Methods(方法):

               ①public Method[] getMethods():返回对应类/接口以及其所有父类/父接口的所有的公共方法;

               ②public Method getMethod(String name,Class<?>... parameterTypes):返回对应类/接口以及其所有父类/父接口中指定名称和参数类型的公共方法;

               ③public Method[] getDeclaredMethods():返回对应类/接口中定义的所有方法,但不包括继承来的方法;

               ④public Method getDeclaredMethod(String name,Class<?>... parameterTypes)

:返回对应类/接口中定义过的指定名称的方法,但不包括继承来的方法;

假如有两个类有继承关系:

Test1:

public class Test1 {
private void a(){
}
private void a(int m,int n){
}
public void b(){
}
public void b(int m,int n){
}
}

Test2:

public class Test2 extends Test1 {
private void c(){
}
private void c(int m,int n){
}
public void d(){
}
private void d(int m,int n){
}
}

通过反射获取方法时:

import java.lang.reflect.Method;

public class Test{
public static void main(String args[]){
Test2 t = new Test2();
Class<?> clazz = t.getClass();
Method[] Method1 = clazz.getMethods();
for(Method m:Method1){
System.out.println(m);    //取到b,d,无序
}
try {
System.out.println(clazz.getMethod("b", int.class,int.class)); //public void Test1.b(int,int)(能取到b,d,但取不到a,c)
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
Method[] Method2 = clazz.getDeclaredMethods();
for(Method m:Method2){
System.out.println(m);    //取到c,d,无序
}
try {
System.out.println(clazz.getDeclaredMethod("d")); //public void Test2.d() )(能取到c,d,但取不到a,b)
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}

        6、获取类的Constructors(构造方法):

               ①public Constructor<?>[] getConstructors():返回对应类的公共构造方法,但不包括父类的构造方法;

               ②public Constructor<T> getConstructor(Class<?>... parameterTypes):返回对应类但不包括其父类的指定相同参数类型的公共构造方法;

               ③public Constructor<?>[] getDeclaredConstructors():返回对应类中定义的所有的构造方法,但不包括继承来的构造方法;

               ④public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回对应类中定义的指定参数类型的构造方法,但不包括继承来的构造方法;

假如有两个类有继承关系:

Test1:

public class Test1 {
public Test1(){
}
public Test1(int m){
}
public Test1(int m,int n){
}
private Test1(int m,int n,int x){
}
}

Test2:

public class Test2 extends Test1 {
public Test2(){
}
public Test2(String str){
}
public Test2(String str1,String str2){
}
private Test2(String str1,String str2,String str3){
}
}

通过反射获取方法时:

import java.lang.reflect.Constructor;

public class Test{
public static void main(String args[]){
Class<?> clazz = Test2.class;
Constructor<?>[] constructors1 = clazz.getConstructors();
for(Constructor<?> c:constructors1){
System.out.println(c);
}
try {
System.out.println(clazz.getConstructor(String.class,String.class));
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
}
Constructor<?>[] constructors2 = clazz.getDeclaredConstructors();
for(Constructor<?> c:constructors2){
System.out.println(c);
}
try {
System.out.println(clazz.getDeclaredConstructor(String.class,String.class,String.class));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}

        由此可见,获取构造方法与获取变量和方法的方法不同,它不能获取到其父类的构造方法。

        7、调用方法:获取Class对象的Method对象后调用Method类中invoke(Object o, Object... args)方法。

import java.lang.reflect.*;

public class Test{
public void testMethod(int a){
System.out.println("testMethod:"+a);
}
public static void main(String args[]){
Class<?> clazz = Test.class;
try {
Object t = clazz.newInstance();
try {
Method m = clazz.getMethod("testMethod", int.class);
try {
m.invoke(t, 3);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
}
        8、动态代理:动态代理即代理是在运行期发生的,而不是在编译上其发生的。

接口或抽象类:

public interface ProxyInterface {
public void say();
}

实际作用类:

public class RealPart implements ProxyInterface{
public void say() {
System.out.println("RealPart");
}
}

代理类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ProxyPart implements InvocationHandler {
private Object obj;
public ProxyPart(Object obj){
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(obj, args);
return null;
}
}

主入口:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test {
public static void main(String[] args) {
RealPart real = new RealPart();
InvocationHandler handler = new ProxyPart(real);
Class<?> clazz = handler.getClass();
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(clazz.getClassLoader(),real.getClass().getInterfaces(),handler);
System.out.println(proxy.getClass());
proxy.say();
}
}
参考:http://www.cnblogs.com/Quincy/archive/2011/06/19/2084557.html#



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  反射 Reflect 代理 Proxy