vue项目接口域名动态的获取方法
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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~