关于反射的一些理解

目录

1.反射简介
2.类对象的获取
3.类结构信息的获取与使用
5.获取泛型信息
6.Array类
7.总结

反射简介

反射是构建框架技术的基础所在,虽然反射的执行效率较低,但是会大大的提高开发效率。Java反射机制是指在运行时,动态获取信息及调用对象方法的功能。
Java程序的一般加载过程是,先把.java文件编译成.class,然后虚拟机再去运行.class文件。而Java反射机制在编译时,并不确定哪个类被加载,而是在运行时才加载。

类对象的获取

想要获得并操作类信息,很重要的一步就是获取Class对象。每个类被加载后,都会生成一个且仅一个class对象,Java中通常有如下三种方式来获得某类的Class对象:

Student stu = new Student();

//通过Class类的forName静态函数。参数为类的全限名。(不传全限名会抛异常)
Class c1 = Class.forName("demo2.Student");

//通过该类class属性
Class c2 = Student.class;

//通过该类对象的getClass()方法
Class c3 = stu.getClass();

//通过哈希码可以看出,获得的3个指针,指向的是同一个对象
System.out.println(c1.hashCode()); //1802598046
System.out.println(c2.hashCode()); //1802598046
System.out.println(c3.hashCode()); //1802598046

顺便说一下,为了性能和安全,推荐使用:类.class 的方式来创建对象

下面案例中使用的Student类如下:
三个属性,三个构造方法,以及一个静态方法和Setter/Getter方法

public class Student {
	static int a;
	public String name;
	private int age;
	
	private Student(String name) {
		this.name = name;
	}
	public Student() {
		
	}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public static void f() {
		
	}
	public static int getA() {
		return a;
	}
	public static void setA(int a) {
		Student.a = a;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

类结构信息的获取与使用

获得了该类的Class对象后,我们就可以通过该对象拥有的大量方法,来获取类信息(如类名,属性,方法,注解等)。
不论是获得怎样的类信息,大体都可以概括为这几种:

getXxxs——返回类所有的此类信息(仅public修饰的)。
getDeclaredXxxs()————返回类所有的此信息(无视修饰符)。

getXxx——返回类的某一个此类信息(仅能得到public)。
getDeclaredXxx——返回类的某一个此类信息(无视修饰符)。

如果需要传入参数,一般情况下是传入该参数的数据类型的Class对象。

获得构造方法并使用

Class c = Student.class;
		 
Constructor[] constructors1 = c.getConstructors();
/* 数组内容如下
public demo.Student(java.lang.String,int)
public demo.Student()
*/
Constructor[] constructors2 = c.getDeclaredConstructors();
/* 数组内容如下
public demo.Student(java.lang.String,int)
public demo.Student()
private demo.Student(java.lang.String)
*/
		
//得到构造函数public Student()
Constructor<Student> con1 = c.getConstructor();
//得到私有构造函数private Student(String name)
Constructor<Student> con2 = c.getDeclaredConstructor(String.class);
//得到构造函数public Student(String name, int age)
Constructor<Student> con3 = c.getConstructor(String.class, int.class);
	
/* ------- 下面是使用Constructor类型的对象,调用newInstance()方法来创建学生类的对象 ------- */
		
//等价于使用public Student()
con1.newInstance();

/*对于私有构造函数对象,
我们需要使用setAccessible(true)来解除修饰符检查,从而顺利创建学生对象*/
con2.setAccessible(true);
con2.newInstance("Tom");

//等价于使用public Student("Jerry", 19)
con3.newInstance("Jerry", 19);

获得属性并使用

Class c = Student.class;
/*对于属性,同意可以使用getFields()和getDeclaredFields()
得到Field类型的数组*/
c.getFields();
c.getDeclaredFields();
//也可以使用getField(String name)和getField(String name)来获得指定name的属性
Field field_Age = c.getDeclaredField("age");
	
/* ------- 下面是使用Field类型的对象,来设置或得到该属性 ------- */
		
//如果是非public修饰的属性,需要设置Accessible为true
field_Age.setAccessible(true);
Student stu = new Student();//创建学生对象
field_Age.set(stu, 11);//设置该学生的age属性
System.out.println(field_Age.get(stu));//获得该学生的age属性值

//如果是静态属性,set的第一个参数就填该类的Class对象

获得普通方法(成员和静态都可以)并使用

Class c = Student.class;
/*对于方法,同样可以使用getFields()和getDeclaredFields()
得到Method类型的数组*/
c.getMethods();
c.getDeclaredMethods();
/* 也可以使用getMethod(String name, Class<?>... parameterTypes)和
getDeclaredMethod(String name, Class<?>... parameterTypes)来获得指定name的属性 */
Method method_getName = c.getMethod("getName", null);//传入函数名和参数的Class对象,无参则写null
Method method_setName = c.getMethod("setName", String.class);
		
/* ------- 下面是使用Method类型的对象,来调用该方法 ------- */
		
Student stu = new Student();//创建学生对象
method_setName.invoke(stu, "Kate");//等价于调用了stu.setName("Kate")
method_getName.invoke(stu); //等价于调用了stu.getName()

获得注解并使用

注解的使用和上面也是类似的,具体的可以看这篇中的例子
反射获得注解

获取泛型信息

反射操作的是加载号以后的类。可类加载到JVM中的时候,泛型已经被擦出了。为了通过反射能操作泛型,Java增加了一些特别的类。
推荐视频:反射获取泛型信息

Array类

在java.lang.reflect包下还提供了一个Array类,此Array类对象可以代表所有的数组。程序可以通过Array类来动态创建数组,操作数组元素等。例如下面的代码中,创建了数组arr,并为元素复制。

String[] arr = (String[]) Array.newInstance(String.class, 10);
Array.set(arr, 2, "Jack");
Array.set(arr, 7, "Tom");
System.out.println(Array.get(arr, 0)); //null
System.out.println(Array.get(arr, 2)); //Jack
System.out.println(Array.get(arr, 7)); //Tom

总结

总而言之,使用反射后,保证了在程序运行状态时,对任意一个类(指的是.class文件),都能够知道这个类的所有的属性和方法对于某个类的一个对象,都能够调用它的任意一个方法和属性。
关于具体的反射应用场景,推荐文章:反射应用场景

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值