码迷,mamicode.com
首页 > 编程语言 > 详细

【Java】(2)Java反射

时间:2015-07-29 14:05:34      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

1. 概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。


2. 获取Class对象

public class ClassDemo1 {
	public static void main(String[] args) {
		try {
			Entity foo1 = new Entity();
			// 获得Class对象的两种方式:
			Class c1 = Entity.class;
			Class c2 = foo1.getClass();
			Class c3 = Class.forName("com.thr.reflect.Entity");
			// 不管c1还是c2,都代表了Entity的class的对象
			System.out.println(c1 == c2);
			// c3也是Entity的class对象
			System.out.println(c1 == c3);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

}

class Entity {

}
三种方式获取的Class对象是一致的。

通过Class对象我们还可以创建类:

			Entity en = (Entity) c1.newInstance();

通过获取的这个对象就可以像用new创建出来的对象一样使用Entity内部的方法等。


3. 动态加载类

首先创建一个接口:

public interface Singable {

	void sing();
}
然后写两个实现类:
public class Bird implements Singable {

	@Override
	public void sing() {
		System.out.println("Bird sing...");
	}

}
public class Cat implements Singable {

	@Override
	public void sing() {
		System.out.println("Cat sing...");
	}

}

最后再主程序中动态加载类:

public class World {

	public static void main(String[] args) {

		try {
			Class c = Class.forName(args[0]);
			Singable singable = (Singable) c.newInstance();
			singable.sing();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
}

运行时要传入类的全名参数。


4. 获取方法信息

首先来看基本数据类型的Class对象:

public class ClassDemo2 {

	public static void main(String[] args) {
		Class[] cs = new Class[] { int.class, String.class, double.class,
				Double.class, void.class, Class.class };

		for (Class c : cs) {
			System.out.println(c.getName());
			System.out.println(c.getSimpleName());
		}
	}
}
我们编写一个获取类的方法的工具方法:
	public static void printClassMethods(Object obj) {
		// 首先获取Class对象
		Class c = obj.getClass();
		// 获取类的名称
		System.out.println("类的名称是:" + c.getName());
		// 获取类的方法,一个Method的对象就是一个成员方法,通过getMethods()获取的是所有public的方法,包括从父类继承而来的
		// getDeclaredMethods()获取的是所有该类自己生命的方法,不问访问权限
		Method[] ms = c.getMethods();
		for (Method m : ms) {
			// 获取返回值类型
			Class returnType = m.getReturnType();
			System.out.print(returnType.getName() + " ");
			// 获取方法名
			System.out.print(m.getName() + "(");
			// 获取参数类型
			Class[] paramTypes = m.getParameterTypes();
			for (Class type : paramTypes) {
				System.out.print(type.getName() + ",");
			}
			System.out.println(")");
		}
	}
使用它:
	public static void main(String[] args) {
		String s = new String();
		ClassUtil.printClassMethods(s);

		Integer i = 1;
		ClassUtil.printClassMethods(i);
	}

5. 获取成员变量和构造函数信息

获取成员变量信息:

	public static void printClassFields(Object obj) {
		// 首先获取Class对象
		Class c = obj.getClass();
		// 使用getFields()获取的是所有public的成员变量信息,使用getDeclaredFields获取的是该类自己声明的成员变量信息,不问访问权限
		Field[] fs = c.getDeclaredFields();
		for (Field f : fs) {
			// 获取成员变量的类型
			Class fieldType = f.getType();
			String typeName = fieldType.getName();
			// 获取成员变量的名字
			String filedName = f.getName();
			System.out.println(typeName + " " + filedName);
		}
	}
获取构造方法信息:
	public static void printClassConstructor(Object obj) {
		// 首先获取Class对象
		Class c = obj.getClass();
		Constructor[] cons = c.getDeclaredConstructors();
		for (Constructor con : cons) {
			// 获取方法名
			System.out.print(con.getName() + "(");
			// 获取参数类型
			Class[] paramTypes = con.getParameterTypes();
			for (Class type : paramTypes) {
				System.out.print(type.getName() + ",");
			}
			System.out.println(")");
		}
	}

6. 方法反射的基本操作

所有的方法对象都有一个invoke方法我们调用method.invoke(对象, 参数列表)就可以执行方法:

public class MethodDemo1 {
	public static void main(String[] args) {
		try {
			// 获取print(int, int)方法
			A a = new A();
			Class c = a.getClass();
			Method m1 = c.getMethod("print", int.class, int.class);
			// 执行方法,使用o来接受返回值
			// 如果有返回值,那么Object就是返回值的类型;没有返回值就返回null
			Object o1 = m1.invoke(a, 10, 10);
			// 获取print(String, String)方法
			Method m2 = c.getMethod("print", new Class[] { String.class,
					String.class });
			Object o2 = m2.invoke(a, "s1", "s2");
			// 获取print()方法
			Method m3 = c.getMethod("print");
			Object o3 = m3.invoke(a);
			System.out.println(o1);
			System.out.println(o2);
			System.out.println(o3);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}

class A {

	public void print() {
		System.out.println("hello");
	}

	public int print(int a, int b) {
		System.out.println(a + b);
		return a + b;
	}

	public String print(String a, String b) {
		System.out.println(a.toUpperCase() + "," + b.toLowerCase());
		return a + b;
	}
}

7. 泛型的本质

	public static void main(String[] args) {
		List list1 = new ArrayList();
		List<String> list2 = new ArrayList<String>();
		Class c1 = list1.getClass();
		Class c2 = list2.getClass();
		System.out.println(c1 == c2);
		// 反射的操作都是编译之后的操作
		// c1==c2是true说明编译之后集合的泛型是去泛型化的
		// Java中集合的泛型是防止错误输入的,只在编译阶段有效,绕过编译就无效了
		// 我们可以通过方法的反射来绕过编译
		Method m;
		try {
			m = c1.getMethod("add", Object.class);
			m.invoke(list1, 100);
			System.out.println(list1.size());
			System.out.println(list1);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
通过这个例子可以看到通过Java的反射机制可以绕过编译,是在运行时刻执行的,自然就可以绕过集合的泛型。


版权声明:本文为博主原创文章,未经博主允许不得转载。

【Java】(2)Java反射

标签:

原文地址:http://blog.csdn.net/scarthr/article/details/47122111

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!