Java反射

1.一个需求

根据配置文件re.properties指定信息,创建对象并调用方法
classfullpath=com.hspedu.Cat
method=hi

package com.hspedu;
public class Cat {
    private String name = "招财猫";
    public void hi(){
        System.out.println(name + " hi~");
    }
    public void cry(){
        System.out.println(name + " cry~");
    }
}
public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        // 根据配合文件re.properties指定信息,创建Cat对象并调用hi方法

        //传统的方法
        //Cat cat = new Cat();
        //cat.hi();

        // 1.使用Properties类,可以读写配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src/re.properties"));
        String classfullname = properties.get("classfullpath").toString();
        String methodName = properties.get("method").toString();

        System.out.println("classfullname => "  + classfullname); //classfullname => com.hspedu.Cat
        System.out.println("method => " + methodName); // method => hi


        // 2.创建对象,传统的方法,行不通

        // 3.使用反射机制解决
        // (1)加载类, 返回一个Class类型的对象
        Class<?> clazz = Class.forName(classfullname);
        // (2)通过 clazz 得到你加载的类 com.hspedu.Cat的对象实例
        Cat cat = (Cat)clazz.newInstance(); // 类型可转可不转 object运行类型就是Cat
        // (3) 通过 clazz 得到加载Cat类的 methodName 的方法对象
        //     在反射中,可以把方法看成对象
        Method method1 = clazz.getMethod(methodName);
        method1.invoke(cat); // 方法.invoke(对象)
        
    }

}

在这里插入图片描述

改需求

hi方法改为cry
不动源码,改配置文件即可!
在这里插入图片描述

反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息 (比如成员变量,构造器,成员方法等等), 并能操作对象的属性及方法。

加载完类之后,在堆中产生了一个Class类型的对象(堆中一个类只有一个Class对象)这个对象包含了类的完整结构信息。这个对象就像一面镜子,透过这个镜子看到类的结构,所以形象的称之为:反射

在这里插入图片描述

2. 反射机制

反射可以做的事

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时得到任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的成员变量和方法
  • 生成动态代理

反射相关主要的类

  • java.lang.Class代表一个类,Class对象表示某个类加载后在队中的对象(模板)
  • java.lang.reflect.Method 代表类的方法,Method对象表示某个类的方法
  • java.lang.reflect.Field: 代表类的成员变量,Field对象表示某个类的成员变量
  • java.lang.reflect.Constructor: 代表类的构造方法,Constructor对象表示某个类的构造器
package com.hspedu;

public class Cat {
    private String name = "招财猫";
    public int age = 10;

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

    public void hi(){
        System.out.println(name + " hi~");
    }
    public void cry(){
        System.out.println(name + " cry~");
    }
}
public class Reflect01 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("src/re.properties"));
        String classfullname = properties.get("classfullpath").toString();
        String methodName = properties.get("method").toString();

        Class<?> clazz = Class.forName(classfullname);
        Object obj = clazz.newInstance();

        // getField() 不能得到私有的属性
        Field ageField = clazz.getField("age");
        System.out.println(ageField.get(obj)); // 成员变量对象.get(对象)

        //()中可以指定构造器参数类型,返回无参构造器
        Constructor<?> constructor1 = clazz.getConstructor();
        System.out.println(constructor1);
        
        // String.class 就是 String类的class对象
        Constructor<?> constructor2 = clazz.getConstructor(String.class);
        System.out.println(constructor2);

    }
}

在这里插入图片描述

3. 反射优缺点

  • 可以动态创建和使用对象(框架底层的核心),使用灵活,没有反射机制,框架技术就失去地城支撑
  • 使用反射基本是解释执行,对执行速度有影响

反射调用优化

Method、Field、Constructor对象都有setAccessible()方法
setAccessible作用是启动和禁用访问安全检查的开关
参数为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false表示开启检查

4. Class类分析

在这里插入图片描述

Class也是类,因此也继承Object类

Class类对象不是new出来的,而是系统创建的 ClassLoader.loadClass

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

反射机制也是通过ClassLoader加载的,如果该类没有加载过,会loadClass一次,否则不会加载了,内存中只有一个此类的Class对象

对于某个类的Class类对象,在内存中只有一份,因此类只加载一次

每个类的实例都会记得自己是由哪个Class实例所生成

通过Class可以完整地得到一个类的完整结构,通过一系列的API

Class对象是放在堆的

在这里插入图片描述

5. Class类的相关方法

package com.hspedu.reflection;
import java.lang.reflect.Field;

public class Reflect02 {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        String classAllPath = "com.hspedu.reflection.Car";
        //<?>是通配符,得到car类对应的Class对象
        Class<?> clazz = Class.forName(classAllPath);
        // (Car)clazz是错误的

        // 2.输出clazz
        System.out.println(clazz); //clazz对象显示是哪个类的对象 class com.hspedu.reflection.Car
        System.out.println(clazz.getClass()); // class java.lang.Class

        // 3. 得到类的包名
        System.out.println(clazz.getPackage().getName()); // com.hspedu.reflection

        // 4. 得到全类名
        System.out.println(clazz.getName()); // com.hspedu.reflection.Car

        // 5. 通过clazz创建对象实例
        Object obj = clazz.newInstance(); //obj运行时就是car对象实例
        System.out.println(((Car)obj).brand); // byd

        //6. 通过反射获取属性 brand
        Field brand = clazz.getField("brand");
        System.out.println(brand.get(obj)); //byd

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

        // 8. 得到所有的属性字段
        Field[] fields = clazz.getFields();
        for(Field f : fields){
            System.out.println(f.getName()); // brand price color
        }

    }
}

class Car{
    public String brand = "byd";
    public int price;
    public String color;
}

6.获取Class对象的六中方式

在这里插入图片描述
在这里插入图片描述

        Cat cat = new Cat();
        // 运行时态 cat对象与Class对象时关联的
        Class<? extends Cat> clazz = cat.getClass();

在这里插入图片描述

7. 类加载

静态加载: 编译时加载相关的类,依赖性太强

在这里插入图片描述

动态加载: 运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性

在这里插入图片描述

类加载时机

  1. 当new对象时(静态加载)
  2. 当子类被加载,父类也加载(静态加载)
  3. 调用类中的静态成员时 (静态加载)
  4. 通过反射(动态加载)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

8.Field类

在这里插入图片描述

9. 反射爆破

暴破创建对象

public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        // 1. 通过public的无参构造器创建实例
        Class clazz = User.class;
        Object o = clazz.newInstance();
        System.out.println(o); //  User [age=10,name=superkcl]


        // 2. 通过public的有参构造器创建实例
        // constructor 对象就是 public User(String name)....
        Constructor constructor = clazz.getConstructor(String.class);
        Object obj = constructor.newInstance("超级氯化钾");
        System.out.println(obj); // User [age=10,name=超级氯化钾]

        //3. 通过private有参构造器创建实例
        //报错 Constructor constructor2 = clazz.getConstructor(int.class, String.class);
        Constructor privateConstructor = clazz.getDeclaredConstructor(int.class, String.class);
        //报错, Object obj2 = privateConstructor.newInstance(100, "张三丰");
        //暴破,使用反射可以访问private构造器
        // 在反射面前都是纸老虎
        privateConstructor.setAccessible(true);
        Object obj2 = privateConstructor.newInstance(100, "张三丰");
        System.out.println(obj2); // User [age=100,name=张三丰]
        
    }
}
class User{
    private int age = 10;
    private String name = "superkcl";
    public User(){

    }
    public User(String name){
        this.name = name;
    }
    private User(int age,String name){
        this.age = age;
        this.name = name;
    }
    public String toString(){
        return "User [age="+age + ",name="+name+"]";
    }
}


暴破属性

在这里插入图片描述

public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        // 1. 通过public的无参构造器创建实例
        Class clazz = Student.class;
        Object o = clazz.newInstance();
        System.out.println(o); //  Student [age=0,name=null]

        Field age = clazz.getField("age");
        age.set(o,88); // 通过反射操作属性
        System.out.println(o); // Student [age=88,name=null]

        // 通过反射操作private name属性
        Field name = clazz.getDeclaredField("name");
        // 报错 ! name.set(o,"纸老虎");
        name.setAccessible(true);
        name.set(o,"纸老虎");
        name.set(null,"纸老虎"); //static属性这样做也可以
        System.out.println(o); // Student [age=88,name=纸老虎]

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

    }
    public String toString(){
        return "Student [age=" + age + ",name=" + name + "]";
    }
}

暴破方法

在这里插入图片描述

public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        // 1. 通过public的无参构造器创建实例
        Class clazz = Boss.class;
        Object o = clazz.newInstance();
        System.out.println(o); //  Student [age=0,name=null]

        Method say = clazz.getDeclaredMethod("say",int.class,String.class,char.class);
        say.setAccessible(true);
        System.out.println(say.invoke(o,100,"张三",'男')); //100 张三 男
        System.out.println(say.invoke(null,100,"张三",'男')); //这样也可以静态方法



    }
}
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);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值