Java-反射

Java-反射

文章推荐

https://blog.csdn.net/ju_362204801/article/details/90578678

有视频,非常好理解,强烈推荐

简单理解

类是一个模板,用于描述一类对象的行为和状态,对象是类的一个实例,有状态和行为。类对象,是用于描述这种类,都有什么属性、方法的。

反射是从Class类对象开始,因为万物皆可对象,代码存储在.java文件中,编译得到.class文件,用于执行,即这些class文件就是Class类。反射就是对这个这个Class类进行 “解剖” ,感觉这个词用的很形象。“解剖” 是在Class类对象中,利用反射把一个类的成员变量、方法、属性等信息,映射成一个个对象。然后对对象进行操作。

反射主要是用于框架(尤其是Spring框架)和工具开发,是框架设计的关键,但耗性能。当需要切换调用业务方法,可以不需要修改代码,不需要重新编译,只修改对应配置文件,通过反射调用,实现切换调用另外的业务方法。

 

获取类对象

使用反射先要得到想反射的类,有多种方法获得Class对象。

  1. Class.forName
  2. Test_Main.class
  3. new Test_Main().getClass()

 需要抛出多种异常

    //三种获取Class类的方法
    public void test1() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
    }

    public void test2() throws Exception{
        Class tClass = Test_Main.class;
    }

    public void test3() throws Exception{
        Class tClass = new Test_Main().getClass();
    }

 Class实例: 就是指JVM中一份字节码,一个类在JVM中只有一份字节码。在一个JVM中,一种类,只会有一个类对象存在。所以不同方式取出来的类对象,都是一样的。

 

Java创建对象

另外Java创建对象的方法有很多。

  • 通过new语句实例化一个对象
  • 通过反射机制创建对象
  • 通过clone()方法创建对象
    • 在使用clone()方法,不会调用构造函数,而是需要有一个分配了内存的源对象。在创建新对象时,首先应该分配一个和源对象一样大的内存空间。
  • 通过反序列化的方式创建对象
    • 序列化就是把对象通过流的方式存储到文件里,那么反序列化就是把字节内容读出来,并还原成Java对象,这里还原的过程就是反序列化,使用反序列化时也不会调用构造方法。

 反射方法

无参方法

    /*  m1() 无参方法
        public void m1(){
        System.out.println("m1");
    }
     */
    @Test
    public void test1() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Test_Main test_main = (Test_Main)tClass.newInstance(); //新建实例
        Method m1 = tClass.getMethod("m1",null); //输入空值
        m1.invoke(test_main,null); //调用实例和输入值
    }

 

 

含参方法

 

    /*  m2():
        public void m2(String name){
        System.out.println(name);
    }
     */
    @Test
    public void test2() throws Exception{
        Class tClass = Test_Main.class;
        Test_Main test_main = (Test_Main)tClass.newInstance();
        Method m2 = tClass.getMethod("m2", String.class);
        m2.invoke(test_main,"tom");//输出tom
    }

 

 

有返回类型和多参数方法

    /*
        public String m4(String name ,int age){
        return name+age;
    }
     */
    @Test
    public void test4() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Test_Main test_main = (Test_Main) tClass.newInstance();
        Method m4 = tClass.getMethod("m4", String.class, int.class);
        String returnValue = (String) m4.invoke(test_main,"jerry",5); //返回类型
        System.out.println(returnValue); //打印jerry5
    }

 

 

private 方法

 

反射private 方法会显示带锁,需要使用 getDeclaredMethod 方法调用,设置对象的Accessible的访问标志位为true,就可以通过反射获取私有变量。

 

    /*
    private void m3(){
        System.out.println("m3");
    }
     */
    @Test
    public void test3() throws Exception{
        Class tClass = new Test_Main().getClass();
        Test_Main test_main = (Test_Main)tClass.newInstance(); //新建实例
        Method m3 = tClass.getDeclaredMethod("m3",null); //强制访问
        m3.setAccessible(true); //设置访问标志位为 True
        m3.invoke(test_main,null); //打印m3
    }

 

 

static方法

不需要新建实例,直接获取方法。

    /*  static 方法
        public static void m5(){
        System.out.println("m5");
    }
     */
    @Test
    public void test5() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Method m5 = tClass.getMethod("m5",null); //没有返回值
        m5.invoke(null,null); // 没有实例化对象,无输入参数 打印m5
    }

 

反射属性和反射构造函数方法都是使用类似方法步骤。

 

 反射属性字段

    //属性字段
    public String name = "Paige";
    public static int id = 147;
    private int age = 5;

 

获取/修改属性

    @Test
    public void test1() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Test_Main test_main = (Test_Main) tClass.newInstance(); //新建实例

        Field field1 = tClass.getField("name"); //获取属性
        String returnValue = (String) field1.get(test_main); //通过get获取属性
        System.out.println(returnValue); //打印出:Paige

        field1.set(test_main,"tom"); //set修改属性
        System.out.println(field1.get(test_main)); //打印出:tom
    }

 

private属性

        Field field2 = tClass.getDeclaredField("age");
        field2.setAccessible(true); //private属性同样需要强制访问
        System.out.println(field2.get(test_main)); //打印出:5

 

static属性

        Field field3 = tClass.getField("id");
        System.out.println(field3.get(null)); //static 同样不需要实例,设置为null即可 //打印出:147

 

反射构造函数方法都是使用类似方法步骤,只是使用方法不同。

 

反射构造方法

无参构造方法

    /*
        public Test_Main() {
        System.out.println("无参构造方法");
    }
     */
    @Test
    public void test_constructor1() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Constructor constructor1 = tClass.getConstructor(null); //得到无参构造函数
        constructor1.newInstance(null); //用构造方法创建对象
    }

 

 

一个参数

    /*
        public Test_Main(String name) {
        this.name = name;
        System.out.println("name:"+name);
    }
     */
    @Test
    public void test_constructor2() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Constructor constructor1 = tClass.getConstructor(String.class); //得到String构造函数
        constructor1.newInstance("tomas"); //用构造方法创建对象,输出name: tomas
    }

 

多个参数

    /*
    public Test_Main(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("name: "+name+" age: "+age);
    }
 */
    @Test
    public void test_constructor3() throws Exception{
        Class tClass = Class.forName("com.hut.djh.Test_Main");
        Constructor constructor1 = tClass.getConstructor(String.class,int.class); //得到String、int构造函数
        constructor1.newInstance("tomas",58); //用构造方法创建对象,输出name: tomas age: 58
    }

 

源码

posted @ 2021-02-02 00:54  秃头不用洗发水  阅读(63)  评论(0编辑  收藏  举报