java反射机制

本文深入解析Java反射机制,包括获取Class对象的三种方式,利用反射获取类的信息,动态操作构造器、方法和属性,以及反射机制的性能影响。同时,探讨了泛型在反射中的应用。
  1. 获取Class对象的三种方式
1. 通过对象的getClass()方法
Class c1=(new User()).getClass();

2. 通过字节码文件获取
Class c2=User.class;

3. 通过Class类的静态方法获取
Class c3=Class.forName("com.bee.entity.User");
  1. 同一个类只会被加载一次
public class Test {

	public static void main(String[] args) {
		String path = "demo6.TestBean";
		try {
			Class<?> clazz1 = Class.forName(path);
			System.out.println(clazz1.hashCode());

			Class<?> class2 = Class.forName(path);
			System.out.println(class2.hashCode());

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

输出

366712642
366712642

Class对象专门用来存放类的信息。一个类只对应一个Class对象。因为,类的对象虽然可以有多个,但对应的类只有一个。

  1. 利用反射获取类的信息

先定义一个类TestBean

public class TestBean {
	private String name;
	private int age;

	public TestBean() {
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public TestBean(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
}

读取上述类TestBean的信息

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

public class Test {

	public static void main(String[] args) {
		String path = "demo.TestBean";
		try {
			Class<?> clazz = Class.forName(path);

			// 获取类的名字
			System.out.println(clazz.getName()); // 获得包全路径名
			System.out.println(clazz.getSimpleName()); // 只获得类名

			// 获取属性信息
			Field[] fields1 = clazz.getFields(); // 只能获取public属性
			Field[] fields2 = clazz.getDeclaredFields(); // 可以获得private属性(可以获得所有的属性)
			Field field3 = clazz.getDeclaredField("name");
			for (Field field : fields2) {
				System.out.println("属性:" + field);
			}

			// 获取方法信息
			// clazz.getMethod(name, parameterTypes) 只能获得public方法
			Method[] methods = clazz.getDeclaredMethods();
			Method method1 = clazz.getDeclaredMethod("getName", null);
			// 如果方法有参数,必须传递参数类型对应的Class对象。
			Method method2 = clazz.getDeclaredMethod("setName", String.class);
			for (Method method : methods) {
				System.out.println("方法:" + method);
			}

			// 获得构造器信息
			// Constructor[] constructors=clazz.getConstructors() 只能获得public构造方法
			Constructor[] constructors = clazz.getDeclaredConstructors();
			for (Constructor constructor : constructors) {
				System.out.println("构造器:" + constructor);
			}
			// 获取无参构造器
			Constructor cons1 = clazz.getDeclaredConstructor(null);
			System.out.println("无参构造器:" + cons1);
			// 获取有参构造器
			Constructor cons2 = clazz.getDeclaredConstructor(String.class, int.class);
			System.out.println("有参构造器:" + cons2);

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
  1. 通过反射动态操作构造器,方法,属性
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test {

	public static void main(String[] args) {
		String path = "demo.TestBean";
		try {
			Class<TestBean> clazz = (Class<TestBean>) Class.forName(path);

			// 通过反射构造对象
			TestBean tb = clazz.newInstance(); // 调用TestBean的无参构造方法
			// 对于JavaBean/POJO/DTO必须要配置一个无参构造器,以便框架使用newInstance()构建对象实例。
			System.out.println(tb);

			// 调用有参构造器
			Constructor<TestBean> cons1 = clazz.getDeclaredConstructor(String.class, int.class);
			TestBean tb1 = cons1.newInstance("黄忠", 83);
			System.out.println(tb1.getName() + tb1.getAge() + "岁");

			// 通过反射调用普通方法
			TestBean tb2 = clazz.newInstance();
			tb2.setName("云长"); // 等效于下边的invoke()方法
			tb2.setAge(57); // 等效于下边的invoke()方法

			TestBean tb3 = clazz.newInstance();
			Method method1 = clazz.getDeclaredMethod("setName", String.class);
			Method method2 = clazz.getDeclaredMethod("setAge", int.class);
			method1.invoke(tb3, "玄德");
			method2.invoke(tb3, 66);
			System.out.println(tb3.getName() + tb3.getAge() + "岁");

			// 通过反射操作属性
			TestBean tb4 = clazz.newInstance();
			Field f1 = clazz.getDeclaredField("name");
			Field f2 = clazz.getDeclaredField("age");

			// 报错不能访问私有属性的解决方法(属性可以设置,方法也可以这样设置)
			f1.setAccessible(true);
			f2.setAccessible(true);

			f1.set(tb4, "紫龙");
			f2.set(tb4, 33);
			System.out.println(tb4.getName() + f2.get(tb4) + "岁");

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
  1. 反射机制的性能
  • setAccessible
  1. 是访问安全检查的开关。设置true表示反射的对象在使用时应该取消Java语言访问检查。
  2. 禁止安全检查可以提高反射的运行速度。
  • 可以考虑使用cglib/javaassist字节码操作提升反射操作的速度。
  1. 反射操作泛型(Generic)
  • Java使用泛型擦除机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的。泛型用于确保数据的安全性和免去强制类型转换带来的不便。Java一旦编译完成,所有和泛型有关的类型将全部擦除。
  • Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型,但又和原始类型保持一致。
  1. ParameterizedType:表示一种参数化的类型,比如:Collection
  2. GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
  3. TypeVariable:是各种类型变量的公共父接口
  4. WildcardType:代表一种通配符类型表达式,比如:?,? extends Number,? super Integer。
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Test {

	public void test1(Map<String, TestBean> map, List<TestBean> list) {
		System.out.println("Test.test1()");
	}

	public Map<Integer, TestBean> test2() {
		System.out.println("Test.test2()");
		return null;
	}

	public static void main(String[] args) {
		try {
			// 获得指定方法参数泛型信息
			Method m = Test.class.getMethod("test1", Map.class, List.class);
			Type[] t = m.getGenericParameterTypes();
			for (Type type : t) {
				System.out.println("#" + type);
				if (type instanceof ParameterizedType) {
					Type[] genericTypes = ((ParameterizedType) type).getActualTypeArguments();
					for (Type genericType : genericTypes) {
						System.out.println("泛型类型:" + genericType);
					}
				}
			}

			System.out.println("-------------------");

			// 获得指定方法返回值泛型信息
			Method m2 = Test.class.getMethod("test2", null);
			Type returnType = m2.getGenericReturnType();
			System.out.println("#" + returnType);
			if (returnType instanceof ParameterizedType) {
				Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
				for (Type type : genericTypes) {
					System.out.println("返回值泛型类型:" + type);
				}
			}

		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}

	}

}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值