Java十分钟精通反射机制原理

网友投稿 330 2022-08-22


Java十分钟精通反射机制原理

什么是反射?

反射机制是在运行状态中,它为java提供一种“操作对象”的能力,在运行状态下,通过Class文件对象,可以调用到任何类里面的属性、方法、以及构造方法,包括私有的,所有的类在反射机制面前都是透明的

自己的概括:通过Class文件对象可以看到这个类里面的所有东西,并且可以使用和修改

反射的前提是获取Class文件对象((字节码对象),那么一共有三种方式获取:

Class.forName(“全类名”) ----通过Class类的静态方法(最常用)

类名.class

对象.getClass()

//方式1:获取字节码对象,Class.forName("全类名")

Class cla1 = Class.forName("Study01.Person");

//方式2: 类名.Class

Class cla2 = Person.class;

//方式3:对象.getClass();

Person per = new Person();

Class cla3 = per.getClass();

//这三个class对象都是由Person这个类生成的

//那么我们看一下这三个字节码对象是不是同一个:

System.out.println(cla1==cla2);

System.out.println(cla2==cla3);

//输出结果: 两个true

结论:

字节码对象在类加载的时候就产生,并且只有一个

无论哪种方式获取字节码对象都是同一个字节码对象

通过反射来获取类中的属性:

获取到Class字节码对象后,我们就可以通过字节码对象来获取到我们想要获取的类的属性、方法、构 造方法、以及private修饰的。

部分Class方法:(全部的可以查阅官方文档) 查阅地址:https://docs.oracle.com/en/java/javase/17/docs/api/jXgnuWnPGava.base/java/lang/Class.html

Demo演示:

1、建一个Person类,里面有两个public和两个private的属性(不设置构造和get/set,就是看反射能不能得到里面的值)

public class Person {

private String name; //名字

private int age = 18; //年龄

public int ID = 123; //身份证

public String Sex; //性别

@Override

public String toString(){

return "姓名"+name+"年龄:"+age+"ID:"+ID+"性别:"+Sex;

}

}

测试类:

public class Test {

public static void main(String[] args) throws ClassNotFoundException {

//获取Class文件对象,用最常用的通过Class类的静态方法

Class per = Class.forName("Test01.Person"); //这里是传入全路径!!从最外层的包名开始!

//使用getFields()方法获取全部被public修饰的属性(方法上面的截图有)

//并且返回的是Field类型的数组

Field fields[] = per.getFields();

for (Field field:fields) {

System.out.println(field);

}

}

}

输出:

我们成功的获取到了Person类中全部public属性

2、也可以获取全部的属性,包括私有的:(其他代码就不重写啦)

for (Field field : per.getDeclaredFields()) {

System.out.println(field);

}

输出:

3、获取公有的属性,并且修改这个值:

Field f = per.getField("Sex");

System.out.println(f);

//获取一个对象:

Object obj = per.getConstructor().newInstance();

//修改值:

f.set(obj,"男");

Person p = (Person)obj;

System.out.println(p.Sex);

输出:

4、获取私有的属性,并且修改这个值: 这里把上面修改公有属性的值也连起来:

Person p = (Person)obj;

//获取公有字段并调用,并修改

Field f = per.getField("Sex");

//获取一个对象:

Object obj = per.getConstructor().newInstance();

f.set(obj,"男"); //将Sex的属性修改成了 男

//调用私有的属性,并修改

f = per.getDeclaredField("name");

//在访问私有的属性的值之前,先要设置运行访问↓

//在访问之前忽略访问权限的检查,叫暴力反射

f.setAccessible(true);

f.set(obj,"张三");

System.out.println("Person里面的信息是:"+p.toString());

}

}

输出:

通过反射来获取类中的方法(公有、私有、构造):

Person类:

public class Person {

private String name; //名字

private int age = 18; //年龄

public int ID = 123; //身份证

public String Sex ; //性别

//构造:

public Person() {}

public Person(String name, int age, int ID, String sex) {

this.name = name;

this.age = age;

this.ID = ID;

Sex = sex;

}

//无参公有方法:

public void eat(){

System.out.println("我会吃饭");

}

//有参公有方法:

public void eat(String food){

System.out.println("我在吃:"+food);

}

//有参私有方法

private void play(String name){

System.out.println(name+"在玩");

}

}

测试类:

public class Test {

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

//获取到Person以及父类Object里面的public方法:

System.out.println("-----获取到Person以及父类Object里面的public方法↓-----");

for (Method method : Person.class.getMethods()) {

System.out.println(method);

System.out.println("方法名:"+ method.getName());

}

//获取到Person里面的方法,包括私有

System.out.println("-----获取到Person里面的方法,包括私有↓-----");

for (Method method:Person.class.getDeclaredMethods()) {

System.out.println(method.getName()+" ");

}

//按照方法名获取到Person中的eat方法:

System.out.println("-----根据方法名获取到Person类中的eat方法↓-----");

Method earMethod1 = Person.class.getMethod("eat");

Person per = new Person();

//通过invoke(Object,param...)来调用指定的方法

earMethod1.invoke(per);

//使用反射调用有参方法;

System.out.println("-----使用反射调用有参方法(传入参数)↓-----");

Method earMethod2 = Person.class.getMethod("eat",String.class);

earMethod2.invoke(per,"牛肉");

//通过暴力反射获取到私有的play方法:

System.out.println("-----通过暴力反射获取到私有的play方法传入参数)↓-----");

Method earMethod3 = Person.class.getDeclaredMethod("play", String.class);

//在访问私有的属性的方法之前,先要设置运行访问

earMethod3.setAccessible(true);

earMethod3.invoke(per,"小王");

}

输出:

-----获取到Person以及父类Object里面的public方法↓-----

public void Test02.Person.eat(java.lang.String)

方法名:eat

public void Test02.Person.eat()

方法名:eat

public final void java.lang.Object.wait() throws java.lang.InterruptedException

方法名:wait

public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

方法名:wait

public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

方法名:wait

public boolean java.lang.Object.equals(java.lang.Object)

方法名:equals

public java.lang.String java.lang.Object.toString()

方法名:toString

public native int java.lang.Object.hashCode()

方法名:hashCode

public final native java.lang.Class java.lang.Object.getClass()

方法名:getClass

public final native void java.lang.Object.notify()

方法名:notify

public final native void java.lang.Object.notifyAll()

方法名:notifyAll

小结:

以上就是小应学长对反射的理解和方法的应用(当然还有很多方法,这里就不一一举例,大家可以查看官网文档和其他技术博客开学习),其实我刚开始接触反射的时候也很难理解反射的概念,也是通过大量的视频和查看其他的博客来结合每个人的见解,这篇文章也有很多不足之处,欢迎大家批评指正,一起共同进步。

当然反射也有缺点(查阅其他博客的知识):

性能问题: 使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。

反射会模糊程序内部逻辑:一般开发人员希望在源代码中看到程序内部的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。其实反射代码比直接的代码更复杂。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java分布式面试CAP分别代表含义分析
下一篇:java基础二叉搜索树图文详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~