java语法之反射

Java反射允许程序在运行时检查自身,并能获取类的所有信息,包括成员变量、方法和构造器等。通过反射可以访问私有属性和方法,创建对象并调用其方法。文章提供了获取类、成员变量、方法和构造器的API示例,并展示了反射在创建和操作对象上的应用。

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

什么是反射

允许运行中的Java程序对自身进行检查。
反射可以直接操作程序的私有属性,反射像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到包括(成员变量、成员方法、构造器等),并且可以操纵类的字段、方法、构造器等部分。

反射用到的API

获取字节码对象

Class.forName(“类的全路径”);
类名.class
对象.getClass();

常用方法

  • 获取包名 类名
    clazz.getPackage().getName()//包名
    clazz.getSimpleName()//类名
    clazz.getName()//完整类名
  • 获取成员变量定义信息
    getFields()//获取所有公开的成员变量,包括继承变量
    getDeclareds()//获取本类定义的成员变量,包括私有,但不包括继承的变量
    getField(变量名)
    getDeclaredField(变量名)
  • 获取构造方法定义信息
    getConstructor(参数类型列表)//获取公开的构造方法
    getConstructors()//获取所有的公开的构造方法
    getDeclaredConstructors()//获取所有的构造方法,包括私有
    getDeclaredConstructor(int.class, String.class)
  • 获取方法定义信息
    getMethods()//获取所有可见的方法,包括继承的方法
    getMethod(方法名, 参数类型列表)
    getDeclaredMethods()//获取本类定义的方法,包括私有,不包括继承的方法
    getDeclaredMethod(方法名, int.class, String.class)
  • 反射新建实例
    clazz.newInstance();//执行无参构造创建对象
    clazz.newInstance(666, “海绵宝宝”);//执行含参构造创建对象
    clazz.getConstructor(int.class, String.class)//获取构造方法
  • 反射调用成员变量
    clazz.getDeclaredField(变量名);//获取变量
    clazz.setAccessible(true);//使私有成员允许访问
    f.set(实例, 值);//为指定实例的变量赋值,静态变量,第一参数给null
    f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null
  • 反射调用成员方法
    Method m = Clazz.getDeclaredMethod(方法名, 参数类型列表);
    m.setAccessible(true);//使私有方法允许被调用
    m.invoke(实例, 参数数据);//让指定实例来执行该方法

反射的应用

创建:测试物料类

package com.review;

public class Student {
	private String name;
	public int age;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public Student() {}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public void play() {
		System.out.println("今天要把反射彻底搞明白,不然不睡了~~");
	}
	public void sunDay(int n) {
		System.out.println("今天写了" + n + "个接口");
	}
	//重写toString来查看学生对象的具体属性和属性值
	@Override
	public String toString() {
		return "Student{" +
				"name='" + name + '\'' +
				", age=" + age +
				'}';
	}
}

练习:获取类对象

pakage com.reflection;

public class TestReflect {
	//单元测试方法:@Test + public + void + 没有参数
	//导包:import org.junit.Test
	@Test
	public void getClazz() throws ClassNotFoundException {
		//练习获取字节码对象的3种方式
		Class<?> clazz1 = Class.forName("com.review.Student");
		Class<?> clazz2 = Student.class;
		Class<?> clazz3 = new Student().getClass();
		
		//获取Student类对应的字节码对象
		System.out.println(clazz1);//class com.reflection.Student
		//获取当前字节码对象clazz1的名字
		System.out.println(clazz1.getName());//com.reflection.Student
		//获取Student类的类名
		System.out.println(clazz2.getSimpleName());
		//获取Student类对应的包对象
		System.out.println(clazz3.getPackage());
		//获取Student类对应的包对象,再获取这个包对象的名字
		System.out.println(clazz3.getPackage().getName());
	}
}

练习:获取成员变量

package com.reflection;

public class TestReflect {
	@Test
	public void getStu() {
		Student s1 = new Student("张三", 3);
		Student s2 = new Student("李四", 4);
		Student s3 = new Student("王五", 5);
		
		Student[] s = {s1, s2, s3};
		System.out.println(Arrays.toString());
		for(Student stu : s) {
			stu.play();
			System.out.println(stu.age);
		}
	}
	
	@Test
	public void getFie() throw ClassNotFoundException {
		//获取字节码对象
		Class<?> clazz = Class.forName("com.review.Student");
		//获取所有成员变量
		Field[] fs = clazz.getFields();
		//遍历数组,获取每个成员变量的具体信息
		//注意!目前的成员变量必须是public修饰才能获取到
		for(Field f : fs) {
			System.out.println(f.getName());
			System.out.println(f.getType());
		}
	}
}

练习:通过字节码对象获取类的成员方法

package com.reflection;

public class TestReflect {
	@Test
	public void getFunction() {
		Class<?> clazz = Student.class;
		Method[] ms = clazz.getMethods();
		for(Method m : ms) {
			System.out.println(m);
			System.out.println(m.getName());
			//通过方法对象获取方法所有参数的数组
			Class<?>[] pt = m.getParameterTypes();
			System.out.println(Arrays.toString(pt));
		}
	}
}

练习:通过字节码对象获取类的构造方法

package com.reflection;

public class TestReflect {
	@Test
	public void getCons() {
		Class<?> clazz = new Student().getClass();
		Constructors<?>[] cs = clazz.getConstructors();
		for(Constructor c : cs){
			System.out.println(c.getName());//打印本轮遍历到的构造方法的名字
			Class[] pt = c.getParameterTypes();//获取构造函数的参数类型
			System.out.println(Arrays.toString(pt));
		}
	}
}

练习:创建对象

package com.reflection;

public class TestReflect {
	@Test
	public void getObject() = throws Exception {
		Class<?> clazz = Student.class;
		/*反射创建对象方案1:通过触发目标类的无参构造创建对象*/
		Object o = clazz.newInstance();
		System.out.println(o);
		/*反射创建对象方案2:通过触发目标类的全参构造创建对象
        * 思路:
        * 1.先获取指定的构造函数对象,注意需要指定构造函数的参数,传入的是.class字节码对象
        * 2.通过刚刚获取到的构造函数对象创建Student目标类的对象,并且给对象的属性赋值
        * */
        //3.获取目标类中指定的全参构造
		Constructor<?> c = clazz.getConstructor(String.class, int.class);
		//4.通过获取到的构造函数:创建对象+给对象的属性赋值
		Object o2 = c.newInstance("小六", 6);
		System.out.println(o2);
	}
}

暴力反射

指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。

getDeclaredAnnotation(Class annotationClass):A - Class
getDeclaredAnnotations():Annotation[] - Class
getDeclaredAnnotationsByType(Class annotationClass):A[] - Class
getDeclaredClasses():Class<?>[] - Class getDeclaredConstructor(Class<?>…parameterTypes):Constructor - Class
getDeclaredConstructors():Constructor<?>[] - Class getDeclaredField(String name):Field - Class getDeclaredFields():Field[] - Class getDeclaredMethod(String name,Class<?>…parameterTypes):Method - Class
getDeclaredMethods():Method[] - Class
getDeclaringClass():Class<?> - Class

创建:测试物料类

package com.review;

public class Person {
	private String name;
	private int age;

	private void save(int n,String s) {
		System.out.println("save()..."+n+s);
	}
	private void update() {
		System.out.println("update()...");
	}
}

练习:创建测试类

package com.reflection;

public class TestReflect{
	@Test
	public void getFie() throws Exception {
		Class<?> clazz = Person.class;
		Field field = clazz.getDeclaredField("name");
		System.out.println(field);
		System.out.println(field.getType().getName());
		System.out.println(field.getType());

		Object obj = clazz.newInstance();//触发无参构造利用反射创建对象
		field.setAccessible(true);
		
		field.set(obj,"海绵宝宝");
		System.out.println(field.get(obj));
	}

	@Test
	public void getFie1() throws Exception {
		Class<?> clazz = Person.class;
		Field fields = clazz.getDeclaredField("age"); 
		
		System.out.println(fields.getType().getName());
		Object obj = clazz.newInstance();
		
		fields.setAccessible(true);
		fields.set(obj,17);
		System.out.println(fields.get(obj));
	}
		
	@Test
	public void getFunction() throws Exception {
		//1.获取Class字节码对象
		Class<?> clazz = Person.class;
		//2.通过暴力反射获取私有方法
        /*getDeclaredMethod(m,x,y,z...)
        * m:要获取的方法名
        * x,y,z...可变参数,是这个方法的参数类型,但注意要加“.class”
        * */
		Method method = clazz.getDeclaredMethod("save" ,int.class ,String.class)
		//没有对象就通过反射的方式创建对象
		Object obj = clazz.newInstance();
		//想要执行私有方法,也需要先设置私有可见
		method.setAccessible(true);

		 /*invoke(o,x,y,z...),表示通过反射技术执行方法
        * o :要执行的是哪个对象的方法
        * x,y,z...:执行这个方法【method对象代表的之前获取到的save()】时需要传入的参数
        * */
		//通过反射技术invoke(),执行目标对象obj的目标方法method【save()】
		//save()被调用时传入的参数是100,"反射成功啦~"
		method.invoke(obj ,100 ,"反射成功啦~");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值