反射的简单使用

本文介绍了Java反射的基本概念,解释了为何要使用反射,并详细阐述了反射的常用类和方法,包括获取Class对象的途径、创建对象实例、操作方法以及字段信息。通过实例展示了如何通过反射创建和操作JavaBean,强调了反射在降低程序耦合性和提高灵活性方面的优势。

查考文章
整理Java反射常用方法 https://blog.youkuaiyun.com/github_35180164/article/details/52037112
深入解析Java反射(1) - 基础 https://www.sczyh30.com/posts/Java/java-reflection-1/

反射是什么

反射:允许任意一个类在运行时获取自身的类信息,并且可以操作这个类的方法和属性。这种动态获取类信息和动态调用对象方法的功能称为Java的反射机制。

为什么要用反射

通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

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

反射可以降低程序耦合性,提高程序的灵活性

反射常用类

  • java.lang.reflect.Constructor<T> :与构造函数相关的反射
  • java.lang.reflect.Field :与字段相关的反射
  • java.lang.reflect.Method :与方法相关的反射
  • java.lang.reflect.Modifier :与修饰符相关的反射

反射常用方法

  • Field相关

    • Class.getDeclaredFields() : 获取当前类所有的(包括私有)字段
    • Class.getDeclaredField(String) : 获取单个字段(包括私有)
    • Class.getFields() : 获取当前类所有的(不包括私有)字段
    • Class.getField(String) : 获取单个字段(不包括私有)
  • Method相关

    • Class.getDeclaredMethods() : 获取类本身的所有方法,包括公有、保护、私有
    • Class.getDeclaredMethod(String, Class[]) : 获取类本身的指定方法,包括公有、保护、私有
    • Class.getMethods() : 获取类本身和其所有父类的公有和保护方法
    • Class.getMethod(String, Class[]) : 获取类本身和其所有父类指定的公有和保护方法

反射的运用

  • 测试 user 类
	public class User {
		private String username;
		private String password;
	
		public User() {
			super();
		}
	
		public User(String username, String password) {
			super();
			this.username = username;
			this.password = password;
		}
	
		public String getUsername() {
			return username;
		}
	
		public void setUsername(String username) {
			this.username = username;
		}
	
		public String getPassword() {
			return password;
		}
	
		public void setPassword(String password) {
			this.password = password;
		}
	
		private String privateMethod(String str) {
			return "这是调用私有方法:" + str;
		}
	
		@Override
		public String toString() {
			return "User [username=" + username + ", password=" + password + "]";
		} 
	}

获得 Class 对象三种方法

  1. 使用 Class.forName 静态方法:
	public static Class<?> forName(String className)

例如:

	try {
		Class<?> userClass = Class.forName("com.test.User");
	} catch (ClassNotFoundException e) { 
		e.printStackTrace();
	} 
  1. 调用对象的 class
	Class<?> userClass = User.class;
  1. 调用某个对象的 getClass() 方法
	User user = new User();
	Class<? extends User> userClass = user.getClass(); 

创建对象实例

	@Test
	public void run(){ 
		try {
			Class<?> userClass = Class.forName("com.test.User");
			
			// 直接使用Class.newInstance()方法来创建Class对象的无参构造生成实例对象
			User user1 = (User) userClass.newInstance();
			user1.setUsername("小茗");
			user1.setPassword("123ABC");
			System.out.println("无参构造生成实例对象: " + user1.toString());
 
			// 使用 java.lang.reflect.Constructor 类生成有参构造生成实例对象
			// getConstructor(Class... arg0) 参数为Java的可变参数 传入类型为 java.lang.Class 类型
			Constructor<?> constructor = userClass.getConstructor(String.class, String.class);
			User user2 = (User) constructor.newInstance("小黄", "ABC123");
			System.out.println("有参构造生成实例对象 : " + user2.toString());

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	} 

结果:
创建对象实例结果

操作方法

获取方法的属性
	@Test
	public void run() {
		try {
			Class<?> userClass = Class.forName("com.redis.test.User");
			// 获取类本身的所有方法,包括公有、保护、私有
			Method[] methods = userClass.getDeclaredMethods();

			// 获取类本身和其所有父类的公有和保护方法
			// Method[] methods = userClass.getDeclaredMethods();
			for (int i = 0; i < methods.length; i++) {
				// 
				System.out.println("方法修饰符未转义前: " + methods[i].getModifiers());
				System.out.println("方法修饰符转义后: " + Modifier.toString(methods[i].getModifiers()));
				System.out.println("获取方法名: " + methods[i].getName());
				System.out.println("获取方法参数列表变量数量: " + methods[i].getParameterCount());

				// 获取参数列表类型
				Class<?>[] types = methods[i].getParameterTypes();
				System.out.print("获取方法参数列表变量类型: ");
				for (int j = 0; j < types.length; j++) {
					System.out.print(types[j].getName() + ",");
				}
				System.out.println(); 
				System.out.println();
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
	}
  • 结果
    方法属性反射
通过反射对方法操作
	@Test
	public void run() {
		try {
			Class<?> userClass = Class.forName("com.redis.test.User");

			// 通过反射 调用非私有方法 set 方法为其赋值
			User user = (User) userClass.newInstance();
			Method setUsernameMethod = userClass.getMethod("setUsername", String.class);
			Method setPasswordMethod = userClass.getMethod("setPassword", String.class);
			setUsernameMethod.invoke(user, "小茗");
			setPasswordMethod.invoke(user, "123ABC");
			System.out.println("调用对象获取值: " + user.toString());

			// 通过反射 调用非私有方法 get 方法获取所赋的值
			Method getUsernameMethod = userClass.getMethod("getUsername");
			Method getPasswordMethod = userClass.getMethod("getPassword");
			String username = (String) getUsernameMethod.invoke(user);
			String password = (String) getPasswordMethod.invoke(user);
			System.out.println("通过反射 调用getter方法获取值: username=" + username + ", password=" + password);

			// 通过反射为私有属性赋值
			// 使用 getMethod 方法不能找到私有方法,否则会报 java.lang.NoSuchMethodException
			Method privateMethod = userClass.getDeclaredMethod("privateMethod", String.class);

			// 该方法是private的,需要调用该方法的 f.setAccessible(true); 才能读取和修改该方法。 否则会报
			// java.lang.IllegalAccessException:
			privateMethod.setAccessible(true);
			String value = (String) privateMethod.invoke(user, "ABCD");

			System.out.println("通过反射 调用private修饰的方法: " + value);

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
	}
  • 结果
    通过反射操作方法

字段信息

字段属性信息
	@Test
	public void run() { 
		try {
			Class<?> userClass = Class.forName("com.redis.test.User");
			
			// 获取类本身的所有字段,包括公有、保护、私有
			Field[] declaredFields = userClass.getDeclaredFields();
			
			// 获取类本身和其所有父类的公有和保护字段
			// Field[] declaredFields = userClass.getFields();

			// 获取属性的类型
			for (int i = 0; i < declaredFields.length; i++) {
				System.out.println("属性修饰符未转义前: " + declaredFields[i].getModifiers());
				System.out.println("属性修饰符转义后: " + Modifier.toString(declaredFields[i].getModifiers()));
				System.out.println("获取属性类型: " + declaredFields[i].getType().getName());
				System.out.println("获取属性类型: " + declaredFields[i].getType().getSimpleName());
				System.out.println("获取属性名: " + declaredFields[i].getName()); 
				System.out.println();
			} 
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
  • 结果
    字段属性信息
字段属性操作
	@Test
	public void run6() {
		try {
			Class<?> userClass = Class.forName("com.redis.test.User");
			
			// 创建User实例
			User user = (User) userClass.newInstance();

			Field usernameField = userClass.getDeclaredField("username"); 
			// 该字段是private的,需要调用该字段的 f.setAccessible(true); 才能读取和修改该字段。 否则会报
			// java.lang.IllegalAccessException:
			usernameField.setAccessible(true);
			usernameField.set(user, "晓明");

			Field passwordField = userClass.getDeclaredField("password"); 
			// 该字段是private的,需要调用该字段的 f.setAccessible(true); 才能读取和修改该字段。 否则会报
			// java.lang.IllegalAccessException:
			passwordField.setAccessible(true);
			passwordField.set(user, "123abc");

			System.out.println(user);

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) { 
			e.printStackTrace();
		} catch (SecurityException e) { 
			e.printStackTrace();
		} catch (IllegalArgumentException e) { 
			e.printStackTrace();
		} catch (IllegalAccessException e) { 
			e.printStackTrace();
		} catch (InstantiationException e) { 
			e.printStackTrace();
		}
	}
  • 结果
    字段属性操作

使用反射创建JavaBean

  • 创建简单 JavaBean
	
	public class User { 
		private String username;
		private String password;
	
		public User() {
			super();
		}
	
		public User(String username, String password) {
			super();
			this.username = username;
			this.password = password;
		}
	
		public String getUsername() {
			return username;
		}
	
		public void setUsername(String username) {
			this.username = username;
		}
	
		public String getPassword() {
			return password;
		}
	
		public void setPassword(String password) {
			this.password = password;
		}
	
		@Override
		public String toString() {
			return "User [username=" + username + ", password=" + password + "]";
		}
	
	} 
  • 创建 JavaBean 反射类
	import java.lang.reflect.Field; 
	
	/**
	 * 获取 javaBean 并使用反射重新生成 
	 *
	 */
	public class ReflectClass { 
		public static void main(String[] args) throws ClassNotFoundException {
			// 加载需要被反射的类
			Class<?> forName = Class.forName("com.redis.test.User");
			// 获取所有字段(包括私有的变量)
			Field[] declaredFields = forName.getDeclaredFields();
			StringBuffer sb = new StringBuffer();
			sb.append("public class User {\n");	
			// 拼接 字段
			for (int i = 0; i < declaredFields.length; i++) {
				sb.append("\t");
				sb.append(java.lang.reflect.Modifier.toString(declaredFields[i].getModifiers()));			
				sb.append(" ");			
				sb.append(declaredFields[i].getType().getSimpleName());			
				sb.append(" ");			
				sb.append(declaredFields[i].getName());		
				sb.append(";"); 
				sb.append("\n");
			}
	
			sb.append("\n");
			
			// 拼接GET SET 方法
			for (int i = 0; i < declaredFields.length; i++) {
				// 将字段转换为首字母大写
				char[] cs=declaredFields[i].getName().toCharArray();
		        cs[0]-=32; 
		        
		        // 拼接GET 方法 
				sb.append("\tpublic ").append(declaredFields[i].getType().getSimpleName()).append(" get").append(String.valueOf(cs)).append("(){").append("\n");	
				sb.append("\t\t");	 
				sb.append("return this.").append(declaredFields[i].getName()).append(";");  
				sb.append("\n\t");   
				sb.append("}");  
				sb.append("\n"); 
				
	
		        // 拼接SET 方法 
				sb.append("\tpublic void set").append(String.valueOf(cs)).append("("+declaredFields[i].getType().getSimpleName()+" "+declaredFields[i].getName()).append("){").append("\n");	
				sb.append("\t\t");	
				sb.append("this.").append(declaredFields[i].getName()).append(" = " ).append(declaredFields[i].getName()).append(";");  
				sb.append("\n\t");   
				sb.append("}");  
				sb.append("\n"); 
				
			}
			sb.append("}");	
			System.out.print(sb.toString());	
		}
	}

  • 控制台打印结果
    控制台打印结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值