当前位置: 首页 > news >正文

Java基础1-反射篇

1、页首请关注 思维导航大纲

2、大牛文章学习:

序号博主主要内容
1 sinat_38259539 总结的较全面的反射内容
2  

3、自己的理解:

3.1.本文大纲 

 

3.2.正文

1、获取class类的方法 

反射首先是要获取class类,获取class类有以下几种方法:

[参考博文:https://blog.csdn.net/beiyoujiayu/article/details/50451875] (感谢原文博主内容)内容如下,并对其中a、b、c 三点进行了验证:

#a&b. 内容验证:

public class Test {

   public static  void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
       System.out.println("111111");
       Class clazz = A.class;
       System.out.println("222222");
       A a = (A)clazz.newInstance();
       System.out.println("333333");

       System.out.println("\n111111");
       Class clazz1 =Class.forName("$reflect.B");
       System.out.println("222222");
       B b = (B)clazz1.newInstance();
       System.out.println("333333");
   }

}

class A{
    // 静态代码块
    static{
        System.out.println("hello A~");
    }
    // 非静态代码块
    {
        System.out.println("world A~");
    }
}
class B{ 
    static{
        System.out.println("hello B~");
    }
    {
        System.out.println("world A~");
    }
}

 

运行结果,大家仔细看看,这个结果的输出也是惊艳到我了,竟然不一样(底层实现细节还不清楚,哪位大牛看到是否能指教一下):

 

#c. 内容,这个博文写的不对,应该说class.forName 是动态加载,其他的是静态加载,

参考博文[java动态加载类和静态加载类: https://blog.csdn.net/su20145104009/article/details/52935472]

还有这篇文章:https://www.cnblogs.com/yangwenbin/p/4344294.html  

以及这篇文章:https://blog.csdn.net/zyw23zyw23/article/details/70244825

 核心差别是:两者的出现的时期不同:

     动态加载(运行时加载): Class.forName()在运行时加载;

     静态加载(编译时加载): Class.class和getClass()是在编译器加载

 

2、反射的过程,构造器、字段、方法 的反射

 class获取到以后,我们就可以为所欲为啦~~~~~~~

测试类:

class Human {
    public String publicField;
    protected String protectedField;
    private String privateField;
}
class Person extends Human{

    public String sex;
    private Integer age;
public double high; // 注意该字段没有get set 方法
private Person() { } public Person(Integer age, String sex) { this.age = age; this.sex = sex; } private void privateMethod() { System.out.println("执行私有方法"); } protected void protectedMethod() { System.out.println("执行protected方法"); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Person{" + "sex='" + sex + '\'' + ", age=" + age + '}'; } }

2.构造器的反射:

主要有以下几个方法,带 Declare的表示获取申明的所有构造器:

 

 

具体代码:

    Class clazz = Class.forName("$reflect.Person");
    System.out.println("获取公共构造器:");
    Constructor[] cons = clazz.getConstructors();
    for (Constructor con : cons) {
    System.out.println(con);
    }
    System.out.println("获取定义的所有构造器:");
    cons = clazz.getDeclaredConstructors();
    for (Constructor con : cons) {
    System.out.println(con);
    }
输出:
获取公共构造器:
public $reflect.Person(java.lang.Integer,java.lang.String)
获取定义的所有构造器:
private $reflect.Person()
public $reflect.Person(java.lang.Integer,java.lang.String)

获取对象:

        Class clazz = Class.forName("$reflect.Person");

        System.out.println("测试1:获取对象[获取私有构造器报错]");
        try {
            Constructor con = clazz.getConstructor();
            con.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

测试1:获取对象[获取私有构造器报错]
java.lang.NoSuchMethodException: $reflect.Person.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getConstructor(Class.java:1825)
at $reflect.Test2.main(Test2.java:27)

 

        System.out.println("测试2:获取对象[私有构造器直接获取对象报错]");
        try {
            Constructor con = clazz.getDeclaredConstructor();
            Object obj = con.newInstance(); //私有构造器获取对象直接报错
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }

测试2:获取对象[私有构造器直接获取对象报错]
java.lang.IllegalAccessException: Class $reflect.Test2 can not access a member of class $reflect.Person with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
at $reflect.Test2.main(Test2.java:29)


System.out.println(
"测试3:获取对象[成功]"); try { Constructor con = clazz.getDeclaredConstructor();
       // 设置为可读 con.setAccessible(
true); Object obj = con.newInstance(); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); }
测试3:获取对象[成功]

 

2.2.字段的反射:

方法:

代码:

    System.out.println("获取公共字段:");
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
        System.out.println(field);
    }

获取公共字段:

public java.lang.String $reflect.Person.sex

public double $reflect.Person.high

public java.lang.String $reflect.Human.publicField

    System.out.println("获取定义的所有字段:");
    fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        System.out.println(field);
    }

获取定义的所有字段:
public java.lang.String $reflect.Person.sex

public double $reflect.Person.high

private java.lang.Integer $reflect.Person.age

设置对象字段:

try {
        Constructor con = clazz.getDeclaredConstructor();
        con.setAccessible(true);
        Object obj = con.newInstance();
        System.out.println(obj);
        Field field = clazz.getField("sex");
        field.set(obj, "男");
        System.out.println(obj);
        //field = clazz.getField("age");    java.lang.NoSuchFieldException: age
        //field.set(obj, 28);
     field = clazz.getDeclaredField("age"); field.setAccessible(true); field.set(obj, 28); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); }

Person{sex='null', age=null}
Person{sex='男', age=null}
Person{sex='男', age=28}

总结1:没有get/set方法发字段也可以通过字段反射设置值:

    try {
        Class clazz = Class.forName("$reflect.Person");
        Object obj = new Person(28, "男");
        System.out.println(obj);

        Field f = clazz.getField("high");
        f.set(obj, 17);
        System.out.println(f.get(obj));
        System.out.println(obj);
    }
    catch (Exception e){
       e.printStackTrace();
    }

Person{sex='男', age=28, high=0.0}
17.0
Person{sex='男', age=28, high=17.0}

 

2.3.方法的反射: 

方法:

 

获取方法:

  System.out.println("获取公共方法:");
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
        System.out.println(method);
    }

获取公共方法:
public java.lang.String $reflect.Person.toString()
public java.lang.Integer $reflect.Person.getAge()
public void $reflect.Person.setAge(java.lang.Integer)
public java.lang.String $reflect.Person.getSex()
public void $reflect.Person.setSex(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()


    System.out.println("获取定义的所有方法:");
    methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
        System.out.println(method);
    }

获取定义的所有方法:
public java.lang.String $reflect.Person.toString()
private void $reflect.Person.privateMethod()
protected void $reflect.Person.protectedMethod()
public java.lang.Integer $reflect.Person.getAge()
public void $reflect.Person.setAge(java.lang.Integer)
public java.lang.String $reflect.Person.getSex()
public void $reflect.Person.setSex(java.lang.String)

执行方法:

    try {
        Constructor con = clazz.getConstructor(Integer.class, String.class);
        Person person = (Person)con.newInstance(10,"男");
        System.out.println(person); // Person{sex='男', age=10}

        Method method = clazz.getMethod("getAge");
        System.out.println(method.invoke(person)); // 10

        method = clazz.getMethod("setAge", Integer.class);
        method.invoke(person, 18);
        System.out.println(person.getAge()); // 18
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }

注意点1:观察以上输出,我们可以发现: 

  1、get Methods/Fields 能获取自身及父类的公开public修饰的方法和字段。

  2、getDeclared Methods/Fields 能自身所以修饰词的字段和方法,不能获取父类相关字段或方法。

即:通过本class的反射,不能获取父类 private/protected/default 的相关字段和方法。

      不过可以通过 clazz.getSuperClass()方法获取父类class后进行相关反射操作。

 

3、内省

定义:可以理解为是轻量级的反射,主要的作用是针对bean对象字段的操作

代码:

public class IntroSpectorTest {

    public static  void main(String[] args) throws Exception {
        Object obj = new Person1("男",18);

        BeanInfo person = Introspector.getBeanInfo(Person1.class) ;
        PropertyDescriptor[] pds = person.getPropertyDescriptors() ;
        for (PropertyDescriptor pd : pds) {
            System.out.println("\nname: "+pd.getName());
            System.out.println(pd.getReadMethod());
            System.out.println(pd.getWriteMethod());
            System.out.println(pd.getPropertyType());
            System.out.println(pd.getDisplayName());
            System.out.println("Get方法invoke: "+pd.getReadMethod().invoke(obj));
        }
    }
}

class Human1 {

    public Human1(){}

    // 父类 public 内省可以获取
    public Map getMap(){
        return null;
    }

name: map
public java.util.Map $reflect.Human1.getMap()
null
interface java.util.Map
map
Get方法invoke: null

}
class Person1 extends Human1{

    public String sex;
    private Integer age;
public double high; // 内省无get、set 方法
public Person1(String sex, Integer age) { this.sex = sex; this.age = age; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; }

name: age
public java.lang.Integer $reflect.Person1.getAge()
public void $reflect.Person1.setAge(java.lang.Integer)
class java.lang.Integer
age
Get方法invoke: 18

// 没有字段也可以获取, 没有set方法
    public Integer getAge1() {
        return 11;
    }

name: age1
public java.lang.Integer $reflect.Person1.getAge1()
null
class java.lang.Integer
age1
Get方法invoke: 11

// private 不行
    private Integer getAge2() {
        return 11;
    }
    // protected 不行
    protected Integer getAge3() {
        return 11;
    }
    // 不以get开头不行
    public Integer age4() {
        return 11;
    }
    // get大小写敏感,不行
    public Integer gETAge41() {
        return 11;
    }


    // 光有set不行,必须有get
    public void setAge5() {}

    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }

name: sex
public java.lang.String $reflect.Person1.getSex()
public void $reflect.Person1.setSex(java.lang.String)
class java.lang.String
sex
Get方法invoke: 男

}

 总结2:观察以上输出,我们可以发现: 

  1、内省是根据get方法获取字段,而非通过字段获取。

  2、对于没有get/set方法发字段,内省无法进行值的设置和获取,此时需要依赖字段反射,这也是为什么上面我说到:内省是轻量级的反射。

总结2-1源码分析,内省方法构建逻辑主要在这个方法中:

构建细节(看源码可以发现:static方法会过滤、is开头也可以是内省方法 等更多的逻辑细节):

 

4、修饰词:

 

 

5、class类原理(源码分析)、jvm加载类机制,反射源码分析

4、举一反三

5、总结领悟

转载于:https://www.cnblogs.com/do-your-best/p/9374574.html

相关文章:

  • set跟list的区别
  • ES6之路第十一篇:Reflect
  • SpringBoot | 第七章:过滤器、监听器、拦截器
  • 纯CSS实现垂直居中的几种方法
  • webapi跨域使用session
  • Zookeeper-watcher机制源码分析(一)
  • vs2017创建dotnetcore web项目,并部署到centos7上
  • Python爬虫开发【第1篇】【HTTP与HTTPS请求与响应】
  • 敏捷个人课后练习:接纳情绪
  • 大二暑假周进度报告之三
  • 记遇到的一个小问题:Tomcat在服务器上启动,但是远程访问却加载不到页面,Tomcat界面都打不开...
  • json格式的相互转化
  • mybatis 脚本
  • 探究 Redis 4 的 stream 类型
  • Flink的部署
  • 【RocksDB】TransactionDB源码分析
  • Docker容器管理
  • FineReport中如何实现自动滚屏效果
  • HTTP--网络协议分层,http历史(二)
  • HTTP中GET与POST的区别 99%的错误认识
  • java8 Stream Pipelines 浅析
  • java中具有继承关系的类及其对象初始化顺序
  • Python进阶细节
  • Redash本地开发环境搭建
  • vue-router的history模式发布配置
  • vue数据传递--我有特殊的实现技巧
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 来,膜拜下android roadmap,强大的执行力
  • 盘点那些不知名却常用的 Git 操作
  • 如何学习JavaEE,项目又该如何做?
  • 云大使推广中的常见热门问题
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • postgresql行列转换函数
  • ​io --- 处理流的核心工具​
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • (007)XHTML文档之标题——h1~h6
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (2)STM32单片机上位机
  • (ZT)出版业改革:该死的死,该生的生
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (六)Hibernate的二级缓存
  • .Mobi域名介绍
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net 程序发生了一个不可捕获的异常
  • .net 无限分类
  • .net反编译的九款神器
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • /etc/sudoers (root权限管理)
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • @Responsebody与@RequestBody
  • [ 蓝桥杯Web真题 ]-布局切换
  • [20190401]关于semtimedop函数调用.txt