反射(Reflection) --Java学习笔记

反射

  • 反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)

反射学什么?

学习获取类的信息、操作它们

  1. 反射第一步:加载类,获取类的字节码:Class对象
  2. 获取类的构造器:Constructor对象
  3. 获取类的成员变量:Field对象
  4. 获取类的成员方法:Method对象

全部认识完后,再看反射的应用场景

1、反射第一步:加载类,获取类的字节码:Class对象

获取Class对象的三种方式

  • Class c1=类名.class
  • 调用Class提供方法:  public static Class forName(String package)
  • Object提供的方法:  publicClass getClass();  Class c3=对象.getClass()

代码演示:

package com.zeyu.reflect;

public class Test1Class {
    public static void main(String[] args) throws Exception {
        Class c1 = Student.class;
        System.out.println(c1.getName());   //全类名
        System.out.println(c1.getSimpleName()); //简名:Student

        Class c2 = Class.forName("com.zeyu.reflect.Student");   //填全类名
        System.out.println(c1 == c2);   //拿到的是同一个对象

        Student s = new Student();  //创建类的实例
        Class c3 = s.getClass();    //调用getClass方法
        System.out.println(c3 == c2);   //拿到的依旧是同一个对象
    }
}

运行结果:

2、获取类的构造器:Constructor对象

Class提供了从类中获取构造器的方法

获取类构造器的作用:依然是初始化对象返回

代码演示:

package com.zeyu.reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class Test2Constructor {
    @Test
    public void testGetConstructors() {
        //1、反射第一步,必须先得到这个类的class对象
        Class c = Cat.class;
        //2、获取类的全部构造器
//        Constructor[] constructors = c.getConstructors();   //只能拿public类型的构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        //3、遍历数组中的每一个构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "-->" + constructor.getParameterCount());
        }
    }

        @Test
        public void testGetConstructor() throws Exception {
            //1、反射第一步,必须先得到这个类的class对象
            Class c = Cat.class;
            //2、获取某一个构造器:无参构造器
//            Constructor constructor = c.getConstructor(); //只能拿public类型的构造器
            Constructor constructor = c.getDeclaredConstructor();   //存在就能拿到
            System.out.println(constructor.getName() + "-->" + constructor.getParameterCount());
            constructor.setAccessible(true);    //禁止检查访问权限
            Cat cat = (Cat) constructor.newInstance();  //调用构造器完成对象初始化
            System.out.println(cat);

            //获取有参构造器
            Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
            System.out.println(constructor2.getName() + "-->" + constructor2.getParameterCount());
            constructor2.setAccessible(true);
            Object cat2 = constructor2.newInstance("黑猫警长", 3);  //初始化对象
            System.out.println(cat2);
        }
}

运行结果:

也可以用反射破坏单例设计模式

3、获取类的成员变量:Field对象

Class提供了从类中获取成员变量的方法

获取到成员变量的作用:依然是赋值、取值

代码演示:

package com.zeyu.reflect;

import org.junit.Test;

import java.lang.reflect.Field;

public class Test3Field {
    @Test
    public void testGetFields() throws Exception {
        //反射第一步,必须先拿到类的class对象
        Class c = Cat.class;
        //获取类的全部成员变量
        Field[] fields = c.getDeclaredFields();
        //遍历这个成员变量数组
        for (Field field : fields) {
            System.out.println(field.getName() + "--->" + field.getType());
        }

        //拿到某个成员变量
        Field fName = c.getDeclaredField("name");
        System.out.println(fName.getName() + "--->" + fName.getType());

        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "--->" + fAge.getType());

        //赋值
        Cat cat = new Cat();
        fName.setAccessible(true);    //暴力访问
        fName.set(cat,"小橘");
        System.out.println(cat);

        //取值
        String name = (String) fName.get(cat);
        System.out.println(name);
    }
}

运行结果:

4、获取类的成员方法:Method对象

Class提供了从类中获取成员方法的API

成员方法的作用:依然是执行

代码演示:

package com.zeyu.reflect;

import org.junit.Test;

import java.lang.reflect.Method;

public class Test4Methods {
    @Test
    public void TestGetMethods() throws Exception {
        //1、反射第一步,先得到类的class对象
        Class c = Cat.class;
        //2、获取类的全部成员方法
        Method[] methods = c.getDeclaredMethods();
        //3、遍历这个数组的每个方法对象
        for (Method method : methods) {               //getParameterCount()统计形参个数
            System.out.println(method.getName() + "--->" + method.getParameterCount() + "--->"
            + method.getReturnType());
        }
        //4、获取某个方法对象
        Method run = c.getDeclaredMethod("run");
        System.out.println(run.getName() + "--->" + run.getParameterCount() + "--->"
                + run.getReturnType());

        Method eat = c.getDeclaredMethod("eat", String.class);
        System.out.println(eat.getName() + "--->" + eat.getParameterCount() + "--->"
                + eat.getReturnType());

        Cat cat = new Cat();
        run.setAccessible(true);    //禁止检查访问权限
        Object rs = run.invoke(cat);//调用无参run方法,用cat对象调用
        System.out.println(rs); //无返回值,返回结果为空

        eat.setAccessible(true);
        Object rs2 = (String) eat.invoke(cat, "鱼");
        System.out.println(rs2);
    }
}

运行结果:

反射的作用?

  • 基本作用:可以得到一个类的全部成分然后操作
  • 可以破坏封装性
  • 最重要的用途是:适合做lava的框架,基本上,丰流的框架都会基于反射设计出一些通用的功能

案例:使用反射做一个简易版的框架

需求:
对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

实现步骤

  1. 定义一个方法,可以接收任意对象
  2. 每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量
  3. 遍历成员变量,然后提取成员变量在该对象中的具体值
  4. 把成员变量名、和其值,写出到文件中去即可

代码演示:

实现类:

package com.zeyu.reflect;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class ObjectFrame {
    //保存任意对象的字段和数据到文件中去
    public static void saveObject(Object obj) throws Exception {
        PrintStream ps = new PrintStream(new FileOutputStream("src\\com\\zeyu\\reflect\\data.txt",true));
        //obj是任意对象,到底有多少字段需要保存
        Class c = obj.getClass();
        String cname = c.getSimpleName();
        ps.println("------------------" + cname + "------------------");
        //从这个类中提取它的全部成员变量
        Field[] fields = c.getDeclaredFields();
        //遍历每个成员变量
        for (Field field : fields) {
            field.setAccessible(true);
            //拿到成员变量的名字
            String name = field.getName();
            //拿到这个成员变量在对象中的数据
            String value = field.get(obj) + "";
            ps.println(name + "=" + value);
        }
        ps.close();
    }
}

测试类:

package com.zeyu.reflect;

import org.junit.Test;

public class Teat5ObjectFrame {
    @Test
    public void testSave() throws Exception {
        Cat cat = new Cat("小橘",2);
        Student s = new Student("小明","男",22,172.8);

        ObjectFrame.saveObject(cat);
        ObjectFrame.saveObject(s);
    }
}

运行结果:

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A泽予

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值