欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java 的反射机制

程序员文章站 2022-06-18 11:28:37
...
Java 的反射机制一之Class类
一、 Java反射机制
二、 Class类 
三、 通过反射创建运行时类的对象
四、 通过反射获取运行时类的完整结构 及调用运行时类的指定属性、指定方法等
14.6 反射的应用:动态代理

一、Java反射机制

1)Java反射机制

反射(Reflection)被视为动态语言的关键,反射机制允许程序在执行期(即运行时)借Reflection API取得任何类的内部信息并能操作任意对象的内部属性和方法

2)Java反射机制提供的功能

在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的成员变量和方法
生成动态代理

3)反射相关的主要API:

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法


二、Class类的常用API

1)Class类

在Object中定义了public final Class getClass()方法,此方法将被所有子类继承,且返回值的类型是一个Class类型,此类是Java反射机制的源头(理解:可以通过对象反射求出类的名称)

正常方式:引入需要的包类名称→通过new实例化→取得实例化对象

反射方式:实例化对象→getClass()方法→取得完整的包类名称

对于每个类而言,JRE都为其保留了一个不变的Class类型的对象,以下有几点需要注意的:

  • Class本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个类在 JVM 中只会有一个Class实例 
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过Class可以完整地得到一个类中的完整结构 

方法名 功能说明
static Class  forName(String name)  返回指定类名 name 的 Class 对象
Object newInstance()  调用缺省构造函数,返回该Class对象的一个实例
getName()  返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称
Class [] getInterfaces()  获取当前Class对象的接口
ClassLoader getClassLoader()  返回该类的类加载器
Class getSuperclass()  返回表示此Class所表示的实体的超类的Class
Constructor[] getConstructors() 返回一个包含某些Constructor对象的数组
Field[] getDeclaredFields() 返回Field对象的一个数组
Method getMethod(String name,Class  …  paramTypes) 返回一个Method对象,此对象的形参类型为paramType


三、通过反射创建运行时类的对象

获取Class类的实例的四种方式

                Class clazz1 = Person.class;
		Class clazz2 = Class.forName("com.baidu.java3.Person");
		Person p = new Person();
		Class clazz3 = getClass().getClassLoader().loadClass("com.baidu.java3.Person");
		Class clazz4 = p.getClass();
(1)前提:若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高
       实例:Class clazz = String.class;
(2)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
       实例:Class clazz = “www.baidu.com”.getClass();
(3)前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
       实例:Class clazz = Class.forName(“java.lang.String”);
(4)其他方式ClassLoader cl = this.getClass().getClassLoader();
        Class clazz4 = cl.loadClass(“类的全类名”);

四、 通过反射获取运行时类的完整结构 及调用运行时类的指定属性、指定方法等

实现的全部接口:Interface

所继承的父类:Superclass
全部的构造器:Constructor
全部的方法:Method
全部的Field:Field

注解:Annotation

使用反射可以取得:
1.实现的全部接口
public Class<?>[] getInterfaces()   
确定此对象所表示的类或接口实现的接口。 
2.所继承的父类
public Class<? Super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
3.全部的构造器
public Constructor<T>[] getConstructors()
返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
返回此 Class 对象表示的类声明的所有构造方法。
4.全部的方法
public Method[] getDeclaredMethods()
返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()  
返回此Class对象所表示的类或接口的public的方法

Method类中:

  • public Class<?> getReturnType()取得全部的返回值
  • public Class<?>[] getParameterTypes()取得全部的参数
  • public int getModifiers()取得修饰符
  • public Class<?>[] getExceptionTypes()取得异常信息
Constructor类中:
  • 取得修饰符: public int getModifiers();
  • 取得方法名称: public String getName();
  • 取得参数的类型:public Class<?>[] getParameterTypes();
5.全部的Field
public Field[] getFields() 
返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields() 
返回此Class对象所表示的类或接口的全部Field。

Field方法中:
  • public int getModifiers()  以整数形式返回此Field的修饰符
  • public Class<?> getType()  得到Field的属性类型
  • public String getName()  返回Field的名称。
6. Annotation相关
get Annotation(Class<T> annotationClass) 
getDeclaredAnnotations() 
7.泛型相关
获取父类泛型类型:Type getGenericSuperclass()
泛型类型:ParameterizedType
获取实际的泛型类型参数数组:getActualTypeArguments()




下面是演示的目录结构及代码功能:

Java 的反射机制

Java 的反射机制

代码示例:

MyAnn.java

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnn {

	int age();
}

Person.java

public class Person<T> {

	public String name;
	public int age;
	private int sex;
	int id;
	
	public Person(){
		
	}
	
	
	public Person(String name,int age){
		this.name = name;
	}
	
	@Deprecated
	public void say(){
		System.out.println(name + "  " + age + " " + sex + " " + id);
	}
	
	private void show(){
		System.out.println("show" + sex);
	}
}

Student.java

@MyAnn(age = 30)
public class Student extends Person<String> {

	private String address;
	@MyAnn(age = 10)
	public int score;
	
	
	public Student(){
		
	}
	
	public Student(int score){
		this.score = score;
	}
	
	public Student(String address,int score){
		this.address = address;
		this.score = score;
	}
	
	private Student(String address){
		this.address = address;
	}
	
	@MyAnn(age = 20)
	public void info(){
		System.out.println(address + " " + score);
	}
	
	public void show(){
		System.out.println("student");
	}
	
	private void eat(){
		System.out.println("eat");
	}
}

ReflectionTest.java

public class ReflectionTest {

	/*
	 * 获取类中的所有属性
	 */
	@Test
	public void test1() throws Exception, Exception{
		Class clazz = Student.class;
		Student stu = (Student) clazz.newInstance();
		
		//获取所有的public所修饰的属性 (包含父类中的)(所有public修饰的)
		Field[] fields = clazz.getFields();
		for (Field field : fields) {
			System.out.println(field);
		}
		System.out.println("----------------------------");
		/*
		 * 获取本类中所有的属性(所有public/private修饰的)
		 */
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field field : declaredFields) {
			System.out.println(field);
		}
	}
	/*
	 * 获取类中所有的方法 
	 */
	@Test
	public void test2(){
		Class clazz = Student.class;
		//获取本类以及父类中所有的public所修饰的方法(所有public修饰的)
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
		
		System.out.println("-------------------------------");
		//获取本类中所有的方法(所有public/private修饰的)
		Method[] declaredMethods = clazz.getDeclaredMethods();
		for (Method method : declaredMethods) {
			System.out.println(method);
		}
	}
	/*
	 * 获取对象中的所有构造器
	 */
	@Test
	public void test3() throws Exception, Exception{
		//第一步  获取Class的实例
		Class clazz = Student.class;
		Student student = (Student) clazz.newInstance();
		
		//获取public修饰构造器(所有public修饰的)
		Constructor[] constructors = clazz.getConstructors();
		for (Constructor constructor : constructors) {
			System.out.println(constructor);
		}	
		System.out.println("-------------------------------");	
		//获取所有的构造器(所有public/private修饰的)
		Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
		for (Constructor constructor : declaredConstructors) {
			System.out.println(constructor);
		}
	}
	/*
	 * 获取注解
	 */
	@Test
	public void test4() throws Exception, Exception{
		Class clazz = Student.class;
		//获取的是类上的注解
		Annotation[] annotations = clazz.getAnnotations();
		for (Annotation annotation : annotations) {
			System.out.println(annotation);
		}
		
		//获取属性上的注解
		Field field = clazz.getField("score");
		Annotation[] annotations2 = field.getAnnotations();
		//for (Annotation annotation : annotations2) {
		//System.out.println(annotation);
		//}
		//获取注解中属性的值
		MyAnn a = (MyAnn) annotations2[0];
		System.out.println(a.age());
	}	
	/*
	 * 获取父类中的泛型类型(重点)
	 */
	@Test
	public void test5(){
		//获取父类
		Class clazz = Student.class;
		//获取父类
		Class superclass = clazz.getSuperclass();
		System.out.println(superclass);
		//获取带泛型的父类
		Type genericSuperclass = clazz.getGenericSuperclass();
		//将Type类型转成ParameterizedType
		ParameterizedType type = (ParameterizedType) genericSuperclass;
		//调用getActualTypeArguments获取泛型的集合
		Type[] actualTypeArguments = type.getActualTypeArguments();
		
		System.out.println(actualTypeArguments[0]);
		
	}
	
	/*
	 * 通过(有/无参)构造器创建对象
	 */
	@Test
	public void test6() throws Exception, Exception{
		//第一步 获取Class的实例
		Class clazz = Student.class;
		//默认是以空参的构造器创建对象
		Student student1 = (Student) clazz.newInstance();
		//创建有参构造器的对象
		/*
		 * int.class :  形参的Class实例
		 * 20  : 传递的实参
		 */
		/*
		 * 创建有参构造器的对象 (所有public修饰的)
		 */
		Constructor con1 = clazz.getConstructor(int.class);
		Student student2 = (Student) con1.newInstance(20);
		student2.show();
		System.out.println("-------------------------------");
		/*
		 * 创建有参构造器的对象 (所有public/private修饰的)
		 */
		Constructor con = clazz.getDeclaredConstructor(int.class);
		con.setAccessible(true);
		Student student3 = (Student) con.newInstance(20);
		student3.show();
	}
	/*
	 * 给属性赋值,调用方法 (重点)
	 */
	@Test
	public void test7() throws Exception, Exception{
		Class clazz = Student.class;
		Student stu = (Student) clazz.newInstance();
		/*
		 * 给属性赋值
		 * address:属性的名称
		 * setAccessible(true) : 允许访问所有的属性
		 * set(stu, "aaa") : stu指的是当前属性所在的对象,aaa指的是实参
		 */
		Field declaredField = clazz.getDeclaredField("address");
		declaredField.setAccessible(true);
		declaredField.set(stu, "小小");
		stu.info();
		
		System.out.println("-----------------------------------");
		
		/*
		 * 调用私有的方法
		 * eat : 方法名
		 * setAccessible(true) : 允许调用所有的方法
		 * invoke(stu) : 通过stu对象调用eat方法
		 */
		Method method = clazz.getDeclaredMethod("eat");
		method.setAccessible(true);
		method.invoke(stu);
	}
	
	/*
	 * 获取属性的详细信息
	 */
	@Test
	public void test8(){
	
		Class clazz = Student.class;
		//获取本类中所有的属性
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field field : declaredFields) {
			//System.out.println(fielzZd);
			//获取属性的权限修饰符
			int modifiers = field.getModifiers();
			System.out.print(Modifier.toString(modifiers) + " ");
			//获取属性的类型
			Class<?> type = field.getType();
			System.out.print(type + " ");
			//获取属性的名称
			String name = field.getName();
			System.out.print(name);
		}
	}
	/*
	 * 获取方法中的详细信息
	 */
	@Test
	public void test9(){
		Class clazz = Student.class;
		Method[] declaredMethods = clazz.getDeclaredMethods();
		for (Method method : declaredMethods) {
			//获取方法的权限修饰符
			System.out.print(Modifier.toString(method.getModifiers()) + " ");
			//获取返回值类型
			System.out.print(method.getReturnType() + " ");
			//获取方法名
			System.out.print(method.getName() + " ");
			System.out.println();
		}
	}	
}

Java 的反射机制二之Proxy简单动态代理

代理设计模式的原理: 

     使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上.

Proxy :专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。
提供用于创建动态代理类和动态代理对象的静态方法
            static Class<?>   getProxyClass(ClassLoader loader, Class<?>... interfaces)  创建一个动态代理类所对应的Class对象
            static Object   newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  直接创建一个动态代理对象

在说动态代理之前先示例看一下

静态代理

Java 的反射机制

Boss.java
public interface Boss {

	void eat();
	void buy();
}
BigBoss.java
public class BigBoss implements Boss{

	@Override
	public void eat() {
		System.out.println("吃吃吃。。。。。");
	}
	@Override
	public void buy() {
		System.out.println("买买买。。。");
	}
}
ITBoss.java
public class ITBoss implements Boss {

	public void eat(){
		System.out.println("IT老板吃饭了..............");
	}
	
	public void buy(){
		System.out.println("IT老板买买买...........");
	}
}
BigXiaoMi.java
public class BigXiaoMi implements Boss {

	//创建一个被代理对象
		BigBoss bigBoss;
		
		public BigXiaoMi(BigBoss bigBoss){
			this.bigBoss = bigBoss;
		}
		
		public void eat(){
			if(true){ //条件判断
				System.out.println("--------代理开始了---------------");
				bigBoss.eat();
				System.out.println("--------代理结束了---------------");
			}
		}
		
		
		public void buy(){
			if(true){ //条件判断
				System.out.println("--------代理开始了---------------");
				bigBoss.buy();
				System.out.println("--------代理结束了---------------");
			}
		}
}
ITXiaoMi.java
public class ITXiaoMi implements Boss {

	//创建一个被代理对象
	ITBoss itBoss;
	
	public ITXiaoMi(ITBoss itBoss){
		this.itBoss = itBoss;
	}
	
	public void eat(){
		if(true){ //条件判断
			System.out.println("--------代理开始了---------------");
			itBoss.eat();
			System.out.println("--------代理结束了---------------");
		}
	}
	
	
	public void buy(){
		if(true){ //条件判断
			System.out.println("--------代理开始了---------------");
			itBoss.buy();
			System.out.println("--------代理结束了---------------");
		}
	}
}
静态类测试
ProxyTest.java
/*
 * 静态代理:
 * 
 */
public class ProxyTest {

	@Test
	public void test(){
		
		ITXiaoMi itXiaoMi = new ITXiaoMi(new ITBoss());
		itXiaoMi.eat();
		itXiaoMi.buy();
		
		BigXiaoMi bigXiaoMi = new BigXiaoMi(new BigBoss());
		bigXiaoMi.eat();
		bigXiaoMi.buy();
	}
}
Java 的反射机制

弊端:从上面的静态代理可以看出代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能,动态代理可以实现要求

动态代理

静态代理每创建一个被代理类 就要创建一个代理类来代理目标类对象,这就显得很繁琐
所以使用动态代理解决这种繁琐的创建代理类的问题,即只需要创建一个代理类来代理所有的代理目标类对象

动态代理步骤

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。

2.创建被代理的类以及接口

3.通过Proxy的静态方法

newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个接口代理

4.通过代理对象调用被代理对象实现类的方法

代码示例:

Java 的反射机制

Boss.java
public interface Boss {

	void eat();
	void buy();
}

BigBoss.java
/*
 * 被代理对象
 * 
 */
public class BigBoss implements Boss{

	@Override
	public void eat() {
		// TODO Auto-generated method stub
	System.out.println("BigBoss 吃吃吃。。。。");	
	}
	@Override
	public void buy() {
		// TODO Auto-generated method stub
	System.out.println("BigBoss买买买");	
	}
	
}

ITBoss.java
/*
 * 被代理对象
 * 
 */
public class ITBoss implements Boss{
 
	@Override
	public void eat() {
		// TODO Auto-generated method stub
	System.out.println("ITBoss吃吃吃。。。。。。");	
	}
	@Override
	public void buy() {
		// TODO Auto-generated method stub
	System.out.println("ITBoss买买买。。。。。。");	
	}
}


ProxyXiaoMi.java
public class ProxyXiaoMi implements InvocationHandler {

	//被代理对象(也就是 BigBoss,ITBoss
	private Object tarage;
	
	public Object getProxyObject(Object tarage){
		/*
		 *创建动态代理对象 并作为返回值
		 * 第一个参数:类加载器
		 * 第二个参数:目标对象实现的所以接口
		 * 第个参数:InvocationHandler实现类的对象
		 */
		return Proxy.newProxyInstance(
				tarage.getClass().getClassLoader(),
				tarage.getClass().getInterfaces(), 
				this);
	}

	@Override
	public Object invoke(Object tarage, Method method, Object[] args) throws Throwable {
		System.out.println("------------代理开始了-------------");
		//调用目标对象的方法
		Object obj = method.invoke(tarage, args);//此处的target不可写成proxy
		System.out.println("------------代理结束了-------------");
		return obj;
	}
}
测试方法
ProxyTest.java
public class ProxyTest {

	@Test
	public void test() {
		ProxyXiaoMi proxyXiaoMi = new ProxyXiaoMi();

		Boss boss = (Boss) proxyXiaoMi.getProxyObject(new ITBoss());
		boss.eat();
		boss.buy();

		Boss boss2 = (Boss) proxyXiaoMi.getProxyObject(new BigBoss());
		boss2.eat();
		boss2.buy();

	}
}
Java 的反射机制





相关标签: Class Proxy