java反射

许多java对象在运行时表现出两种状态:编译时类型和运行时类型。例如:Person p = new Student();

为了解决这个问题,需要知道该对象运行时类型的方法。

第一种做法是假设在编译时和运行时完全知道类型的真实信息,这就可以用instanceof进行判断,然后利用强制类型转换将其转换成其运行时类型的变量。

第二种做法是编译时完全不知道这个对象可能属于哪些类,这时就必须要利用反射。


要获得Class对象,通常用下面三种方式:

1、Class类的静态方法,Class.forName()
2、类的class属性,Person.class
3、通过对象的getClass()方法。这个方法是java.lang.Object类中的方法。
1、2都是通过类来获取的,一般情况下用第二种比较好,直接调用属性。但是当程序只能获取到字符串如”java.lang.String”时,就只能用第一种了。

获得某个类对应的Class对象后,就可以调用Class对象的方法来获得该对象和该类的真实信息了,如类包含的构造器、方法、成员变量、Annotation、内部类、接口、继承的父类、修饰符、所在包、类名等等。


使用反射来生成对象有两种方式:

1,使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该对象的对应类有默认构造器。

2,先使用Class对象获取指定的Construtor对象,再调用Construtor对象的newInstance()方法来创建该Class对象对应类的实例。


使用反射调用方法:

获得类对应的Class对象后,可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或者指定方法,返回Method数组或者对象。

在Method中包含一个invoke()方法:public Object invoke(Object obj, Object... args),其中obj是执行该方法的主调,后面的args是传入的实参。


使用反射访问成员变量:

getField(String name)获取指定名称的public成员变量

getDeclaredField(String name)获取指定名称的成员变量,与访问权限无关。

Field提供了两组方法来读取或者设置成员变量值:

getXxx(Object obj),获取成员变量值,这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消get后面的Xxx。

setXxx(Object obj),设置成员变量值,这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消set后面的Xxx。


使用反射操作数组:

newInstance(Class<?> componentType, int... dimensions)创建一个指定元素类型,指定维度的新数组。

getXxx(Object array, int index) 这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消get后面的Xxx。

setFloat(Object array, int index, Xxx f) 这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消set后面的Xxx。

注意这些方法都是java.lang.reflect.Array的静态方法


如果在程序中为一个或多个接口动态生成实现类或创建实例,都可以使用Proxy生成动态代理。


使用泛型可以避免强制类型转换,下面代码在编译时不会发生错误,但是在运行时抛出异常:

public static Object getInstance(String clsName)
{
	try
	{
		// 创建指定类对应的Class对象
		Class cls = Class.forName(clsName);
		// 返回使用该Class对象所创建的实例
		return cls.newInstance();
	}
	catch(Exception e)
	{
		e.printStackTrace();
		return null;
	}
}
但是如果改成下面这样,就不会发生了:

public class CrazyitObjectFactory2
{
	public static <T> T getInstance(Class<T> cls)
	{
		try
		{
			return cls.newInstance();
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}
	public static void main(String[] args)
	{
		// 获取实例后无须类型转换
		Date d = CrazyitObjectFactory2.getInstance(Date.class);
		JFrame f = CrazyitObjectFactory2.getInstance(JFrame.class);
	}
}

使用反射来获取泛型信息:

public class GenericTest
{
	private Map<String , Integer> score;
	public static void main(String[] args)
		throws Exception
	{
		Class<GenericTest> clazz = GenericTest.class;
		Field f = clazz.getDeclaredField("score");
		// 直接使用getType()取出的类型只对普通类型的成员变量有效
		Class<?> a = f.getType();
		// 下面将看到仅输出java.util.Map
		System.out.println("score的类型是:" + a);
		// 获得成员变量f的泛型类型
		Type gType = f.getGenericType();
		// 如果gType类型是ParameterizedType对象
		if(gType instanceof ParameterizedType)
		{
			// 强制类型转换
			ParameterizedType pType = (ParameterizedType)gType;
			// 获取没有泛型信息的原始类型
			Type rType = pType.getRawType();
			System.out.println("原始类型是:" + rType);
			// 取得泛型参数的类型
			Type[] tArgs = pType.getActualTypeArguments();
			System.out.println("泛型信息是:");
			for (int i = 0; i < tArgs.length; i++)
			{
				System.out.println("第" + i + "个泛型类型是:" + tArgs[i]);
			}
		}
		else
		{
			System.out.println("获取泛型类型出错!");
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值