第三章. Java反射

本文详细介绍了Java反射机制,包括如何获取Class对象、成员变量、成员方法、构造方法以及父类信息。通过反射,程序可以在运行时动态地访问和修改类的行为,增加了代码的灵活性和动态性。同时,文章列举了反射在数据库连接、动态执行方法等方面的应用实例,展示了反射在实际开发中的重要作用。
摘要由CSDN通过智能技术生成

1. 反射

反射(reflection):程序可以运行时访问、检测和修改它本身状态或行为的能力。
– 增加动态性
– 降低耦合度,增加了程序灵活性(人们不想修改代码,只需改动配置文件)
java.lang.reflect包 (Java11)

  • 可以在运行时访问和使用编译期间完全未知的类。
    –使用时进行加载,要有class文件
  • 给Java插上动态语言特性的翅膀
  • 反射直接对class文件进行操作
  • 但是需要注意的是反射使用不当会造成很高的资源消耗!

反射机制:

  1. 编译期可以使用并不知道的类。
    –编译时并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知。
  2. 要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。
    当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。
    – jvm加载类的条件,类class文件存在
    – 若class不存在,只需要编译此class文件,再在配置文件中配置(动态性的实现)

反射的作用:

  1. 在运行时判断任意一个对象所属的类
  2. 在运行中查看和操作对象
    • 基于反射自由创建对象(反射能构建出无法直接访问的类(private))
    • set或者get到无法访问的成员变量
    调用不可访问的方法
  3. 实现通用的数组操作代码
  4. 类似函数指针的功能

2. 反射接口

Class:类型标识
–当一个类被加载以后,Java虚拟机就会自动产生一个Class对象
–JVM为每个对象都保留其类型标识信息,包含方法、成员以及构造方法的声明和定义等信息
Java.lang.Class (Java11)
参考代码
在这里插入图片描述
在这里插入图片描述

2.1获取Class方式:

  1. obj.getClass()
	Student stu1 = new Student();//new 产生一个Student对象,一个Class对象
	Class stuClass1 = stu1.getClass();//获取Class对象
	System.out.println(stuClass1.getName());
  1. 通过Class类的静态方法:forName(String className)(常用)
    – className是真实路径,包名.类名
    – String className可以从配置文件加载,降低耦合性,实现动态性
	package fanshe;
	Class stuClass2 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,包名.类名
	System.out.println(stuClass1 == stuClass2);//判断是否获取的是同一个Class对象
  1. 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
	Class stuClass2 = Student.class;
  • 在运行期间,一个类,只有一个Class对象产生。
  • 三种方式常用第二种,
    第一种对象都有了还要反射干什么。
    第三种需要导入类的包,依赖太强,不导包就抛编译错误。
    一般都第二种,一个字符串可以传入也可写在配置文件中等多种方法。

2.2 获取成员变量并调用

  1. 获取批量

     Field[ ] getFields():返回本类和所有父类的public属性
     Field[ ] getDeclaredFields();返回本类自己定义的属性,包括private,但不包括父类属性
    
  2. 获取单个

     public Field getField(String fieldName):获取某个public属性;
     public Field getDeclaredField(String fieldName):获取某个属性(可以是私有的)
    
  • 可以通过 setAccessible(true);//使得private临时变为public
import java.lang.reflect.Field;
class A
{
	public int age;
	private String name;
	
	public A(int age, String name)
	{
		this.age = age;
		this.name = name;
	}
}
public class FieldTest {

	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
		A obj = new A(20, "Tom");
		Class c = obj.getClass();
		
		//获取本类及父类所有的public字段
		Field[] fs = c.getFields(); 
		System.out.println(fs[0].getName() + ":" + fs[0].get(obj));
		
		//获取本类所有声明的字段
		Field[] fs2 = c.getDeclaredFields();
		for(Field f : fs2)
		{
			f.setAccessible(true);//使得private临时变为public
			System.out.println(f.getName() + ":" + f.get(obj));
		}
		
		Field fs3 = c.getField("name");
		System.out.println(fs3);
	}
}

在这里插入图片描述

2.3 获取成员方法并调用

  1. 获取批量

     public Method[ ] getMethods():获取所有public方法;(包含了父类的方法也包含Object类)
     public Method[ ] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
    
  2. 获取单个

    public Method getMethod(String name,Class<?>... parameterTypes):
    	参数:
    	name : 方法名;
    	Class ... : 形参的Class类型对象
    	-- 无参则不加
    public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
    
  • 调用方法:

      Method --> public Object invoke(Object obj,Object... args):
      			参数说明:
      			obj : 要调用方法的对象;
      			-- 非静态方法需要传递obj,静态方法不需要
      			args:调用方式时所传递的实参;
      			-- 有参函数传递args,无参函数传递 null
    
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static java.lang.System.out;

class B {
	public void f1() {
		out.println("B.f1()...");
	}

	private String f2(String s) {
		out.println("B.f2()...");
		return s;
	}
}
public class MethodTest {

	public static void main(String[] args)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
		B obj = new B();
		Class c = obj.getClass();

		// 获取public方法 包括父类和父接口
		Method[] ms = c.getMethods();
		for (Method m : ms) {
			if ("f1".equals(m.getName())) {
				m.invoke(obj, null); //invoke调用方法,非静态需要传递obj
			}
		}

		// 获得该类的单个方法
		Method ms2 = c.getDeclaredMethod("f2",String.class);
		
		ms2.setAccessible(true);
		String result = (String) ms2.invoke(obj, "abc");
		out.println(result);
	}
}

在这里插入图片描述

2.4 获取构造方法并调用

  1. 获取批量

     	public Constructor[] getConstructors():所有"public"构造方法
        public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
    
  2. 获取单个:

     	public Constructor getConstructor(Class... parameterTypes):获取单个的"public"构造方法:
     	public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
    
  • 调用构造方法:

      	弃用 Class.newInstance(Object... initargs)
      	-- 会直接调用该类的无参构造函数进行实例化
      	改用为: Class.getDeclaredConstructor().newInstance()
      	-- getDeclaredConstructor()方法会根据他的参数对该类的构造函数进行搜索并返回对应的构造函数,没有参数就返回该类的无参构造函数,然后再通过newInstance进行实例化。
    
package fanshe;
 
public class Student {
	
	//---------------构造方法-------------------
	//(默认的构造方法)
	Student(String str){
		System.out.println("(默认)的构造方法 s = " + str);
	}
	
	//无参构造方法
	public Student(){
		System.out.println("调用了公有、无参构造方法执行了。。。");
	}
	
	//有一个参数的构造方法
	public Student(char name){
		System.out.println("姓名:" + name);
	}
	
	//有多个参数的构造方法
	public Student(String name ,int age){
		System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
	}
	
	//受保护的构造方法
	protected Student(boolean n){
		System.out.println("受保护的构造方法 n = " + n);
	}
	
	//私有构造方法
	private Student(int age){
		System.out.println("私有的构造方法   年龄:"+ age);
	}
 
package fanshe;
import java.lang.reflect.Constructor;

public class Constructors {
 
	public static void main(String[] args) throws Exception {
		//1.加载Class对象
		Class clazz = Class.forName("fanshe.Student");
		
		
		//2.获取所有公有构造方法
		System.out.println("**********************所有公有构造方法*********************************");
		Constructor[] conArray = clazz.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		
		System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
		conArray = clazz.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("*****************获取公有、无参的构造方法*******************************");
		Constructor con = clazz.getConstructor(null);
		//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
		//2>、返回的是描述这个无参构造函数的类对象。
	
		System.out.println("con = " + con);
		//调用构造方法
		Object obj = con.newInstance();
	//	System.out.println("obj = " + obj);
	//	Student stu = (Student)obj;
		
		System.out.println("******************获取私有构造方法,并调用*******************************");
		con = clazz.getDeclaredConstructor(char.class);
		System.out.println(con);
		//调用构造方法
		con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
		obj = con.newInstance('男');
	}
	
}

在这里插入图片描述

2.5 获取父类信息

	sonClass.getSuperclass():获取父类Class
	sonClass.getInterfaces() :获取接口Class 
class Father { }

class Son extends Father 
  implements Cloneable, Comparable
{
	protected Object clone() throws CloneNotSupportedException
	{
		return super.clone();
	}

	public int compareTo(Object o) {
		return 0;
	}
}

public class SuperTest {

	public static void main(String[] args) {
		Son son = new Son();
		Class c = son.getClass();
		
		Class father = c.getSuperclass();
		System.out.println(father.getName());
		
		Class[] inters = c.getInterfaces();
		for(Class inter : inters)
		{
			System.out.println(inter.getName());
		}

	}

}

在这里插入图片描述

3. 反射应用

数据库连接
• 数组扩充器
• 动态执行方法
• Json和Java对象互转
Tomcat的Servlet对象创建
MyBatis的OR/M
Spring的Bean容器
• org.reflections包介绍

  1. jbdc数据库连接
//构建Java和数据库之间的桥梁介质
try{            
	Class.forName("com.mysql.jdbc.Driver");
	//Class.forName(className, true, currentLoader) 
	//通知类加载器加载此类的class文件
	System.out.println("注册驱动成功!");
	}catch(ClassNotFoundException e1){
	System.out.println("注册驱动失败!");
	e1.printStackTrace();
	return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值