Java 反射Reflection

目录


Class对象

获得Class对象的三种方法

利用反射获取类的相关信息

利用反射来调用构造器、属性、普通方法

低效的反射--关闭安全检查

 

 

Class对象

  我们以前在使用new关键字来创建对象的时候,JVM会首先将该class加载,保存的是一个模子,之后使用new关键字来创建的对象保证都是一样的。这个模子保存了class的所有信息(结构和属性)。

  但是有时候,我们在工作中,需要实例化的类有时候是未知的(不同的情况需要实例化不同的类),此时,我们希望能动态的传入类的名字,然后在实例化这个类,而不是将类名写死。

  一个类型只对应一个Class对象

package lixin.gan.note;

public class Reflection01 {
	public static void main(String[] args) {
		try {
			String path = "lixin.gan.orm.annotation.Person";
			Class clas1 = Class.forName(path);
			Class clas2 = Class.forName(path);
			System.out.println(clas1.hashCode() == clas2.hashCode()); // true
			// 说明上面的两个类是一个Class对象
			
			// 注意,类型相同,则对应的Class对象相同,对于数组而言,与数组的元素类型和维数相关,与长度无关
			int[] a1 = new int[10];
			int[] a2 = new int[20];
			int[][] a3 = new int[10][20];
			System.out.println(a1.getClass().hashCode() == a2.getClass().hashCode());  // true
			System.out.println(a1.getClass().hashCode() == a3.getClass().hashCode());  // false
			
			double[] d4 = new double[10];
			System.out.println(d4.getClass().hashCode() == a1.getClass().hashCode());  // false
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}

  

 

获得Class对象的三种方法

package lixin.gan.basic;

import java.lang.reflect.InvocationTargetException;

class Person{
	private int id;
	private String name;
	public Person() {
		super();
	}
	public Person(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + "]";
	}
}


public class GetClassObject {
	public static void main(String[] args) {
				
		/**
		 * 方式1, 通过对象来获取
		 */
		Person p = new Person();
		Class personClass = p.getClass();
		
		
		/**
		 * 方式2, 使用类名
		 */
		personClass = Person.class;
		
		
		/**
		 * 方式3, 使用类的包名 + 类名
		 */
		try {
			personClass = Class.forName("lixin.gan.basic.Person");
			
			// 无参构造
			// Person p2 = (Person)personClass.getConstructor().newInstance();
			
			// 有参构造
			Person p2 = (Person)personClass.getConstructor(int.class, String.class).newInstance(1, "abc");
			
			System.out.println(p2);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
}

  

 

利用反射获取类的相关信息

package lixin.gan.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 利用反射,获取类的相关信息(类名、属性、方法、注解、构造器)
 */
public class GetClassObjectInfo {

	/**
	 * 获取类的名字
	 */
	public static void getClassName() {
		try {
			String path = "lixin.gan.orm.annotation.Person";
			Class clas = Class.forName(path);

			// 获得完整路径 + 类名
			System.out.println(clas.getName());  //  lixin.gan.orm.annotation.Person
			
			// 获得类名
			System.out.println(clas.getSimpleName());  // Person
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取属性信息
	 */
	public static void getFieldInfo() {
		try {
			String path = "lixin.gan.orm.annotation.Person";
			Class clas = Class.forName(path);

			/*
			 * 获取所有的public属性
			Field[] fields = clas.getFields();
			for (Field f : fields) {
				System.out.println(f);
			}
			*/
			
			/*
			 * 获取所有的属性(包括private)
			Field[] fields = clas.getDeclaredFields();
			for (Field field : fields) {
				System.out.println(field); // 默认打印属性的所有信息
				// private int lixin.gan.orm.annotation.Person.id
				
				System.out.println(field.getName());  // 只简单打印属性的名称
				// id
			}
			*/
			
			// 获取指定名称的属性
			Field field = clas.getDeclaredField("name");
			System.out.println(field + "--" + field.getName());
			// private java.lang.String lixin.gan.orm.annotation.Person.name--name
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 获取对象的方法
	 */
	public static void getMethodInfo() {
		try {
			String path = "lixin.gan.orm.annotation.Person";
			Class clas = Class.forName(path);

			/*
			 * 获取所有public的方法,注意,包含很多从父类中继承而来的public方法
			Method[] methods = clas.getMethods();
			for(Method method : methods) {
				System.out.println(method);
			}
			*/
			
			/*
			 * 获取所有public的方法
			 * 注意,只返回自己定义的方法,不会包含从父类中继承而来的public方法
			Method[] methods = clas.getDeclaredMethods();
			for(Method method : methods) {
				System.out.println(method);
			}
			*/
			
			// 获取指定的方法名称,需要指定方法的参数类型,因为可能会出现重载的多个同名方法
			Method method = clas.getDeclaredMethod("setName", String.class);
			System.out.println(method);
			// public void lixin.gan.orm.annotation.Person.setName(java.lang.String)
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 获取构造器的信息
	 */
	public static void getConstructorInfo() {
		try {
			String path = "lixin.gan.orm.annotation.Person";
			Class clas = Class.forName(path);
			
			// 获取所有public的构造器
			//Constructor[] constructors = clas.getConstructors();
			
			// 获取所有的构造器
			Constructor[] constructors = clas.getDeclaredConstructors();
			
			// 获取指定的构造器,需要传入参数,因为构造器可能会重载,不传入参数,表示无参构造器
			Constructor constructor = clas.getDeclaredConstructor(int.class, String.class, String.class);
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
	}
	
	public static void main(String[] args) {
		getConstructorInfo();

	}
}

  

 

利用反射来调用构造器、属性、普通方法

package lixin.gan.test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import lixin.gan.annotation.MyField;
import lixin.gan.annotation.MyTable;
import lixin.gan.annotation.Person;

/**
 * 通过反射,动态使用构造器、方法、属性、注解
 */
public class ReflectionToUse {
	
	/**
	 * 利用反射来实例化对象
	 */
	public static void getInstance() {
		try {
			String path = "lixin.gan.orm.annotation.Person";
			
			/*使用泛型
			Class<Person> clas =(Class<Person>)Class.forName(path);
			Person p = clas.newInstance(); // 调用无参构造方法
			System.out.println(p);  // Person [id=0, name=null, gender=null]
			*/
			
			/* 使用强制类型转换
			Class clas = Class.forName(path);
			Person p = (Person)clas.newInstance();
			System.out.println(p);
			*/
			
			/*通过选定构造器来获取对象实例*/
			Class clas = Class.forName(path);
			Constructor<Person> constructor = clas.getConstructor(int.class, String.class, String.class);
			Person p = constructor.newInstance(100, "ganlixin", "male");
			System.out.println(p);
			// Person [id=100, name=ganlixin, gender=male]
			
			// 一步完成可以写成
			p = (Person) clas.getConstructor(int.class, String.class, String.class).newInstance(1001, "xyz", "male");
			System.out.println(p);
			// Person [id=1001, name=xyz, gender=male]
			// 注意上面用得是getConstructor,也可以使用getDeclaredConstructor,毕竟,能够调用,应该就是public的
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	
	/**
	 * 利用反射来调用普通方法
	 */
	public static void callSimpleMethod() {
		String path = "lixin.gan.orm.annotation.Person";
		try {
			Class clas = Class.forName(path);
			Constructor<Person> constructor = clas.getDeclaredConstructor(int.class, String.class, String.class);
			Person person = constructor.newInstance(100, "xyz", "male");
			System.out.println(person);
			
			// 获取要调用的方法,注意传入参数列表的类型,因为可能出现重载
			Method method = clas.getDeclaredMethod("setName", String.class);
			// method.invode(obj, args);  调用obj对象的method方法,参数是args
			method.invoke(person, "abc");
			System.out.println(person);
			// Person [id=100, name=abc, gender=male]
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 操作属性
	 */
	public static void manageField() {
		String path = "lixin.gan.orm.annotation.Person";
		try {
			Class clas = Class.forName(path);
			Constructor<Person> constructor = clas.getDeclaredConstructor(int.class, String.class, String.class);
			Person person = constructor.newInstance(100, "xyz", "male");
			System.out.println(person);
			
			// 直接通过getter或者setter来 获取、设置属性值
			person.getName();  
			
			Field field = clas.getDeclaredField("name");
			/*
			 * // 直接设置或者访问属性值,如果没有访问权限,就会出错
			 * field.get(person)
			 * field.set(person, "aaaa"); 
			 */
			
			// 正确方式,应该先设置为可获取
			field.setAccessible(true);
			System.out.println(field.get(person));  // xyz
			field.set(person, "aaa");
			System.out.println(person);
			// Person [id=100, name=aaa, gender=male]
			
			/**
			 * field.get(obj) 表示获取obj对象的field属性
			 * field.set(obj, value) 表示设置obj的field属性值
			 */
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取注解的相关信息
	 */
	public static void getAnnotationsInfo() {
		String path = "lixin.gan.orm.annotation.Person";
		
		try {
			Class clas = Class.forName(path);
			Person p = (Person)clas.getConstructor(int.class, String.class, String.class).newInstance(100, "hello", "male");
			
			// 获得类的所有注解,注意是类的,而不是属性的
			Annotation[] annotations = clas.getDeclaredAnnotations();
			for (Annotation a : annotations) {
				System.out.println(a);
			}
			/*
			@lixin.gan.orm.annotation.MyTable(value=Person)
			@lixin.gan.orm.annotation.MyAnnotation2(value=hehe)
			 */
			
			// 获得类的指定注解
			// 假设我已经知道该类有哪些注解,我现在想知道其中一个注解的相关信息,
			Annotation annotation = clas.getDeclaredAnnotation(MyTable.class);
			System.out.println(annotation);
			// @lixin.gan.orm.annotation.MyTable(value=person)
			System.out.println(((MyTable)annotation).value());  // person
			
			// 也可以这样
			MyTable myTableAnnotation = (MyTable) clas.getDeclaredAnnotation(MyTable.class);
			System.out.println(myTableAnnotation);
			// @lixin.gan.orm.annotation.MyTable(value=person)
			System.out.println(myTableAnnotation.value());		// person
			
			
			// 获得属性的注解, 和获得类的注解是一样的
			// 注意,需要先获得属性,然后通过属性来获取注解
			Field field = clas.getDeclaredField("name");
			MyField myFieldAnnotation = field.getDeclaredAnnotation(MyField.class);
			System.out.println(myFieldAnnotation);
			// @lixin.gan.orm.annotation.MyField(canEmpty=true, primaryKey=false, columnName=name, type=varchar, length=30)
			
			System.out.println(myFieldAnnotation.columnName() + "--" + myFieldAnnotation.type() + "--" + myFieldAnnotation.length());
			// name--varchar--30
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		getAnnotationsInfo();
	}
}

  

 

低效的反射--关闭安全检查

  为了提高反射的效率,可以通过setAccessible(true)来关闭权限检测。

package lixin.gan.test;

import java.lang.reflect.Method;

/**
 * 测试效率
 */
class Person {
	private String name;
	
	public Person(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
}

public class TestEfficiency{
	
	/**
	 * 使用最原始的方式来调用方法
	 */
	public static void test1() {
		Person person = new Person("Jane");
		
		for (int i = 0; i < 100000000L; i++) {
			person.getName();
		}
	}
	
	/**
	 * 使用反射的方式来调用方法,并且每次都要进行权限检查(private、protected、public、default)
	 */
	public static void test2() {
		try {
			Class clas = Class.forName("lixin.gan.note.Person");
			
			Person person = (Person)clas.getConstructor(String.class).newInstance("Jane");
			
			Method method = clas.getDeclaredMethod("getName", null);
			// 通常,在调用一个方法的时候,我们会先检查权限问题,比如private的权限,不能在外部访问或调用。
			// 所以下面的1亿次的调用,就会进行1亿次权限检查
			
			for (int i = 0; i < 100000000L; i++) {
				method.invoke(person, null);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 同样使用反射的方式调用方法,只不过在调用之前,关闭权限检查,这样的话,不用每次调用方法都进行权限检查了
	 */
	public static void test3() {
		try {
			Class clas = Class.forName("lixin.gan.note.Person");
			
			Person person = (Person)clas.getConstructor(String.class).newInstance("Jane");
			
			Method method = clas.getDeclaredMethod("getName", null);
			
			method.setAccessible(true);
			// 通常,在调用一个方法的时候,我们会先检查权限问题,比如private的权限,不能在外部访问或调用。
			// 通过这一步设置后,之后调用这个方法,就不会进行权限检查了,即使他是private,也是可以调用的
			
			for (int i = 0; i < 100000000L; i++) {
				method.invoke(person, null);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		long start, end;
		
		start = System.currentTimeMillis();
		test1();
		end = System.currentTimeMillis();
		System.out.println("test1 耗费了 " + (end-start) + " 毫秒");
		
		start = System.currentTimeMillis();
		test2();
		end = System.currentTimeMillis();
		System.out.println("test2 耗费了 " + (end-start) + " 毫秒");
		
		start = System.currentTimeMillis();
		test3();
		end = System.currentTimeMillis();
		System.out.println("test3 耗费了 " + (end-start) + " 毫秒");
		
		/*
		统计数据如下:
		test1   147毫秒		148 毫秒		147 毫秒
		test2   1043 毫秒		938 毫秒		936 毫秒
		test3	477 毫秒		469 毫秒		470 毫秒
		 */
	}
}

  

 

posted @ 2018-11-18 10:51  寻觅beyond  阅读(255)  评论(0)    收藏  举报
返回顶部