Java反射

本文详细介绍了Java中的反射机制,包括通过Class.forName()、getClass()和类名.class等方式获取Class对象,以及如何实例化类、访问和修改属性、调用方法和构造函数。反射提供了一种在运行时检查和操作类、接口和对象的能力,增强了程序的灵活性和可扩展性。文章还展示了如何通过反射访问私有成员和调用私有方法,以及如何使用反射创建对象和调用构造函数。
摘要由CSDN通过智能技术生成

今日金句

一日不可无常业,安闲便易起邪心

前言

框架通常借助设计模式、反射和配置文件等技术实现灵活的开发和可扩展性。今天我们就来了解反射这项技术。

一、反射概述

1.1 概念

Java中的反射是指在程序运行时检查、访问、修改变量、方法、调用构造函数的机制

Java中反射机制主要是由java.lang.Class类及其相关方法以及java.lang.reflect包中的Field、Method、Constructor类和访问控制相关类构成的。

1.2 作用

(1)可以在运行时动态地获取类、接口、方法、属性等对象的信息,实现了代码和数据的分离,增加了程序的灵活性和可扩展性。

(2)可以在运行时动态地创建对象、调用方法、操作属性,尤其使用在框架的开发中,可以通过反射机制灵活的使用已经存在的类库、组件库等。

(3)可以实现一些基于注解的编程技术,例如通过注解定义一些特定的属性信息,然后可以使用反射机制在程序运行时动态地读取和处理这些注解信息。

(4)反射机制可以实现一些基本Java中无法实现的特殊操作,例如通过反射机制访问私有成员,执行私有方法,实现单例模式等。

二、类类

Java中的类类是指java.lang.Class类,是Java反射机制的核心类之一。类类表示Java程序中的一个类或接口。

2.1常用方法

方法描述
getName()返回类的名称,包括包名
getSimpleName()返回类的简单名称,不包括包名
getModifiers()返回类的修饰符,例如public、private、static等
getPackage()返回类所在的包
getFields()返回类或接口的public字段
getDeclaredFields()返回类或接口声明的所有字段,包括私有字段
getMethods()返回类或接口的public方法
getDeclaredMethods()返回类或接口声明的所有方法,包括私有方法
getConstructors()返回类的public构造器
getDeclaredConstructors()返回类声明的所有构造器,包括私有构造器

2.2实例化类类

这里有个Student类

package com.xqx.reflect;

public class Student {
	private String sid;

	private String sname;

	public Integer age;

	static {
		System.out.println("加载进jvm中!");
	}

	public Student() {
		super();
		System.out.println("调用无参构造方法创建了一个学生对象");
	}

	public Student(String sid) {
		super();
		this.sid = sid;
		System.out.println("调用带一个参数的构造方法创建了一个学生对象");
	}

	public Student(String sid, String sname) {
		super();
		this.sid = sid;
		this.sname = sname;
		System.out.println("调用带二个参数的构造方法创建了一个学生对象");
	}

	@SuppressWarnings("unused")
	private Student(Integer age,String sname) {
		System.out.println("调用Student类私且多参的构造方法创建一个学生对象");
		this.age = age;
		this.sname = sname;
	}

	public String getSid() {
		return sid;
	}

	public void setSid(String sid) {
		this.sid = sid;
	}

	public String getSname() {
		return sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public void hello() {
		System.out.println("你好!我是" + this.sname);
	}

	public void hello(String name) {
		System.out.println(name + "你好!我是" + this.sname);
	}

	@SuppressWarnings("unused")
	private Integer add(Integer a, Integer b) {
		return new Integer(a.intValue() + b.intValue());
	}
}

2.2.1Class.forName()

这个方法可以根据给定的类名获取对应的Class对象

			Class c = Class.forName("com.xqx.reflect.Student");

2.2.2getClass()

该方法可以返回当前对象的类的Class对象。例如

			Student stu=new Student();
			Class class1 = stu.getClass();

2.2.3类名.class

			Class c1=Student.class;
			System.out.println(c);
			System.out.println(c1);
			System.out.println(class1);

打印结果:

class com.xqx.reflect.Student
class com.xqx.reflect.Student
class com.xqx.reflect.Student

2.2.4创建类实例

获取了类的Class对象之后,就可以使用Class.newInstance()方法来创建类实例:

		//一切反射从类类开始
		Class c = Class.forName("com.xqx.reflect.Student");
		//创建类实例 无参实例化
		Student stu = (Student) c.newInstance();

需要注意的是,newInstance()方法只能创建无参构造函数的类对象,如果存在有参构造函数,则需要使用Constructor类来创建类实例。同时,在Java 9中,newInstance()方法已被废弃,建议使用Class.getDeclaredConstructor()方法代替。

三、反射属性

通过Field类来获取对象的属性,也可以获取到私有属性,还可以设置属性的值。

3.1公有属性的获取与赋值

getDeclaredField()方法获取属性、get()方法打印获取到属性的值、set()方法为熟悉赋值

		Student student = new Student();
		student.setSid("s001");
		student.setSname("xqx");
		student.age=18;
		//一切反射从类类开始
		Class<? extends Student> c = student.getClass();
		//获取到公有属性age
		Field ageField = c.getDeclaredField("age");	
		System.out.println("修改前:"+ageField.get(student));
		ageField.set(student, 16);
		System.out.println("修改后:"+ageField.get(student));

打印结果:

加载进jvm中!
调用无参构造方法创建了一个学生对象
修改前:18
修改后:16

3.2私有属性的获取与赋值

获取与赋值方法跟公有属性一致,但必须打开权限setAccessible才可调用,否则报错

		//拿到私有属性
		Field idField = c.getDeclaredField("sid");
		Field nameField = c.getDeclaredField("sname");
		
		//打开私有属性访问权限
		idField.setAccessible(true);
		nameField.setAccessible(true);
		
		System.out.println("修改前:"+idField.get(student));
		//修改
		idField.set(student, "s110");
		System.out.println("修改后:"+idField.get(student));
		
		System.out.println("修改前:"+nameField.get(student));
		nameField.set(student, "nb");
		System.out.println("修改后:"+nameField.get(student));
	

打印结果:

修改前:s001
修改后:s110
修改前:xqx
修改后:nb

3.3 获取所有属性

		//拿到所有字段
		Field[] fields = c.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			//拿到所有字段名、值
			System.out.println(field.getName() + ":" + field.get(student));
		}

打印结果:

sid:s110
sname:nb
age:16

3.4获取修饰符

Class类的getModifiers()方法可以返回一个int类型的修饰符,这个修饰符是由多个常量值通过位运算组合而成的。获取修饰符可以帮助我们更方便地了解一个类的特性,从而更好地理解并使用该类。

		//拿到所有字段
		Field[] fields = c.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			int modifiers = field.getModifiers();
			if (Modifier.isPublic(modifiers)) {
				System.out.println("public:"+field.getName());
				System.out.println("public修饰符的常量值:"+modifiers);
			}
			if (Modifier.isPrivate(modifiers)) {
				System.out.println("private:"+field.getName());
				System.out.println("private修饰符的常量值:"+modifiers);
			}
		}

打印结果:

private:sid
private修饰符的常量值:2
private:sname
private修饰符的常量值:2
public:age
public修饰符的常量值:1

四、反射方法

4.1 获取公有无参方法

		// 一切反射从类类开始
		Class<Student> c = Student.class;
		// 创建类实例
		Student stu = (Student) c.newInstance();
		//获取无参方法  hello是方法名
		Method m = c.getMethod("hello");
		//调用方法
		Object invoke = m.invoke(stu);
		System.out.println(invoke);

打印结果:

加载进jvm中!
调用无参构造方法创建了一个学生对象
你好!我是null
null

4.2 获取公有一参方法

		//获取有参方法  hello是方法名 String.class是参数类型
		Method m2 = c.getMethod("hello", String.class);
		//调用方法 stu是类实例  "nb"是要传的参数
		Object invoke2 = m2.invoke(stu, "nb");
		System.out.println(invoke2);

打印结果:

nb你好!我是null
null

4.3 获取私有多参方法

跟调用私有属性一样,必须打开访问权限setAccessible

		//获取私有多参方法  add是方法名 Integer.class是参数类型
		Method m3 = c.getDeclaredMethod("add", Integer.class, Integer.class);
		// 打开访问权限
		m3.setAccessible(true);
		//调用方法 stu是类实例  22、33是要传的参数
		Object invoke3 = m3.invoke(stu, 22, 33);
		System.out.println(invoke3);

打印结果:

55

五、反射构造函数

5.1获取无参

		//一切反射从类类开始
		Class c = Class.forName("com.xqx.reflect.Student");
		//创建类实例 无参实例化
		Student stu = (Student) c.newInstance();
		System.out.println(stu);

打印结果:

加载进jvm中!
调用无参构造方法创建了一个学生对象
com.xqx.reflect.Student@33909752

5.2 获取公有有参

		//获取有参构造
		Constructor c1 =c.getConstructor(String.class);
		Student stu2 = (Student)c1.newInstance("s001");
		System.out.println(stu2);

打印结果:

调用带一个参数的构造方法创建了一个学生对象
com.xqx.reflect.Student@55f96302

5.3获取私有多参

		//私有
		Constructor c3 =c.getDeclaredConstructor(Integer.class,String.class);
		//打开访问权限
		c3.setAccessible(true);
		Student stu4 = (Student)c3.newInstance(120,"xqx");
		System.out.println(stu4);

打印结果:

调用Student类私且多参的构造方法创建一个学生对象
com.xqx.reflect.Student@42a57993

六、总结

反射机制的基本步骤如下:

(1)获取Class对象。可以通过多种方式来获取Class对象,比如Class.forName()、Object.getClass()以及类字面常量等。

(2)创建实例对象。获取Class对象后,可以使用Class.newInstance()方法来创建类实例对象。

(3)获取或设置对象的属性。通过Field类来获取对象的属性,可以获取私有属性,也可以设置属性的值。

(4)调用对象的方法。通过Method类来获取对象的方法,可以获取私有方法,也可以调用方法。

(5)调用对象的构造函数。通过Constructor类来调用对象的构造函数。

好啦,今天的分享就到此为止!希望你看完本篇文章有所收获,祝你变得更强、未来出“粽”!!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值