Java动态性--->1 反射简介

1  动态语言:



 

1 Java语言动态性:



 

2 Java反射机制:



 

3 Java反射机制应用场景:



 

4  反射实例代码

1 bean

public class User {
	
	private int id;
	private int age;
	private String uname;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getUname() {
		return uname;
	}
	
	public void setUname(String uname) {
		this.uname = uname;
	}
	
	public void setUname() {
		this.uname = "zm";
	}
	
	private void test(){
		System.out.println("hadoop5");
	}
	
	public User(int id, int age, String uname) {
		super();
		this.id = id;
		this.age = age;
		this.uname = uname;
	}
	
	//javabean必须要有无参的构造方法! 以方便反射下 User u = clazz.newInstance();
	public User() {
	}
}



2 反射代码


public static void main(String[] args) {

		String path = "com.test.bean.User";
		
		try {
			Class<User> clazz = (Class<User>) Class.forName(path);
			
			//通过反射API调用构造方法,构造对象
			User u = clazz.newInstance();	//其实是调用了User的无参构造方法
			System.out.println(u);
			
			Constructor<User> c = clazz.getDeclaredConstructor(int.class,int.class,String.class);
			User u2 = c.newInstance(1001,18,"zm二");
			System.out.println(u2);
			System.out.println(u2.getUname()); // 通过反射创建实例对象后 可以直接调用对象里的Public方法
			
			//通过反射API调用普通方法
			User u3 = clazz.newInstance();
			Method method = clazz.getDeclaredMethod("setUname", String.class);// 别人给我传什么方法名 我就调用这个方法 实现动态调用方法
			method.invoke(u3, "zm三");   //u3.setUname("zm三");
			System.out.println(u3.getUname()); // zm三
			
			//通过反射API操作属性
			User u4 = clazz.newInstance();
			Field f = clazz.getDeclaredField("uname");
			f.setAccessible(true); //这个属性不需要做安全检查了,可以直接访问
			f.set(u4, "zm四");		//通过反射直接写属性
			System.out.println(u4.getUname());	//通过反射直接读属性的值
			System.out.println(f.get(u4));
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	
		
	}

5 反射带来的效率下降问题:

 反射机制下回导致性能低下, 如果必须使用反射,可以建议 将 setAccessible设置为true,

 表示反射的对象在使用时取消Java语言访问检查,

通常,

不使用反射代码效率 =  [20,30]*使用反射(setAccessible为false)

使用反射(setAccessible为false)效率 = 4*使用反射(setAccessible为true)

代码测试如下:

/**
 * 通过跳过安全检查,提高反射效率
 * 三种执行方法的效率差异比较
 * 
 * 结果:
 * 普通方法调用,执行10亿次,耗时:4549ms
反射动态方法调用,执行10亿次,耗时:88568ms
反射动态方法调用,跳过安全检查,执行10亿次,耗时:22170ms

 *
 */
public class Demo06 {
	
	public static void test01(){
		User u = new User();
		
		long startTime = System.currentTimeMillis();
		
		for (int i = 0; i < 1000000000L; i++) {
			u.getUname();
		}
		
		long endTime = System.currentTimeMillis();
		System.out.println("普通方法调用,执行10亿次,耗时:"+(endTime-startTime)+"ms"); 
	}
	
	public static void test02() throws Exception{
		User u = new User();
		Class clazz = u.getClass();
		Method m = clazz.getDeclaredMethod("getUname", null);
//		m.setAccessible(true);
		
		long startTime = System.currentTimeMillis();
		
		for (int i = 0; i < 1000000000L; i++) {
			m.invoke(u, null);
		}
		
		long endTime = System.currentTimeMillis();
		System.out.println("反射动态方法调用,执行10亿次,耗时:"+(endTime-startTime)+"ms");
	}
	
	public static void test03() throws Exception{
		User u = new User();
		Class clazz = u.getClass();
		Method m = clazz.getDeclaredMethod("getUname", null);
		m.setAccessible(true);	//不需要执行访问安全检查
		
		long startTime = System.currentTimeMillis();
		
		for (int i = 0; i < 1000000000L; i++) {
			m.invoke(u, null);
		}
		
		long endTime = System.currentTimeMillis();
		System.out.println("反射动态方法调用,跳过安全检查,执行10亿次,耗时:"+(endTime-startTime)+"ms");
	}
	
	
	public static void main(String[] args) throws Exception {
		test01();
		test02();
		test03();
	}
	
}

6 反射得到方法参数泛型类型和返回值泛型类型



 

/**
 * 通过反射获取泛型信息
 * 
#java.util.Map<java.lang.String, com.bjsxt.test.bean.User>
泛型类型:class java.lang.String
泛型类型:class com.bjsxt.test.bean.User
#java.util.List<com.bjsxt.test.bean.User>
泛型类型:class com.bjsxt.test.bean.User
返回值,泛型类型:class java.lang.Integer
返回值,泛型类型:class com.bjsxt.test.bean.User
 *
 */
public class Demo04 {
	
	public void test01(Map<String,User> map,List<User> list){
		System.out.println("Demo04.test01()");
	}
	
	public Map<Integer,User> test02(){
		System.out.println("Demo04.test02()");
		return null;
	}
	
	public static void main(String[] args) {

		try {
			
			//获得指定方法参数泛型信息
			Method m = Demo04.class.getMethod("test01", Map.class,List.class);
			Type[] t = m.getGenericParameterTypes();
			for (Type paramType : t) {
				System.out.println("#"+paramType);
				if(paramType instanceof ParameterizedType){
					Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
					for (Type genericType : genericTypes) {
						System.out.println("泛型类型:"+genericType);
					}
				}
			}
			
			//获得指定方法返回值泛型信息
			Method m2 = Demo04.class.getMethod("test02", null);
			Type returnType = m2.getGenericReturnType();
			if(returnType instanceof ParameterizedType){
					Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();

					for (Type genericType : genericTypes) {
						System.out.println("返回值,泛型类型:"+genericType);
					}
					
			}
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	
		
	
	}
}

7  反射操作注解 ----> 见  注解定义使用---orm映射注解使用简单介绍

8  反射main函数要注意的事:

Method m = c.getMethod("main",String[].class);
             m.invoke(null, (Object)new String[]{});
             //由于可变参数是JDK5.0之后才有。 如果在反射main函数时不加上 (Object)强转成一个参数的话 会编译成:m.invoke(null,"aa","bb"),就发生了参数个数不匹配的问题。
             //m.invoke(null, (Object)new String[]{});  OK 
             //因此,必须要加上(Object)转型,避免这个问题。
             //public static void main(String[] args)

猜你喜欢

转载自chengjianxiaoxue.iteye.com/blog/2183696