Java之反射

55 篇文章 0 订阅
33 篇文章 0 订阅

        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();
		}
	}
}(能取到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();
		}
	}
}(能取到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#

 

 

 

 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值