Java高级——反射

反射

(使编写的代码,更灵活,更高效)

学习目标

理解反射是什么,能做什么

能够正确使用反射技术获取类的成员并使用

一、基本概念

反射

在程序运行中分析类的一种能力;

(源文件(.java)—编译—》字节码文件(.class)——》运行(obj.method())

反过来即为反射。

功能

1、分析类

加载并初始化一个类;

查看类的所有的属性和方法;

2、查看并使用对象

查看一个对象的所有属性和方法;

使用对象的任意属性和方法;

应用场景

1、构建通用的工具;

2、搭建具有高度灵活性和扩展性的系统框架;

类加载器(ClassLoader)

负责将类的字节码文件(.class)加载到内存中,并生成对应的Class对象;

Class对象

java.lang.Class类的对象,也叫字节码文件对象,每个Class对象对应一个字节码文件;

类加载的时机

1、创建类的实例;

Student stu = new Student();

2、访问类的静态成员

Calendar.getInstance();

3、初始化类的子类

class User extends Person{}

User user = new User;//先加载父类字节码文件,然后加载子类的字节码文件

4、反射方式创建类的Class对象

Class clazz = Class.forName(“类的正名”); //正名:包名+类名

获取Class对象的三种方式

1、Object类的getClass()方法

Class clazz = 对象名.getClass();

2、类的静态属性

Class clazz = 类名.class;

3、Class类的静态方法

Class clazz = Class.forName(“类的正名”); //正名:包名+类名

注意:一个源文件(.java文件)对应一个字节码文件对象(.class)

代码学习

package demo;

/**
 * @author: @橘子先森
 * @create: 2020-11-11 23:28
 **/
public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //需求:获取Class对象
        //方式一、Object类的getClass()方法
        Student student = new Student();
        Class clazz1 = student.getClass();

        //方式二、类的静态属性

        Class clazz2 = Student.class;

        //方式三、Class类的静态方法

        Class clazz3 = Class.forName("demo.Student");	//正名:包名+类名
    }
}

二、反射方式获取构造方法并使用

Constructor< T >对象

构造器对象,属于java.base模块,java.lang.reflect包

通过Class对象获取构造器对象

1、getConstructor(Class<?>… parameterTypes)

返回一个Constructor对象,仅公共构造函数Class<?>… :可变参数,代表Class类型的数组,?:通配符,代表不确定的任意类型;

2、getDeclaredConstructor(Class<?>… parameterTypes)
返回一个Constructor对象,可获取私有构造函数;
3、getConstructors)
返回此类所有(不含私有)构造函数的数组;

Constructor的常用方法

1、String getName()

返回构造函数名;

2、T newInstance(Object… initargs)

使用此构造函数和指定参数创建并初始化对象;

代码学习

package demo;

/**
 * @author: @橘子先森
 * @create: 2020-11-11 23:30
 **/
public class Student {

    //公共的无参构造
    public Student() {
    }

    //公共的带参构造
    public Student(String name) {
        System.out.println("输入name值" + name);
    }

    //私有的带参构造
    private Student(int age) {
        System.out.println("输入age值" + age);
    }
}

package demo;

import java.lang.reflect.Constructor;

/**
 * @author: @橘子先森
 * @create: 2020-11-11 23:58
 **/
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        //需求:通过反射方式创建:Student类型的对象
        //1、获取Student类的字节码文件对象
        Class clazz1 = Class.forName("demo.Student");

        //2、根据第一获取的字节码文件对象,获取指定的构造器对象
        /*//2.1 获取公共的无参构造
        Constructor constructor1 = clazz1.getConstructor();
        System.out.println(constructor1);

        //2.2 获取公共的无参构造
        Constructor constructor2 = clazz1.getConstructor(String.class);
        System.out.println(constructor2);

        //2.3 获取私有的带参构造
        Constructor constructor3 = clazz1.getDeclaredConstructor(int.class);
        System.out.println(constructor3);

        System.out.println("——————————————————————————————————————————");
        //2.4 获取Student类的所有公共构造函数
        Constructor[] cons = clazz1.getConstructors();
        //遍历数组
        for (Constructor con : cons) {
            System.out.println(con);
        }*/

        //2.2 获取公共的无参构造————演示
        Constructor constructor2 = clazz1.getConstructor(String.class);
        System.out.println(constructor2);

        //获取构造器名字
        String name = constructor2.getName();
        System.out.println(name);

        //3、根据构造器对象和参数,创建对应的Student对象
        //Object 张三 = constructor2.newInstance("张三"); //需要向下转型Student类,强转
        Student student = (Student) constructor2.newInstance("张三");

        //4、打印结果
        System.out.println(student);
    }
}

三、反射方式获取成员方法并使用

Method对象

方法对象,属于java.base模块,java.lang.reflect包;

通过Class对象获取方法

1、getMethod(String name, Class<?>… parameterTypes)

返回一个Method对象,仅公共成员方法;

name :方法名;

parameterTypes :方法的参数列表;

2、getDeclaredMethod(String, Class<?>.….)

返回一个Method对象,可获取私有成员方法;

3、getMethods()

返回此类所有(不含私有)方法的数组;

setAccessible(true)

开启暴力反射;

Method的常用方法

1、String getName()

返回方法名;

2、Object invoke(Object obj,Object…args)

在指定对象上调用此方法,参数为args;

代码学习

package demo;

/**
 * @author: @橘子先森
 * @create: 2020-11-11 23:30
 **/
public class Student {

    public static void show1() {
        System.out.println("公共的空参方法");
    }

    public static void show2(int a) {
        System.out.println("公共的带参方法,a" + a);
    }

    private static int show3(int a, int b) {
        System.out.println("私有的带参方法");
        return a + b;
    }
}

import demo.Student;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @author: @橘子先森
 * @create: 2020-11-12 11:05
 **/
public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        //通过反射获取Student类中的成员方法并调用
        //1、获取Student类的字节码文件对象
        Class clazz = Class.forName("demo.Student");

        //2、获取该类的构造器对象,然后创建Student类的对象
        Constructor con = clazz.getConstructor();
        //Object o = con.newInstance(); //需要向下转型成Student类
        Student stu = (Student)con.newInstance();
        //System.out.println(stu);

        //3、获取该类的成员方法对象,然后调用此方法
        //3.1 调用公共的无参方法
        Method method1 = clazz.getMethod("show1");
        //打印方法对象
        System.out.println(method1);
        //打印方法名
        System.out.println(method1.getName());
        //调用方法
        method1.invoke(stu);
        System.out.println("————————————————————————————");

        //3.2 调用公共的带参方法
        Method method2 = clazz.getMethod("show2", int.class);
        //打印方法对象
        System.out.println(method2);
        //打印方法名
        System.out.println(method2.getName());
        //调用方法
        method2.invoke(stu,10);
        System.out.println("————————————————————————————");

        //3.3 调用私有的带参方法
        Method method3 = clazz.getDeclaredMethod("show3", int.class, int.class);
        //开启暴力反射
        method3.setAccessible(true);
        //调用此方法
        int sum = (int)method3.invoke(stu,19,21);
        System.out.println(sum);
        System.out.println("————————————————————————————");

        //3.4 获取Student类中所有的成员方法
        Method[] methods = clazz.getMethods();
        //遍历
        for (Method method : methods) {
            System.out.println(method); //因为Student类默认继承Object类,所以也会打印继承的
        }
    }
}

四、反射方式获取成员变量并使用

filed对象

域(属性,成员变量)对象,属于java.base模块,java.lang.reflect包;

通过Class对象获取属性

1、getField(String name)

返回一个Field对象,仅公共属性;

name: 属性名;

2、getDeclaredField(String name)

返回一个Filed对象,可获取私有的;

3、getDeclaredFields()

返回此类所有(含私有)属性的数组;

Filed类的常用方法

1、void set(Object obj,Object value)

设置obj对象的指定属性为value;

2、viod setAccessible(boolean flag) //暴力反射

将此属性的可访问性设置为指定布尔值

代码学习

package demo;

/**
 * @author: @橘子先森
 * @create: 2020-11-11 23:30
 **/
public class Student {
    public String name;
    private int age;

    //用来打印对象的属性值

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package demo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * @author: @橘子先森
 * @create: 2020-11-12 11:50
 **/
public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        //需求:通过反射获取成员变量并使用
        //1、获取Student类的字节码文件对象
        Class clazz = Class.forName("demo.Student");

        //2、通过字节码文件对象获取构造器对象,然后创建学生类对象
        /*Constructor con = clazz.getConstructor();
        Student student = (Student)con.newInstance();*/

        Student stu = (Student)clazz.getConstructor().newInstance();    //链式编程,当一个方法返回值还是一个对象时

        //3、设置学生对象的各个属性值
        //3.1 设置名字 公有
        Field name = clazz.getField("name");
        name.set(stu,"张三");

        //3.2 设置年龄 私有
        Field age = clazz.getDeclaredField("age");
        //开启暴力反射
        age.setAccessible(true);
        age.set(stu,12);
        
        //4、打印学生对象
        System.out.println(stu);
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值