首页 > 其他分享 >反射:框架设计的灵魂

反射:框架设计的灵魂

时间:2022-09-01 11:23:28浏览次数:60  
标签:反射 java String 框架 Class public Person class 灵魂

一、反射概述

反射:将类的各个组成部分(Class、Field、Constructor、Method)封装为其他对象(如Field对象、Constructor对象、Method对象),这就是反射机制

java代码在计算机中经历的三个阶段:源代码阶段→类对象阶段→运行时阶段

java文件通过编译(javac)生成字节码文件,java文件和字节码文件都在硬盘存储,此时为源代码阶段。

字节码文件通过类加载器(classLoader)加载进内存,内存中通过类对象来描述字节码文件,不管是什么字节码都有共同的属性,如成员变量、构造方法、成员方法。成员变量封装为Field对象,构造方法封装为constructor对象,成员方法封装为Method对象,这三个对象都在Class类中。一个类中可能有多个成员变量,故用Filed[]数组来描述所有的成员变量。构造器也可能有很多个, 故也用一个数组constructor[]来描述,同样,用Method[]数组来描述所有的方法。

好处:

1. 可以在程序运行过程中,操作这些对象。

  当我们定义了一个字符串,这个字符串会有很多方法提示,为什么呢?当字符串的字节码文件加载进内存,在内存中有一个class类对象,在类对象中已经将所有的方法抽取出来封装到Method[]数组中,进入展示出该字符串的所有方法,其实内部用到了反射机制。

2. 可以解耦,提高程序的可扩展性。

二、Class类对象

1、获取Class类对象的方式

1)、加载类对象

Class.forName("全类名"):将字节码文件加载进内存,返回Class类对象。

forName()是静态方法。

* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类。

Person实体类点击保存后就会自动编译,即有了字节码文件。

public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {
        //1.Class.forName("全类名")
        Class cls1 = Class.forName("cn.itcast.domain.Person");
        System.out.println(cls1);
    }
}

结果:class cn.itcast.domain.Person

2)、获取类对象

类名.class:如果内存中已经有这个对象了,可以通过类名的属性class获取

* 多用于参数的传递。

public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {//2.类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);
    }
}

结果:class cn.itcast.domain.Person

3)、如果已经有对象了,通过对象的getClass()方法获取

对象.getClass():getClass()方法在Object类中定义着。

* 多用于对象的获取字节码的方式。

public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {//3.对象.getClass()
        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);
    }
}

结果:class cn.itcast.domain.Person

那么这三种方式获取的类对象是一样的呢?

public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {
        //1.Class.forName("全类名")
        Class cls1 = Class.forName("cn.itcast.domain.Person");
        System.out.println(cls1);
        //2.类名.class
        Class cls2 = Person.class;
        System.out.println(cls2);
        //3.对象.getClass()
        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

        //== 比较三个对象
        System.out.println(cls1 == cls2);//true
        System.out.println(cls1 == cls3);//true
    }
}

结果如下:

class cn.itcast.domain.Person
class cn.itcast.domain.Person
class cn.itcast.domain.Person
true
true

注意:==比较的是对象的内存地址,如果地址值相同,那么说明是同一个对象。

结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

Person实体类

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

    public String a;
    protected String b;
    String c;
    private String d;


    public Person() {
    }

    public Person(String name, int age) {

        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }


    public void eat(){
        System.out.println("eat...");
    }

    public void eat(String food){
        System.out.println("eat..."+food);
    }
}

2、Class对象的方法

获取功能:

1)、获取成员变量们Field[],目的是设置值和获取值

* Field[] getFields() :获取所有public修饰的成员变量
* Field getField(String name)   获取指定名称的 public修饰的成员变量
* Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
* Field getDeclaredField(String name)  

Field成员变量的方法:

1)、设置值

* void set(Object obj, Object value)  

2)、获取值

* get(Object obj) 

3)、忽略访问权限修饰符的安全检查

* setAccessible(true):暴力反射

例1:

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        //1.Field[] getFields()获取所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
    }
}

结果:

public java.lang.String cn.itcast.domain.Person.a

例2:

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Field a = personClass.getField("a");
        System.out.println(a);
    }
}

结果:public java.lang.String cn.itcast.domain.Person.a

获取成员变量的值:

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Field a = personClass.getField("a");
//        System.out.println(a);
        //获取成员变量a 的值
        Person p = new Person();
        Object value = a.get(p);
        System.out.println(value);
        //设置a的值
        a.set(p,"张三");
        System.out.println(p);
    }
}

结果如下:

null
Person{name='null', age=0, a='张三', b='null', c='null', d='null'}

例3:

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        //Field[] getDeclaredFields():获取所有的成员变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    }
}

结果如下:

private java.lang.String cn.itcast.domain.Person.name
private int cn.itcast.domain.Person.age
public java.lang.String cn.itcast.domain.Person.a
protected java.lang.String cn.itcast.domain.Person.b
java.lang.String cn.itcast.domain.Person.c
private java.lang.String cn.itcast.domain.Person.d

例4:访问私有的成员变量

原来我们知道,私有的东西(如成员变量)不能在类的外边访问到,但是在暴力反射面其没有public和private,我的是我的,你的也是我的。

public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;        //获取成员变量a 的值
        Person p = new Person();//Field getDeclaredField(String name)
        Field d = personClass.getDeclaredField("d");
        //忽略访问权限修饰符的安全检查
        d.setAccessible(true);//暴力反射,设为true即忽略
        Object value2 = d.get(p);
        System.out.println(value2);
    }
}

注意:访问权限修饰符不是public修饰的成员的时候,在访问之前忽略权限修饰符的安全检查。

结果:null

2)、获取构造方法们Constructor[],目的是用来创建对象,方法是newInstance()

* Constructor<?>[] getConstructors()  // 获取所有public修饰的构造器
* Constructor<T> getConstructor(类<?>... parameterTypes)  // 获取指定参数类型的pulic修饰的构造器
* Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)  
* Constructor<?>[] getDeclaredConstructors()

创建对象的方法:

* T newInstance(Object... initargs)  

* 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

例1:

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Constructor[] constructors = personClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

结果如下:

public cn.itcast.domain.Person()
public cn.itcast.domain.Person(java.lang.String,int)

例2:

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        //Constructor<T> getConstructor(类<?>... parameterTypes)
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
    }
}

结果:public cn.itcast.domain.Person(java.lang.String,int)

注意,每个构造方法传的参数不一样。

例3:

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;//Constructor<T> getConstructor(类<?>... parameterTypes)
        Constructor constructor = personClass.getConstructor(String.class, int.class);
//        System.out.println(constructor);
        //创建对象
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
    }
}

结果:Person{name='张三', age=23, a='null', b='null', c='null', d='null'}

例4:获取无参构造

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
    }
}

结果:public cn.itcast.domain.Person()

例5:利用无参构造器创建对象

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Constructor constructor1 = personClass.getConstructor();        //创建对象
        Object person1 = constructor1.newInstance();
        System.out.println(person1);
    }
}

结果如下:

Person{name='null', age=0, a='null', b='null', c='null', d='null'}

例6:如果使用空参构造方法创建对象,操作可以简化:Class对象的newInstance方法。

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;        Object o = personClass.newInstance();
        System.out.println(o);
    }
}

结果:Person{name='null', age=0, a='null', b='null', c='null', d='null'}

注意:以后使用空参构造器创建对象的化, 都使用Class对象的newInstance方法。

例7:使用私有的构造器创建对象

将Person类的构造方法修改如下:public改为private

private Person(String name, int age) {

        this.name = name;
        this.age = age;
    }

获取私有构造器

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;//Constructor<T> getConstructor(类<?>... parameterTypes)
        Constructor constructor = personClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(constructor);//constructor1.setAccessible(true);
    }
}

结果:private cn.itcast.domain.Person(java.lang.String,int)

使用私有的构造器创建对象

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Constructor[] constructors = personClass.getConstructors();
        Constructor constructor = personClass.getDeclaredConstructor(String.class, int.class);//创建对象
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
    }
}

结果:报非法访问异常

Exception in thread "main" java.lang.IllegalAccessException: Class cn.itcast.reflect.ReflectDemo3 can not access a member of class cn.itcast.domain.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 cn.itcast.reflect.ReflectDemo3.main(ReflectDemo3.java:22)

使用暴力反射,即忽略安全检查

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Constructor[] constructors = personClass.getConstructors();
        Constructor constructor = personClass.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);//创建对象
        Object person = constructor.newInstance("张三", 23);
        System.out.println(person);
    }
}

结果:Person{name='张三', age=23, a='null', b='null', c='null', d='null'}

3)、获取成员方法们Method[]

* Method[] getMethods()   // 获取所有public修饰的成员方法
* Method getMethod(String name, 类<?>... parameterTypes)   // 获取指定方法名称和参数类型的public修饰的成员方法
* Method[] getDeclaredMethods()  
* Method getDeclaredMethod(String name, 类<?>... parameterTypes)  

方法调用:

1、执行方法:

* Object invoke(Object obj, Object... args)  

2、获取方法名称:

* String getName:获取方法名

例1:获取所有public修饰的方法

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
//        //获取所有public修饰的方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            String name = method.getName();
            System.out.println(name);
            //method.setAccessible(true);
        }
    }
}

结果如下:

public java.lang.String cn.itcast.domain.Person.toString()
toString
public java.lang.String cn.itcast.domain.Person.getName()
getName
public void cn.itcast.domain.Person.setName(java.lang.String)
setName
public void cn.itcast.domain.Person.setAge(int)
setAge
public void cn.itcast.domain.Person.eat()
eat
public void cn.itcast.domain.Person.eat(java.lang.String)
eat
public int cn.itcast.domain.Person.getAge()
getAge
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 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

注意:Person类还有隐藏的继承Object的方法。

例2:获取指定名称的无参成员方法

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        //获取指定名称的方法
        Method eat_method = personClass.getMethod("eat");
        System.out.println(eat_method);
    }
}

结果:public void cn.itcast.domain.Person.eat()

例3:调用无参成员方法

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {

        //0.获取Person的Class对象
        Class personClass = Person.class;
        //获取指定名称的方法
        Method eat_method = personClass.getMethod("eat");
        Person p = new Person();
       //执行方法
        eat_method.invoke(p);
    }
}

结果:eat...

例4:调用含参成员方法:

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Person p = new Person();        
Method eat_method2 = personClass.getMethod("eat", String.class); //执行方法 eat_method2.invoke(p,"饭"); } }

结果如下:eat...饭

例5:执行私有的成员方法

修改Person类中的方法:

private void eat(String food){
        System.out.println("eat..."+food);
    }

调用私有方法

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Person p = new Person();        Method eat_method2 = personClass.getDeclaredMethod("eat", String.class);
//        //执行方法
        eat_method2.invoke(p,"饭");
    }
}

结果:报非法访问异常

Exception in thread "main" java.lang.IllegalAccessException: Class cn.itcast.reflect.ReflectDemo4 can not access a member of class cn.itcast.domain.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.Method.invoke(Method.java:491)
    at cn.itcast.reflect.ReflectDemo4.main(ReflectDemo4.java:23)

使用暴力反射

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        Person p = new Person();        Method eat_method2 = personClass.getDeclaredMethod("eat", String.class);
        eat_method2.setAccessible(true);
        //执行方法
        eat_method2.invoke(p,"饭");
    }
}

结果:eat...饭

4)、获取全类名

* String getName()  

例1:

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //0.获取Person的Class对象
        Class personClass = Person.class;
        //获取类名
        String className = personClass.getName();
        System.out.println(className);//cn.itcast.domain.Person
    }
}

结果:cn.itcast.domain.Person

标签:反射,java,String,框架,Class,public,Person,class,灵魂
From: https://www.cnblogs.com/zwh0910/p/16639225.html

相关文章

  • 下一代 CSS 框架推荐
    tailwindcss:https://tailwindcss.com/WindiCSS:https://cn.windicss.org/unocssunocss是AnthonyFu大佬写的;unocss:https://github.com/unocss/unocss......
  • Swoole实战之手撸HttpServer框架 19 ORM整合(1)初步封装Laravel ORM库、基本查询、使用
    视频地址https://www.bilibili.com/video/BV14E411t7T4?p=28&spm_id_from=pageDriver&vd_source=4a69745b599dffec877b0fcfe130b0921封装composerrequireilluminate......
  • 使用 Gin 框架在 GoLang 中构建 API 服务
    使用Gin框架在GoLang中构建API服务今天我将向你展示如何在Go中构建一个简单的API服务。我们的项目演示将是一个简单的作者和他们的图书库项目。第一步:首先,我......
  • django框架03
    目录静态文件操作静态文件资源及配置form表单注意事项request对象方法pycharm连接MySQLdjango连接MySQLdjangoORMORM操作MySQL操作数据的增删改查操作外键创建静态文件操......
  • 大数据分析常用组件、框架、架构介绍(Hadoop、Spark、Storm、Flume、Kafka、Logstash、
    首先,数据传输组件:①Kafka是用Scala编写的分布式消息处理平台。②Logstash是用JRuby编写的一种分布式日志收集框架。③Flume是用Java编写的分布式实时日志收集框架。......
  • django框架-2
    目录静态文件及相关配置请求方法request对象方法pycharm连接mysqldjango连接MySQLdjango与ormorm语法orm外键关联8.31小练习静态文件及相关配置1.先编写一个登录功能 1.......
  • Go反射
    Go中的反射反射有时我们需要写一个函数,这个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,也可能布局未知,也有可能这个类型在我们设计函数时还不存在,这......
  • 用Vue框架实现 - 点击切换图片
     <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"con......
  • 用Vue框架实现 - JSON数据渲染页面
     <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="referrer"content="no-referrer"/><metahttp-equiv="X-UA-Compatibl......
  • 用Vue框架实现 - 移动端的tabbar
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"conten......