首页 > 编程语言 >java之反射篇(上)——基本使用

java之反射篇(上)——基本使用

时间:2024-08-08 13:54:36浏览次数:11  
标签:基本 反射 java name System 获取 Student println String

目录

一、什么是反射

二、获取class对象的3种方法

三、反射获取构造方法

四、反射获取成员变量

五、反射获取成员方法

 六、反射的作用

 七、反射的两种使用方式

1.Demo1保存信息

2.Demo2结合配置文件获取类信息


一、什么是反射

反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

idea里面的变量,成员方法的提示,都是靠反射获取的,类的信息都被扒的干干净净 

 要使用反射就必须获取类的Class文件,从类的Class对象上获取类的所有信息。

下面就会讲如何获取Class对象

二、获取class对象的3种方法

3种方法对应着代码的3个不同的阶段

 下面是一个测试类Student

class Student{
    private String name;
    public int age;
    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    protected Student(int age) {
        this.age = age;
    }

    private Student(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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

下面代码,通过3种方式获得Student类的字节码文件对象,以及比较

public class test1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取Class对象的三种方式比较
        //1.通过Class.forName("全类名")
        Class<?> clazz = Class.forName("reflect.test.Student");
        System.out.println(clazz);
        //2.通过类名.class
        Class<?> clazz1 = Student.class;
        System.out.println(clazz1);
        //3.通过对象的getClass()
        Student student = new Student();
        Class<? extends Student> clazz2 = student.getClass();
        System.out.println(clazz2);

        //因为类的字节码文件只有一个即Class字节码文件
        //所以都为true
        System.out.println(clazz == clazz1);
        System.out.println(clazz == clazz2);
        System.out.println(clazz1 == clazz2);
    }
}

第一种方式是最为常用的,第二种方式一般作为参数传递使用,第三种只有在有对象的情况下使用 

获得class对象后,就可以通过class对象获取类的构造方法,成员变量,成员方法了。

在反射里面,构造方法,成员变量,成员方法通通视为类

于是我们可以通过class对象的成员方法获取类信息对象——构造方法类Constructor、成员变量类Field、成员方法类Method。

获得类的构造方法,成员变量和成员方法后可以获得三者的信息

三、反射获取构造方法

1.通过class对象的成员方法获得类的构造方法,实际上返回的是类对应的Constructor类。

2.获得的构造方法类的对象可以使用其成员方法创建类的对象。

下面是class对象获取构造方法类的对象的成员方法

和构造方法类对象创建类的对象的成员方法

//获取Student类的所有构造方法
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println(constructor);
}
//获取Student类的指定构造方法
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
//因为两个参数的构造方法私有,所以需要使用暴力反射
//才能使用这个构造方法创建对象
constructor.setAccessible(true);
Student student1 = (Student) constructor.newInstance("张三", 18);
System.out.println(student1);//Student{name='张三', age=18}

//获取构造器后
//可以获取构造器的信息
//比如修饰词、参数列表、返回值类型
//获取构造器的修饰词
System.out.println(constructor.getModifiers());//2代表private
//获取构造器的参数列表
System.out.println(constructor.getParameterTypes());
//获取构造器的返回值类型
System.out.println(constructor.getName());

暴力反射:获得的构造器是私有的private修饰,不能直接使用,必须constructor.setAccessible(true);暴力反射后,临时取消权限校验,就可以使用反射获得的构造方法了。

四、反射获取成员变量

 还能获取成员变量的修饰词、类型、名字、变量的值(上面的获取值)

public class test2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //1.获取类的class对象
        Class<?> clazz = Class.forName("reflect.test.Student");

        //2.获取成员变量的对象
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        Field name = clazz.getDeclaredField("name");
        //name是私有的,要暴力反射
        name.setAccessible(true);
        Student student = new Student();
        //set方法
        //第一个参数:对象
        //第二个参数:对应成员变量赋值或改变值
        name.set(student, "张三");
        //get方法
        //获取对象的对应成员变量的值
        System.out.println(name.get(student));//张三
    }
}

五、反射获取成员方法

 还能获得成员方法的修饰符、方法的名字、形参、返回值、方法的抛出的异常。

//1. 获取class字节码文件对象
Class clazz = Class.forName("com.itheima.myreflect4.Student");

//2. 获取里面所有的方法对象(包含父类中所有的公共方法)
 /* Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}*/

// 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
/*Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
    System.out.println(method);
}*/

// 获取指定的单一方法
Method m = clazz.getDeclaredMethod("eat", String.class);
System.out.println(m);

// 获取方法的修饰符
int modifiers = m.getModifiers();
System.out.println(modifiers);

// 获取方法的名字
String name = m.getName();
System.out.println(name);

// 获取方法的形参
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
    System.out.println(parameter);
}

//获取方法的抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
    System.out.println(exceptionType);
}

//方法运行
/*Method类中用于创建对象的方法
Object invoke(Object obj, Object... args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)*/


Student s = new Student();
m.setAccessible(true);
//参数一s:表示方法的调用者
//参数二"汉堡包":表示在调用方法的时候传递的实际参数
String result = (String) m.invoke(s, "汉堡包");
System.out.println(result);

 六、反射的作用

1.获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑

2.结合配置文件,动态的创建对象并调用方法

 七、反射的两种使用方式

1.Demo1保存信息

public class Demo1 {
    public static void main(String[] args) throws IllegalAccessException, IOException {
        Student s = new Student("小王", 18,"女","1234567");
        Teacher t = new Teacher("小李", 35);
        saveObject(s);
    }

    private static void saveObject(Object obj) throws IllegalAccessException, IOException {
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();

        BufferedWriter bw = new BufferedWriter(new FileWriter("files\\a.txt"));
        for (Field field : fields) {
            field.setAccessible(true);
            String name = field.getName();
            Object value = field.get(obj);
            String line = name + ":" + value;
            bw.write(line);
            bw.newLine();
        }
        bw.close();//将缓冲区的数据刷新到文件
    }
}

2.Demo2结合配置文件获取类信息

下面是配置文件的位置和信息: 

 

主要记录类的全名和类的成员方法 

 

准备好的两个类Student和Teacher

public class Student {
    private String name;
    private int age;
    private String gender;
    private String phone;

    public Student() {
    }
    public Student(String name, int age, String gender, String phone) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.phone = phone;
    }
    private void study(){
        System.out.println("学生在学习");
    }
}
public class Teacher {
    private String name;
    private int age;

    public Teacher() {
    }
    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }
    private void teach(){
        System.out.println("老师在教课");
    }
}

通过配置文件读取上面两个类信息

下面是通过配置文件(记录Student类的全类名和方法名)反射读取Student类的信息

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Properties properties = new Properties();
        FileReader fr = new FileReader("prop.properties");
        properties.load(fr);
        String className = properties.getProperty("classname");
        String methodName = properties.getProperty("method");
        //通过配置文件的类名获取类对象
        Class<?> clazz = Class.forName(className);
        //获取无参构造器创建对象
        Constructor<?> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        Object o = constructor.newInstance();
        //获取叫做study的成员方法并调用
        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(o);
    }
}

 如果要读取Teacher类的信息只要修改配置文件就可以了,修改后的配置文件的内容如下:

 

标签:基本,反射,java,name,System,获取,Student,println,String
From: https://blog.csdn.net/2202_75483664/article/details/141001909

相关文章

  • AI入门之深度学习:基本概念篇
    1、什么是深度学习1.1、机器学习  图1:计算机有效工作的常用方法:程序员编写规则(程序),计算机遵循这些规则将输入数据转换为适当的答案。这一方法被称为符号主义人工智能,适合用来解决定义明确的逻辑问题,比如早期的PC小游戏:五子棋等,但是像图像分类、语音识别或自然语言翻译等......
  • from type [java.lang.String] to type [org. apache.kafka.clients.consumer.Consume
    kafka消费消息的时候,报错Noconverterfoundcapableofconvertingfromtype[java.lang.String]totype[org.apache.kafka.clients.consumer.ConsumerRecord<??>,没有消费到数据,这种情况可能是发送方发送的数据是封装了多个ConsumerRecord<??>对象发送过来的,需要用Consume......
  • ArcGIS API for JavaScript 3.x 到 4.x 的升级手册
    众所周知,3.x版本主要是构建二维地图,且基本不会再添加新功能;而4.x版本主要是构建于三维地图,与3.x相比并不是简单的升级,基本上就是重写了。所以当我们需要把API从3.x升级到4.x时,应用程序基本上是需要重写的,这里将对API升级过程中涉及到的相关变动进行记录与描述。以下......
  • Java 中 Exception 和 Error 有什么区别?
    1.ExceptionException代表程序正常运行过程中可以预料到的意外情况,应该被开发者捕获并进行相应处理。2.ErrorError指在正常情况下不太可能出现的情况。大部分Error导致程序处于不正常、不可恢复的状态,所以不便也不需被开发者捕获,因为这个情况下你捕获了也无济于事......
  • 什么是 Java 中的不可变类?
    不可变类是指创建后无法修改对象状态的类。String类是Java中典型的不可变类。1.不可变类的特点一旦创建,对象的状态就不能被改变。所有成员变量都是final类型。所有可变成员变量都是私有的,并且没有提供修改它们的公共方法。2.不可变类的示例以String类为例,执行s......
  • Flink开发:Java vs. Scala - 代码对比分析,选择你的最佳拍档
    一、引言1.1Flink简介ApacheFlink是一个开源的流处理框架,它支持高吞吐量、低延迟以及复杂的事件处理。Flink的核心是一个流式数据流执行引擎,它的针对数据流的分布式计算提供了数据分发、通信、容错机制。Flink提供了多种API,包括DataStreamAPI(用于构建流处理程序)、D......
  • 基于JAVA的宠物店会员管理系统设计与实现,源码、部署+讲解
    摘要随着计算机和网络的不断革新,世界也已进入了前所未有的电子时代。作为实用性强、应用范围广泛的会员管理系统也在被越来越多的行业所使用。当今社会经济发展迅速,宠物在人们生活中的地位也越来越高。市场上迫切需求一款便携操作的宠物会员管理。因此需要设计开发在效率、功......
  • Java 基础
    Java基础目录Java基础1第一个Java程序2IDEA中的代码结构3Variables与Types3.1数据类型3.2变量的注意事项3.3关键字3.4标识符4运算符4.1算术运算符4.1.1不同数字类型相加4.1.2字符相加4.1.3字符串相加4.3赋值运算符4.4关系运算符4.5逻辑运算符5逻辑控制语句5......
  • Java poi3.17 如何区分获取日期类型的单元格的值
     1、网上看了好多方案,似乎都没有效果。2、解决方法:如果是日期类型的单元格,index是等于3的。但是我偶尔到的情况,不是等于日期类型,也会等于3,这时获取Datedate=cell.getDateCellValue();值会报错,解决方法,就是用try/catch包起来,继续使用dataForMatter.formatCellValue(cel......
  • Java基础(面向对象)
    标签(空格分隔):Java面向对象的特征一:封装与隐藏一、问题引入当我们创建一个类的对象以后,我们可以通过“对象.属性”的方法,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和储存范围的制约。除此之外,没有其他约束条件。但是,实际问题中,我们往往需要给属性赋值加入额外......