JAVA反射机制

本文深入介绍了Java反射机制的基本概念及其实现原理,并通过多个示例展示了如何利用反射机制实现对象的创建、方法调用等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。他主要依托JVM中关于类的元数据信息来完成这一功能,有过C++编程经验的同学应该很了解C++中实现多态的虚表吧,在这里的元数据其实和虚表类似,起码在理解反射的时候可以这么认为。

 

    Java的反射机制主要能实现一下功能:

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

    注意大前提,都是在运行时,通常的语言的运行时状态是不能修改的,而java的强大的反射机制,使得java程序员可以操作类的运行时状态和信息。


    Reflection 是 Java 被视为动态(或准动态)语言的关键,允许程序在执行期 Reflection 任何已知名称之 class 的內部信息,包括 package、type parameters、super class(父类)、implemented interfaces(实现的接口)、inner classes, outer class, fields(属性)、constructors(构造函数)、methods(方法)、modifiers(修饰符),并可于执行期生成instances、变更 fields 內容或调用 methods。换句话说,就是只要知道类的名字,程序员就可以知道类的所有信息,甚至在执行期生成instances、变更 fields 內容或调用 methods。


    何谓动态语言:程序在运行期间,允许改变程序的结构或变量类型,如python,在变量使用前不需要声明他的类型,运行时会根据内容自动改变他的类型,但是对于C/C++来说,在变量使用前,必须首先声明他的类型。根据这种定义,java并不是动态语言,但是他却有着和动态语言相关的一个机制那就是反射。用在java身上就是指我们可以在运行期加载、探知和使用编译器完全未知的classes。换句话说,java可以加载一个运行时才得知名称的class,获悉其完整构造(但是不包括method的定义),并生成这种对象实例,或对其field设置或调用其method。

 

    实现java反射机制的相关的类:(以下解释主要来自jdk_api)
    Java的反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。

  • Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
  • Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
  • Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
  • Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。Class对象是java反射机制的入口,有了类的Class对象,就有了类的一切!
  • Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。


    要获得一个对象的Class对象,有三种方式:

  1. ClassName.class;
  2. obj.getClass();
  3. Class.forName(“class name”);

    正如前面说的,有了类的Class的对象,就有了类的一切,这就是类的元数据,反射的一切从这里开始!

 

    Spring 的ioc主要是使用了工厂模式,核心还是java的反射机制。


    下面给出一些反射的例子,以便更好的理解反射。

这是两个用于测试的类:

package reflect;

public class TestClass {
	
}


package reflect;

public class User{
	private String name;
	private int age;
	//在提供了有参的构造函数的时候,尽量显示的给出无参的
	public User(){
		
	}
	//这里提供了一个有参数的构造函数
	public User(String name){
		this.name = name;
	}
	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;
	}
	@Override
	public String toString() {		
		return "NAME :" + this.name + " AGE: " + this.age;
	}
	public void sayHello(String name,int age){
		System.out.println("hello:"+"NAME :" + name + " AGE: " + age);
	}
	public void sayHello(){
		System.out.println("hello nothing");
	}
	public int add(int a,int b){
		return a+b;
	}
}

获得类的主要信息:

package reflect;

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

public class Reflect {
	
	//
	public static void testGetClassName() {
		TestClass test = new TestClass();
		// 取得取得TestClass类的完整类名
		String testName = test.getClass().getName();

		System.out.println(testName);
	}
	//三种获得Class多的方式
	public static void testInstance(){
		Class<?> demo1= null;
		Class<?> demo2= null;
		Class<?> demo3= null;
		try {
			demo1 = Class.forName("reflect.TestClass");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		demo2 = new TestClass().getClass();
		demo3 = TestClass.class;
		System.out.println("类名:"+demo1.getName());
		System.out.println("类名:"+demo2.getName());
		System.out.println("类名:"+demo3.getName());
	}
	//通过类名使用默认构造函数实例化类对象
	public static void testInstanceFromName(){
		User user = null;
		try {
			 user = (User)Class.forName("reflect.User").newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		user.setAge(12);
		user.setName("raiet");
		System.out.println(user);
	}
	
	//使用有参数的构造函数实例化类对象
	public static void testInstanceFromNameAndParam(){
		String name = "raiet";
		//1,取出类名对应的Class
		Class<?> clazz = null;
		try {
			clazz = Class.forName("reflect.User");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//2,取出所有的构造函数
		Constructor<?> cons[] = clazz.getConstructors();
		System.out.println("构造函数有:");
		for(Constructor con:cons){
			System.out.println(con);
		}
		//3,根据相应的参数构造实例
		User user1 = null;
		User user2 = null;
		try {
			user1 = (User)cons[0].newInstance();
			user2 = (User)cons[1].newInstance("raiet");
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(user1);
		System.out.println(user2);
		
		//也可以使用下面的方式来实现
		try {
			Constructor con= null;
			//取得无参数的构造函数
			con = clazz.getConstructor(new Class[]{});
			User user = (User) con.newInstance(null);
			System.out.println(user);
			
			//取得只有一个带有string类新参数的构造函数
			con = clazz.getConstructor(String.class);
			//传入构造函数的参数
			user = (User) con.newInstance("raiet");
			System.out.println(user);
		} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//通过Class调用它的方法
	public static void testInvokeMethod(){
		System.out.println("test invoke");
		Class<?> user = null;
		try {
			user = Class.forName("reflect.User");
			Method method = user.getMethod("sayHello");
			method.invoke(user.newInstance());
			
			method = user.getMethod("sayHello", String.class,int.class);
			method.invoke(user.newInstance(),"raiet001",25);
			
			method = user.getMethod("add", int.class,int.class);
			Object obj = method.invoke(user.newInstance(), 200,300);
			System.out.println((Integer)obj);
			
			/*
			 * 	其实上面的每段代码都等价于
			 *  User user = new User();
			 *  user.add(200,300)
			 *  但是他们的区别就在于,一个是在运行期确定调用关系(参数有外部传入),
			 *  一个是在编译器就决定了程序的行为
			 * */
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	//根据类名获得类中数据成员及其属性
	public static void testGetProperty(){
		Class<?> user = null;
		try {
			user = Class.forName("reflect.User");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Field[] fields = user.getDeclaredFields();
		for(Field field:fields){
			int mo;
			//获取权限修饰符
			mo = field.getModifiers();
			String priv = Modifier.toString(mo);
			//获取属性类型
			Class<?> type = field.getType();
			System.out.println(priv + " " + type.getName() + " "+field.getName() + ";");
		}
	} 
	
	//返回类的所有信息。。。。
	//返回类的所有的方法名,包括修饰符,返回值,异常(住哟通过反射机制可以取出所有的method,包括private的)
	public static void getAllMethods(){
		Class<?> obj = null;
		try {
			obj = Class.forName("java.lang.String");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("输出所有的方法信息");
		Method[] methods = obj.getDeclaredMethods();
		for(Method method : methods){
			System.out.println(method);
		}
		System.out.println("输出所有的字段信息");
		Field[] fields = obj.getFields();
		for(Field field : fields){
			System.out.println(field);
		}
		System.out.println("输出所有的构造器信息");
		Constructor<?>[] cons = obj.getConstructors();
		for(Constructor<?> con : cons){
			System.out.println(con);
		}
		System.out.println("输出所有的接口信息");
		Class<?>[]  ins = obj.getInterfaces();
		for(Class clazz: ins){
			System.out.println(clazz);
		}
	}
	
	
	public static void main(String[] args) {
		testGetClassName();
		testInstance();
		testInstanceFromName();
		testInstanceFromNameAndParam();
		testInvokeMethod();
		testGetProperty();
		getAllMethods();
	}
}

下面是一个用反射机制实现的赋值对象的例子:

package reflect;

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

public class BeanCopy {
	//一个拷贝java bean的方法,内部使用反射机制实现
	public Object copy(Object obj){
		Object copyObj= null;
		//先取得的Class对象
		Class<?> clazz = obj.getClass();
		try {
			copyObj = clazz.newInstance();
		} catch (InstantiationException | IllegalAccessException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		//取得所有的属性,注意这里不要使用getFields方法,那样只能取得public的属性
		Field[] fields = clazz.getDeclaredFields();
		System.out.println("*********************************************");
		System.out.println("类中的属性:");
		for(Field field:fields){
			//获取字段的名字,以便后面用来拼接get和set方法
			String fieldName = field.getName();
			//取得第一个字母,并转换为大写,否和普通java bean的名字
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			//拼接get和set方法名
			String getMethodName = "get" + firstLetter + fieldName.substring(1);
			String setMethodName = "set" + firstLetter + fieldName.substring(1);
			try {
				//取得get和set方法
				Method getMethod = clazz.getMethod(getMethodName, null);//get方法没有参数
				Method setMethod = clazz.getMethod(setMethodName, field.getType());
				
				//调用get和set方法,完成赋值
				Object value = getMethod.invoke(obj, null);
				System.out.println(fieldName + " : "+ value);
				setMethod.invoke(copyObj, value);
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		System.out.println("*********************************************");
		return copyObj;
	}
	
	public static void main(String[] args){
		User user = new User();
		user.setAge(10);
		user.setName("haha");
		//BeanCopy beanCopy = new BeanCopy();
		User newUser = (User)new BeanCopy().copy(user);
		System.out.println(newUser);
	}
}



这里有几个关于反射的多数功能的实例:

http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

http://www.oschina.net/code/snippet_127825_6594

 



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值