Java基础篇:反射机制详解

反射机制、反射含义

  • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意方法和属性;

  • 这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

  • 帮助理解:就是我们可以通过代码获取到类中的所有属性和所有方法

  • 简而言之:自己找到自己,俗称“照镜子”

1.利用反射获取类对象的三种方法

  • 方法一:对象.getClass()方法
  • 方法二:类.clss属性
  • 方法三:Class.forName()

代码块

public class Test {

	public static void main(String[] args) throws Exception {
		//Student类的实例化
		Student student01= new Student(); 
				
		//方法一:通过getclass()
		Class<? extends Student> s1 = student01.getClass();
		System.out.println(s1);
		
		//方法二:通过class属性
		Class<Student> s2 = Student.class;
		System.out.println(s2);
		
		//方法三:通过Class.forname()
		System.out.println(Class.forName("com.Li.reflex01.Student"));
	}
}

2.利用反射获取类对象的类名、方法、属性

stu.getClass();

stu.getClass().getFields().getName() & field.getType() //属性名 和 属性类型

stu.getClass().getMethods().getName() & method.getReturnType() //类方法 和 方法返回值

/**
 * @Description: 测试类:测试获取类对象中的类名、方法和属性
 * @auther:Li Ya Hui
 * @Time:2021年4月19日下午1:33:00
   */
   public class Test {
   public static void main(String[] args) {
   	//1.student类的实例化
   	Student stu = new Student();

   //2.获取student的类对象  class
   Class<? extends Student> student = stu.getClass();
   System.out.println("类的class:\t"+student);
   System.out.println("类的全称:"+stu.getClass().getSimpleName());
   System.out.println("类的简称:"+stu.getClass().getName());

   //3使用增强for遍历学生类的属性  属性名,属性类型
   Field[] stufiled = stu.getClass().getFields();
   for (Field field : stufiled) {
   	System.out.println("属性名:"+field.getName()+"\t\t属性的数据类型:"+field.getType());
   }
   //4.获取类中的方法
   Method[] stumethods = stu.getClass().getMethods();
   for (Method method : stumethods) {
   	System.out.println("类的方法"+method.getName()+"\t类的方法的返回值类型"+method.getReturnType());
   }

 }
}

3.利用反射获取类对象中的构造器、构造器参数类型、实例化构造器

package com.Li.reflex03;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Test {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		
		//获取类对象
		Class<?> stu = Class.forName("com.Li.reflex03.Student");
		
		//获取所有的公有构造方法(前提 类是用public修饰的)
		Constructor<?>[] stuConstru = stu.getConstructors();
		for (Constructor<?> constructor : stuConstru) {
			System.out.println("构造器:\t"+constructor);
			
			//构造器执行  (参数 类型 个数 不对会导致出错)
			//System.out.println("构造器执行:\t:"+constructor.newInstance(""));//等价于Student student = new Student(); 相当于类的初始化

			//获取构造器中的参数类型
			Class<?>[] parameterTypes = constructor.getParameterTypes();
            
			//遍历各个构造器参数类型
			for (Class<?> parameter : parameterTypes) {
				System.out.println("构造器中的参数类型:\t"+parameter.getName());
			}
			System.out.println();
		}
	}
}
实例化重点
类的加载方式不同

​ 在执行Class.forName(“a.class.Name”)时,JVM会在classapth中去找对应的类并加载,这时JVM会执行该类的静态代码段。在使用newInstance()方法的时候,必须保证这个类已经加载并且已经连接了,而这可以通过Class的静态方法forName()来完成的。

​ 使用关键字new创建一个类的时候,这个类可以没有被加载,一般也不需要该类在classpath中设定,但可能需要通过classlaoder来加载。

所调用的构造方法不尽相同

​ new关键字能调用任何构造方法。
​ newInstance()只能调用无参构造方法。

执行效率不同

​ new关键字是强类型的,效率相对较高。
​ newInstance()是弱类型的,效率相对较低。

4.利用反射获取类对象中的方法的包装类

/**
 * @Description:测试类,测试利用反射获取类的方法的包装类Method
 * @auther:Li Ya Hui
 * @Time:2021年4月19日下午8:57:13
 */
public class Test {

	public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		
		//1.获取类对象
		Class<Student> ownerClass = Student.class; 
		
		//2.Student类的实例化
		Student student = ownerClass.newInstance();
		
		//3.通过类对象获取method类   				方法名		方法返回值类型    需是类
		 Method method = ownerClass.getMethod("sayHi", String.class);

		 //多个参数时
		 //Method method = ownerClass.getMethod("sayHi", String.class, String.class);
		 
		 //4.invoke() 是method类中的方法,起作用是回调类中的方法         
		 //invoke 参数讲解: 1.回调那个实例化对象中的方法  	2.传入的参数的值
		 String result = (String) method.invoke(student, "LiYaHui");
		 
		 //多个参数时
//		 String result = (String) method.invoke(student, "LiYaHui","李亚辉");
		 System.out.println(result); 
	}
}

5.通过反射获取运行配置文件内容(Properties)

properties位于java.util.properties,是Java语言的配置文件所使用的类

/**
 * @Description: 利用properties获取配置文件中的内容
 * @auther:Li Ya Hui
 * @Time:2021年4月20日上午9:14:52
 */
public class Test {

	public static void main(String[] args) throws IOException {
		//实例properties类
		Properties properties  = new Properties();
		//创建读取对象
		FileReader fileReader = new FileReader("dbconfig.txt");
		//加载读取对象
		properties.load(fileReader);
		//获取username属性
		String username = properties.getProperty("username");
		//打印username的值
		System.out.println(username);//打印 root
	}
}
自己写的配置文件
//dbconfig.txt
username=root
password=root
drivername=com.mysql.jdbc.driver
url=127.0.01:3306

6.利用反射和properties实现获取配置文件中的内容(类路径、方法名,然后反射实现 实例化、回调方法)

package com.Li.reflex05;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.ObjectInputStream.GetField;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @Description: 利用反射和properties实现获取配置文件中的内容
 * @auther:Li Ya Hui
 * @Time:2021年4月20日上午9:39:51
 */
public class Test {
	public static void main(String[] args) throws Exception {
		//1.propertie类的初始化
		Properties properties = new Properties();
		
		//2.加载配置文件哎
		FileReader fileReader = new FileReader("playerList.txt");
		
		//3.properties加载配置文件
		properties.load(fileReader);
		
		//4.利用properties获取配置文件中的内容
		
		//当前的配置文件中的className的属性值,  得到应用类的路径
		String className = properties.getProperty("className"); 
		System.out.println("获取到的类的路径名:\t"+className);
        
		//当前的配置文件中的methodName的属性值,  得到类的方法名
		String methodName = properties.getProperty("methodName");
		System.out.println("获取到的类中方法的名字:\t"+methodName);
		
		//得到类的class
		Class<?> heroclass = Class.forName(className);
		
		//得到构造器
		Constructor constructor = heroclass.getConstructor();
		
		//初始化构造器,其作用相当于是new ,目前是实例化类
		Object hero = constructor.newInstance();
		
		//调用方法		getMethod使用类对象来调用的,所以不能用hero对象
		Method method = heroclass.getMethod(methodName, String.class);//通过类对象获取到方法的包装类Method,且同时指出本次执行的方法是run,且该方法的传入参数为String
		
		//回调hero类中的run方法
		method.invoke(hero,"ss枪手");
	}
}

//hero类
/**
 * @Description: 英雄类
 * @auther:Li Ya Hui
 * @Time:2021年4月20日上午9:36:45
 */
public class Hero {
	public void run(String attribute)
	{
		if (attribute.endsWith("肉盾")) 
		{
			System.out.println("肉盾!可以慢跑");
		}else if(attribute.endsWith("枪手")){
			System.out.println("枪手可以边打边跑");
		}else {
			System.out.println("可以正常跑!");
		}
	}
}

//配置文件
//playerList.txt
className=com.Li.reflex05.Hero
methodName=run
6.2.String 的 endsWith() 方法

(上面例子的hero英雄类中有应用场景)

endwith和equals方法有些相似,但是不同的是endwith判断是否以指定字符结尾,有点正则表达式的意思

7.在不更改源代码的前提下通过更改配置文件实现程序功能的扩展

package com.Li.reflex07;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.ObjectInputStream.GetField;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * @Description: 在不更改源代码的前提下通过更改配置文件实现程序功能的扩展
 * @auther:Li Ya Hui
 * @Time:2021年4月20日上午9:39:51
 */
public class Test {

	public static void main(String[] args) throws Exception {
		//1.propertie类的初始化
		Properties properties = new Properties();
		
		//2.加载配置文件哎
		FileReader fileReader = new FileReader("playerList2.txt");
		
		//3.properties加载配置文件
		properties.load(fileReader);
		
		//4.利用properties获取配置文件中的内容
		
		//当前的配置文件中的className的属性值,  得到应用类的路径
		String className = properties.getProperty("className"); 
		System.out.println("获取到的类的路径名:\t"+className);
		//当前的配置文件中的methodName的属性值,  得到类的方法名
		String methodName = properties.getProperty("methodName");
		System.out.println("获取到的类中方法的名字:\t"+methodName);
		
		//得到类的class
		Class<?> heroclass = Class.forName(className);
		
		//得到构造器
		Constructor constructor = heroclass.getConstructor();
		
		//初始化构造器,其作用相当于是new ,目前是实例化类
		Object hero = constructor.newInstance();
		
		//调用方法		getMethod使用类对象来调用的,所以不能用hero对象
		Method method = heroclass.getMethod(methodName, String.class);//通过类对象获取到方法的包装类Method,且同时指出本次执行的方法是run,且该方法的传入参数为String
		
		//以上代码没有更改,封装后可实现多次扩展实例代码
		//回调hero类中的run方法
		method.invoke(hero,"boss"); //只需在调用时换参数即可
	}
}
//妖怪类(Devil)
package com.Li.reflex07;
/**
 * @Description: 妖怪类
 * @auther:Li Ya Hui
 * @Time:2021年4月20日上午9:36:45
 */
public class Devil {
	public void run(String attribute)
	{
		if (attribute.endsWith("boss")) 
		{
			System.out.println("boss!可以慢跑");
		}else if(attribute.endsWith("littleboss")){
			System.out.println("littleboss可以稍微快点跑");
		}else {
			System.out.println("可以正常跑!");
		}
	}
}
//配置文件//playerList2.txt
className=com.Li.reflex07.Devil
methodName=run

8.使用反射的小结

​ 1.可以在任何地方通过反射获取到类中的属性和方法和构造器还有实例化

​ 2.因为可以获取到构造器,当然也可以实例化==(通过newInstance()方法即可实现)==

​ 3.经常被应用在框架中,例如Struts,Soring框架

​ 要点:newInstance这个方法勉强等同于news这个关键字

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DataPulse-辉常努腻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值