Java反射--师承韩顺平

本文深入探讨了Java反射机制,包括反射的作用、获取Class对象的多种方式、类加载的阶段、通过反射创建对象、访问类的成员等。通过实例代码展示了如何利用反射动态加载类、创建实例、修改属性值和调用方法。此外,还提供了两个实战练习,进一步巩固反射的使用技巧。
摘要由CSDN通过智能技术生成

java反射详解

做项目必须熟练的技能

1. 介绍

问:反射是干什么的?
场景:根据一个配置文件的信息,创建一个类的实例。
通过反射可以实现动态加载的功能。。

1)反射允许程序执行期间通过Reflection API 获取任何类的内部信息
2)加载完类之后,堆中产生一个Class类的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息

项目框架底层就是反射,
优点:可以动态创建和使用对象,灵活
缺点:因为基本是解释执行,运行速度有影响

Class介绍:
在这里插入图片描述

反射示意图:
在这里插入图片描述

2. 反射操作

在这里插入图片描述
上代码:

在这里插入图片描述

package com.wts.reflection;

import com.wts.reflection.car.Car;

import java.lang.reflect.Field;

public class Reflection {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        String classPath = "com.wts.reflection.car.Car";

        //1.获取Car类 对应的Class类
        Class<?> cls = Class.forName(classPath);

        //2.输出cls
        System.out.println(cls);//--显示的cls对象    //class com.wts.reflection.car.Car
        System.out.println(cls.getClass());//--输出cls的运行类    //class java.lang.Class

        //3.得到包名
        System.out.println(cls.getPackage().getName());//--包名   //com.wts.reflection.car

        //4.得到类名
        System.out.println(cls.getName());//--类名    //com.wts.reflection.car.Car

        //5.创建实例对象
        Car car = (Car) cls.newInstance();
        System.out.println(car);//toString  //Car{brand='宝马', price=50000, color='白色'}

        //6.通过反射获取属性 brand
        Field brand = cls.getField("brand");
        System.out.println(brand.get(car));//*brand  //宝马

        //7.通过反射给属性赋值
        brand.set(car, "奔驰");
        System.out.println(brand.get(car));//奔驰

        //8.获取所有属性
        System.out.println("---------");
        Field[] fields = cls.getFields();
        for (Field field :
                fields) {
            System.out.println(field.get(car));
        }
    }
}

3.获取包装类的六种方式

不同阶段不同的取包装类的方式。
三个阶段上图有说到的:编译阶段,类加载阶段,运行阶段(有实例对象)

上代码:

package com.wts.reflection;

import com.wts.reflection.car.Car;

public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {

        String classAllPath = "com.wts.reflection.car.Car";

        //1.Class.forName   程序编译阶段
        Class<?> cls1 = Class.forName(classAllPath);
        System.out.println(cls1);

        //2.类名.class 类加载阶段   应用场景:用于参数传递
        Class<Car> cls2 = Car.class;
        System.out.println(cls2);

        //3.对象.getClass()   应用场景:有对象实例化了
        Car car = new Car();
        Class cls3 = car.getClass();
        System.out.println(cls3);

        //4.通过类加载器获取 类的Class对象
        //1)先得到类加载器car
        ClassLoader classLoader = car.getClass().getClassLoader();
        //2)通过类加载器得到 Class对象
        Class<?> cls4 = classLoader.loadClass(classAllPath);
        System.out.println(cls4);

        /*---另外两种特别的*/
        //5.基本数据类型得到Class类对象
        Class<Integer> intClass = int.class;
        System.out.println(intClass);
        Class<Boolean> booleanClass = boolean.class;
        System.out.println(booleanClass);
        //int
        //boolean

        //6.基本数据类型对应的包装类得到Class类对象 --5和6会自动装箱和拆箱
        Class<Integer> type = Integer.TYPE;
        System.out.println(type); //int
    }
}

4. 哪些类型有Class对象

在这里插入图片描述

5. 类加载

通过反射实现了类动态加载

在这里插入图片描述

静态加载和动态加载:

  • 静态加载:编译时加载相关的类,如果没有,则报错。
  • 动态加载:反射–>动态加载;运行时不用加载该类,(即使该类不存在),不报错(延后报错)(如下图:当输入2 后,才会报错。第一次运行不报错)
    在这里插入图片描述

类加载的三个阶段–以及类加载后内存分布情况:
在这里插入图片描述
加载阶段
在这里插入图片描述连接阶段–验证
在这里插入图片描述连接阶段–准备
在这里插入图片描述在这里插入图片描述

连接阶段–解析
在这里插入图片描述
在这里插入图片描述其中3,保证了内存只加载一个类?(锁)

6. 通过反射获取类的结构性息

在这里插入图片描述

在这里插入图片描述

7. 通过反射创建对象

在这里插入图片描述

上代码:

package com.wts.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*通过反射-创建实例对象*/
public class ReflectCreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {

        //1.获取Class类对象
        Class<?> aClass = Class.forName("com.wts.reflection.User");

        //2.通过public的无参构造器创建实例
        Object o = aClass.newInstance();
        System.out.println(o);

        //3.通过public的有参构造器创建实例
        /*constructor
            就是
                public User(int age, String name) {
                this.age = age;
                this.name = name;
                }
        */
        Constructor constructor = aClass.getConstructor(int.class, String.class);
        Object aaa = constructor.newInstance(66, "aaa");
        System.out.println(aaa);


        //4.通过非public的有参构造器创建实例 --暴破
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class);

        declaredConstructor.setAccessible(true);//通过暴力反射可以,访问私有private构造器
        Object o4 = declaredConstructor.newInstance(100, "zhangsan");
        System.out.println(o4);

    }
}

/*User类*/
class User {
    private int age = 20;
    private String name = "wts";

    public User() {
    }

    public User(int age, String name) {
        this.age = age;
        this.name = name;
    }

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

效果:
在这里插入图片描述

8. 通过反射访问类中的成员

在这里插入图片描述

爆破反射操作类的属性

上代码:

package com.wts.reflection;

import java.lang.reflect.Field;

public class ReflectGetClassInfo {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.得到Student类对应 Class对象
        Class<?> aClass = Class.forName("com.wts.reflection.Student");

        //2.创建对象
        Object o = aClass.newInstance();
        System.out.println(o);

        //3.用反射,设置age的值
        Field age = aClass.getField("age");
        age.set(o, 10);
        System.out.println(o);
        System.out.println(age.get(o));

        //4.用反射,设置name的值 --私有,用Declared + 爆破
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);
        name.set(null, "aaa"); //--因为name是静态的,在类加载的时候就存在了,
//        name.set(o,"aaa");
        System.out.println(o);

    }

}

class Student {
    public int age;
    private static String name; //--静态的,在类加载的时候就有了

    public Student() {
    }

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

反射访问方法

在这里插入图片描述
上代码:

package com.wts.reflection;

import java.lang.reflect.Method;

public class ReflectGetMethods {
    public static void main(String[] args) throws Exception {
        //1.获取类 -- 创建实例
        Class<?> aClass = Class.forName("com.wts.reflection.Boss");
        Object o = aClass.newInstance();

        //2.
        Method method = aClass.getMethod("hi", String.class);//带参方法
        method.invoke(o, "你好");

        //3.
        Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
        say.setAccessible(true);
        System.out.println(say.invoke(null, 20, "aaa", '男'));//--static可以 o可以取代null

        //4.返回值, 如果方法有返回值,统一返回Object,但是他运行类型和方法定义的返回类型一致(编译看左边运行看右边?)
        Object invoke = say.invoke(null, 500, "bbb", '女');
        System.out.println("invoke的运行类型=" + invoke.getClass());
    }
}


class Boss {
    public int age;
    private static String name; //--静态的,在类加载的时候就有了

    public Boss() {
    }

    private static String say(int n, String s, char c) {
        return n + " " + s + " " + c;
    }

    public void hi(String s) {
        System.out.println("hi" + s);
    }

}

两个练习

上代码:

package com.wts.reflection;

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

/*反射复习练习*/
public class Reflect_review {
    public static void main(String[] args) throws Exception {

        /*练习1 */

        //1.获取Class类,创建实例
        Class<?> aClass = Class.forName("com.wts.reflection.PrivateTest");
        Object o = aClass.newInstance();
        //2.获取属性
        Field name = aClass.getDeclaredField("name");
        name.setAccessible(true);//暴力
        System.out.println(name.get(o));
        //改
        System.out.print("反射更改属性后--");
        name.set(o, "天龙八部");
        System.out.println(name.get(o));

        //用getname方法
        Method getName = aClass.getDeclaredMethod("getName");
        Object invoke = getName.invoke(o);
        System.out.println(invoke);


        

        /*练习2*/
        Class<?> fileCls = Class.forName("java.io.File");
        //指定构造器,‘文件全路径’
        Constructor<?> declaredConstructor = fileCls.getDeclaredConstructor(String.class);
        //文件的全路径
        String allPath = "E:\\桌面\\csdn钢琴家\\1_CSDN代码\\1.txt";
        Object file = declaredConstructor.newInstance(allPath);//创建file对象了 -- file的运行类型就是File

        //得到对象方法
        Method createNewFile = fileCls.getDeclaredMethod("createNewFile");
        createNewFile.invoke(file);
        //file的运行类型就是File
        System.out.println();
        System.out.println(file.getClass());
        System.out.println("文件创建成功" + allPath);


    }
}

class PrivateTest {
    private String name = "hellokitty";
    //默认无参构造器

    public String getName() {
        return name;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值