Java学习日志(十)——反射

反射概述

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

反射的作用:

  • 分析类:
    加载并初始化一个类,查看类的所有属性和方法
  • 查看并使用对象:
    查看一个对象的所有属性和方法,使用对象的任意属性和方法

反射的应用场景:

  • 构造通用的工具
  • 搭建具有高度灵活性和扩展性的系统框架

类加载器(ClassLoader):

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

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

类的加载时机:

  • 创建类的实例:Student stu = new Student();
  • 访问类的静态成员:Calendar.getInstance();
  • 初始化类的子类:class User extends Person{} User user = new User(); //先加载父类
  • 反射方式创建类的Class对象:Class clazz = Class.forName("类的正名");
    正名:包名+类名,例:cn.itcast.demo1.Student

获取Class对象的三种方式:

  • Object类的getClass()方法
    Class clazz = 对象名.getClass();

  • 类的静态属性
    Class clazz = 类名.class;

  • Class类的静态方法
    Class clazz = Class.forName("类的正名")

实例:

package 反射;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Student stu = new Student();
        //方式一:Object类的getClass()方法
        Class clazz1 = stu.getClass();

        //方式二:类的静态属性
        Class clazz2 = Student.class;

        //方式三:Class类的静态方法
        Class clazz3 = Class.forName("反射.Student");

        System.out.println(clazz1 == clazz2);		//true
        System.out.println(clazz1 == clazz3);		//true
        System.out.println(clazz2 == clazz3);		//true
    }
}

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

Constructor <T>对象:
方法对象,属于java.base模块,java.lang.reflect包

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

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

  • getDeclareConstructor (Class<?>...parameterTypes)
    返回一个Constructor 对象,可获取私有构造函数

  • getConstructors ()
    返回此类所有(不含私有)构造函数的数组

Constructor 的常用方法:

  • Sring getName()
    返回构造函数名
  • T newInstance(Object...initargs)
    使用此构造函数和指定参数创建并初始化对象

Test类:

package 反射;

import java.lang.reflect.Constructor;

public class Test2 {
    public static void main(String[] args) throws Exception {
        //需求:通过反射的方式创建:Student类的对象

        //1.获取Student类的字节码文件对象
        Class clazz = Class.forName("反射.Student");

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

        //2.2获取公共的有参构造
        Constructor con2 = clazz.getConstructor(String.class);
        System.out.println(con2);

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

        //2.4获取Student类的所有公共的构造函数
        System.out.println("-----------------------");
        Constructor[] cons = clazz.getConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }*/
        Constructor con2 = clazz.getConstructor(String.class);
        System.out.println(con2);
        //获取构造器的名字,查看是哪个类的构造
        String name = con2.getName();
        System.out.println(name);

        //3.根据构造器的对象,创建对应的Student对象
        Student stu = (Student) con2.newInstance("PAG");

        //4.打印结果
        System.out.println(stu);

    }
}

Student类:

package 反射;


public class Student {
	//公共的空参构造
    public Student(){}
	//公共的有参构造
    public Student(String name){
        System.out.println("名字为" + name);
    }
	//私有的有参构造
    private Student(int age){
        System.out.println("年龄为" + age);
    }
}

运行结果:

public 反射.Student(java.lang.String)
反射.Student
名字为PAG
反射.Student@312b1dae

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

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

通过Class对象获取方法:

  • getMethod(String name,Class<?>...parameterTypes)
    返回一个Method对象,仅公共成员方法
    name:方法名
    parameterTypes:方法的参数列表

  • getDeclareMethod(String,Class<?>...)
    返回一个Method对象,可获取私有成员方法

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

Method的常用方法:

  • Sring getName()
    返回方法名
  • Object invoke(Object obj,Object...args)
    在指定对象上调用此方法,参数为args
  • public void setAccessible(boolean flag)
    是否开启暴力反射(true:开启)

Test类:

package 反射;

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

public class Test3 {
    public static void main(String[] args) throws Exception {
        //需求:通过反射获取Student类中的成员方法并调出
        //1.获取Student类的字节码对象
        Class clazz = Class.forName("反射.Student");

        //2.获取该类的构造器对象,然后创建Student类的对象
        Constructor con = clazz.getConstructor();
        Student stu = (Student)con.newInstance();

        //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,100);

        //3.3调用私有的带参方法
        Method method3 = clazz.getDeclaredMethod("show3", int.class, int.class);
        //开启暴力反射,无视私有关系
        method3.setAccessible(true);
        //调用此方法
        int sum = (int)method3.invoke(stu,10,20);
        System.out.println("两个数的和是:" + sum);
        System.out.println("---------------------");

        //3.4获取Student类中的所有成员方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
    }

Student类:

package 反射;

public class Student {
    //公共无参方法
    public void show1(){
        System.out.println("公共的空参方法");
    }
    //公共有参方法
    public void show2(int a){
        System.out.println("公共的有参方法,你输入的值为:" + a);
    }
    //私有有参方法
    private int show3(int a,int b){
        System.out.println("私有的带参方法");
        return a+b;
    }
}

运行结果:

public void 反射.Student.show1()
show1
公共的空参方法
---------------------
public void 反射.Student.show2(int)
show2
公共的有参方法,你输入的值为:100
私有的带参方法
两个数的和是:30
---------------------
public void 反射.Student.show1()
public void 反射.Student.show2(int)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

Process finished with exit code 0

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

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

通过Class对象获取属性:

  • getField(String name)
    返回一个Field对象,仅公共属性
    name:属性名
  • getDeclaredField(String name)
    返回一个Field对象,可获取私有属性
  • getDeclaredFields()
    返回此类所有(含私有)属性的数组

Field的常用方法:

  • void set(Object obj,Object value)
    设置obj对象的指定属性值为value
  • void setAccessible(boolean flag)
    将此属性的可访问性设置为指定布尔值

Test类:

package 反射;

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

public class Test4 {
    public static void main(String[] args) throws Exception {
        //需求:通过反射获取成员变量并使用
        //1.获取Student类的字节码文件对象
        Class clazz = Class.forName("反射.Student");
        //2.通过字节码文件对象获取构造器对象,然后创建学生类对象
        Constructor con = clazz.getConstructor();
        Student stu = (Student)con.newInstance();
       // Student stu = (Student)clazz.getConstructor().newInstance();  链式编程
        //3.设置学生对象的各个属性
        //3.1设置名字
        Field field1 = clazz.getField("name");
        field1.set(stu,"PAG");
        //3.2设置年龄
        Field field2 = clazz.getDeclaredField("age");
        //开启暴力反射
        field2.setAccessible(true);
        field2.set(stu,19);

        //4.打印学生对象
        System.out.println(stu);
    }
}

Student类:

package 反射;

public class Student {
	//公共成员
    public String name;
    //私有成员
    private int age;

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

运行结果:

Student{name='PAG', age=19}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FFFPAG

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

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

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

打赏作者

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

抵扣说明:

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

余额充值