反射笔记

Java反射机制主要提供以下功能:
● 1.在JVM运行时判断任意一个对象所属的类;
● 2.在JVM运行时构造任意一个类的对象;
● 3.在JVM运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
● 4.在JVM运行时调用任意一个对象的方法
● 5.生成动态代理

java.lang.Class类和java.lang.reflect包中的Field、Constructor、Method、Array类。
Class是java反射的起源,对任何想探测的类必须产生一个Class类的对象;Class类的实例表示正在运行的Java应用程序中的类和接口。
Field类提供有关的类和接口的属性,和动态访问权限。(封装反射类的属性)
Constructor类(封装反射类的构造方法);Method类封装反射类的方法;Array类封装静态方法。

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

反射:程序运行时,需要动态的加载一些类,这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载。例如我们的项目底层数据库使用mysql或者oracle,需要动态加载驱动类,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们要用,这时候我们的程序就写得比较动态化,通过Class tc =Class.forName(“com.java.dbtest.TestConnection”);通过类的全类名让jvm在服务器中找到并加载这个类,而如果是oracle则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出java的特性了!用spring当你配置各种各样的bean时,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载。(–某大佬的解释)

获得Class对象:

  1. Object类中的getClass()方法:
  2. Class类中的forName()静态方法
  3. 直接获取某对象的class:
    创建实例:
  4. 调用无参的构造方法创建指定名称的类的对象,Class对象的newInstance()方法来创建Class对象对应类的实例。
    Class c =Class.forName(“java.util.Date”);
    List list=(List)c.newInstance();
  5. 使用带参构造方法创建指定类的对象,先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
    //1.获取String所对应的Class对象
    Class c = String.class;
    //2.获取String类带一个String参数的构造器
    Constructor constructor = c.getConstructor(String.class);
    //3.根据构造器创建实例
    Object obj = constructor.newInstance(“23333”);
    System.out.println(obj);
    调用方法:
  6. getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
    public Method[] getDeclaredMethods() throws SecurityException
  7. getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
    public Method[] getMethods() throws SecurityException
  8. getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
    public Method getMethod(String name, Class<?>… parameterTypes)
    栗子:public static void main(String[] args) {
    Class<?> c = methodClass.class;
    Object object = c.newInstance();
    Method[] methods = c.getMethods();
    Method[] declaredMethods = c.getDeclaredMethods();
    // 获取methodClass类的add方法
    Method method = c.getMethod(“add”, int.class, int.class);
    // getMethods()方法获取的所有方法
    System.out.println(“getMethods获取的方法:”);
    for (Method m : methods)
    System.out.println(m);
    // getDeclaredMethods()方法获取的所有方法
    System.out.println(“getDeclaredMethods获取的方法:”);
    for (Method m : declaredMethods)
    System.out.println(m);
    }
// 调用无参的构造方法创建指定名称的类的对象
	public static void main(String[] args) {
		Date currentDate = (Date) newInstance("java.util.Date");
		System.out.println(currentDate);
	}

    public static Object newInstance(String className) {
		Object obj = null;
		// 获取指定名称类的Class对象
			obj = Class.forName(className).newInstance();
		return obj;

	}
// 利用反射使用带参构造方法创建指定类的对象
	public static void main(String[] args) {
		Class claszz;
			claszz = Class.forName("java.util.Date");
			// 获取具有指定参数类型的构造方法
			Constructor constructor = claszz.getConstructor(long.class);
			// 给指定的构造方法传参数,创建对象.
			Date date = (Date) constructor.newInstance(123456789000L);
			System.out.println(date);
	    
	}
package testReflection;
public class ReflectInvokeMethodTest {
	// 动态调用指定类的指定方法
	public static void main(String[] args) {
			Class clazz = Class.forName("testReflection.Product");
			// 创建Product对象
			Product product = (Product) clazz.newInstance();
			// 获取名为setName,带一个string类型参数的成员方法所对应的对象代表
			Method method = clazz.getDeclaredMethod("setName", String.class);
			// 在product对象上调用setName并传值给他,返回值为空
			Object returnValue = method.invoke(product, "java");
			System.out.println("返回值" + returnValue);
			// 获取名为displayInfo,不带参数的成员方法
			Method method2 = clazz.getDeclaredMethod("displayInfo");
			// 取消访问检查
			method2.setAccessible(true);
			// 在Product对象上调用私有的displayInfo方法
			method2.invoke(product);//incoke()真正执行
	}
}
class Product {
	private static long count = 0;
	private long id;
	private String name = "无名氏";
	public Product() {id = ++count;}
	public long getId() {return id;}
	public void setId(long id) {this.id = id;}
	public String getName() {return name;}
	public void setName(String name) {
	System.out.println("调用setName方法");
		this.name = name;
	}
	private void displayInfo() {
	System.out.println(getClass().getName() + "id=" + id + "name=" + name);
	}
}

public class ReflectFiledTest {
	// 动态获取或设置指定对象的指定成员变量的值
	@SuppressWarnings({ "deprecation", "rawtypes" })
	public static void main(String[] args) {
		
			Class c = Class.forName("testReflection.Product");
			// 使用无参构造方法创建对象
			Product prod = (Product) c.newInstance();
			// 获取私有属性
			Field iField = c.getDeclaredField("id");
			iField.setAccessible(true);// 取消本字段的访问检查
			// 设置prod对象的iField成员变量的值为100
			iField.setLong(prod, 100);
			// 获取prod对象的IFiled成员变量的值
			System.out.println("id:" + iField.getLong(prod));
			Field nameField = c.getDeclaredField("name");
			nameField.setAccessible(true);
			nameField.set(prod, "赵四");
			System.out.println("name" + nameField.get(prod));

	}
}
public class ReflectArrayTest {
	// 反射获取数组信息
	public static void main(String[] args) {
		int[] iArr = new int[5];
		double[] dArr = new double[5];
		String[] sArr = new String[5];
		// iArr.getClass().getName();先用getComponentType()获取对象;
		System.out.println("数组限定名:" + iArr.getClass().getComponentType().getName());
		System.out.println("数组限定名:" + dArr.getClass().getComponentType().getName());
		System.out.println("数组限定名:" + sArr.getClass().getComponentType().getName());
		// 动态创建数组
			Class<?> cla1 = Class.forName("java.lang.String");
			Object array = Array.newInstance(cla1, 25);
			// 加数据
			for (int i = 0; i < 5; i++) {
				Array.set(array, i, "number:" + i);
			}
			// 拿数据
			System.out.println(Array.get(array, 3));
	}

}

由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

posted @ 2018-01-31 22:30  小沐酱  阅读(1)  评论(0编辑  收藏  举报  来源