Java基础(十九)反射(很重要!)

本文深入讲解Java反射机制,包括Class、Constructor、Field和Method类的使用,以及如何通过反射创建实例对象、调用方法和修改属性。同时探讨了反射的优缺点,并提供了实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反射

1.概念

反射—解析类,通过字节码对象来获取实例对象的过程(运行时期)
在这里插入图片描述

在这里插入图片描述

Class类—代表类的类—创建的对象代表具体类(字节码文件对应类—字节码文件—字节码对象)
Field类—代表属性的类—创建对象就是具体属性
Method类—代表方法的类–创建对象就是具体方法
Constructor类—代表构造方法的类–创建对象就是具体的构造方法

2.获取字节码对象的方式

1)通过类型.class返回对应的字节码对象

//String类的字节码对象
Class<String> clz=String.class;//class java.lang.String
//接口的字节码对象
Class<List> clz1=List.class;//interface java.util.List
//基本类型的字节码对象
Class clz2=int.class;//int
System.out.println(clz);

2)通过对象调用gatClass方法返回对应的字节码对象

Class<String> clz=(Class<String>)"abc".getClass();
System.out.println(clz);//class java.lang.String

3)通过Class.forName(“字符串”)来获取对应的字节码对象(保证字符串内容没有问题)

Class<List> clz=(Class<List>)Class.forName("java.util.List");
System.out.println(clz);//interface java.util.List
3.获取实例对象的方式

1)通过字节码对象调用newInstance()执行无参构造

//执行无参构造来创建实例对象
//String str=clz.newInstance();

2)构造方法类的对象调用newInstance有参方法执行有参构造并且赋值

//先获取有参构造---(String original)
//参数类型需要以字节码对象的形式来传入才能找到对应的构造方法
Constructor c=clz.getConstructor(String.class);
//执行有参构造并且赋值返回实例对象
String str= (String) c.newInstance("abc");
//
String str1=new String("abc");

通过反射来获取integer类的实力对象

//获取字节码对象
Class<Integer> clz1=Integer.class;
//获取有参构造---(int)
clz1.getConstructor(int.class);
Constructor<Integer> c=clz1.getConstructor(int.class);
//执行有参构造并且给构造来赋值返回实例对象
Integer in=c.newInstance("123");
System.out.println(in);
package cn.tedu.reflect;

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

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

        //
        Class<String> clz = String.class;

        //获取构造方法
        //获取指定构造方法
        Constructor<String> c = clz.getDeclaredConstructor
                (char[].class, boolean.class);

        //暴力破解
        c.setAccessible(true);

        //执行构造方法并且给构造方法赋值返回实例对象
        String str = c.newInstance(new char[]{'1', '2'}, true);

        System.out.println(str);
    }
}

属性:

package cn.tedu.reflect;

import java.lang.reflect.Field;

public class ClassDemo4 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        Class<String> clz=String.class;

        //获取指定属性---hash
        Field field= clz.getDeclaredField("hash");

        //提供实例对象
        String str="abc";
        System.out.println(str.hashCode());

        //改变属性值
        //暴力破解---进行正常赋值
        field.setAccessible(true);
        //选择str对象的hashcode属性改值为123
        field.set(str,123);
        //获取属性值
        System.out.println(field.get(str));
        System.out.println(str.hashCode());//96354    123
    }
}

方法:

package cn.tedu.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ClassDemo5 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<String> clz=String.class;

        //获取指定方法
        Method m=clz.getDeclaredMethod("charAt", int.class);

        //提供实例对象
        String str="sjgcdsvc";

        //基于对于的实例对象执行方法
        //str.charAt(4)
        System.out.println(m.invoke(str,4));//d
    }
}

反射缺点:1.打破封装原则 2.跳过泛型的类型检测

4.练习:实现clone方法
package cn.tedu.List;

import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

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

        //创建对象
        Person p=new Person();
        p.setName("豆豆");
        p.setAge(14);
        //调用方法返回克隆对象
        Person p1=(Person) clone(p);
        System.out.println(p1.getName()+","+p1.getAge());
    }

    //实现clone方法
    public static Object clone(Object obj) throws IllegalAccessException, InstantiationException, InvocationTargetException {
        //1.获取原对象的字节码对象
        Class<Object> clz = (Class<Object>) obj.getClass();
        //2.获取实例对象(新对象)
        //一定能获取一个构造方法
        Constructor c = clz.getDeclaredConstructors()[0];
        //获取构造方法上所有的参数类型
        Class[] cs = c.getParameterTypes();
        //提供数组用于存储有参构造参数初始化值
        Object[] os = new Object[cs.length];

        //遍历数组
        for (int i = 0; i < cs.length; i++) {
            //判断是否是基本数据类型
            if (cs[i].isPrimitive()) {
                //基本类型
                if (cs[i] == byte.class || cs[i] == short.class || cs[i] == int.class){
                    os[i] = 0;
            } else if (cs[i] == char.class) {
                os[i] = '\u0000';
            } else if (cs[i] == long.class) {
                os[i] = 0L;
            } else if (cs[i] == float.class) {
                os[i] = 0.0F;
            } else if (cs[i] == double.class) {
                os[i] = 0.0;
            } else {
                os[i] = false;
            }
        }else{//引用类型
            //引用类型的参数初始化值都是null
            os[i] = null;
        }
    }

    //执行有参构造并且赋值返回实例对象
    Object o=c.newInstance(os);
        //执行无参构造来创建实例对象
        //Object o=clz.newInstance();
        //3.获取原对象所有的指定属性
        Field[] fs=clz.getDeclaredFields();
        //4.把原对象的属性值赋值给新对象
        for (Field f:fs){
            //暴力破解
            f.setAccessible(true);
            //先获取原对象的属性值
            Object value=f.get(obj);
            //给新对象属性进行赋值
            f.set(o,value);
        }
        return o;
    }
}
class Person{
    private String name;
    private int 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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

张艳霞zhangyx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值