Java反射详细总结

什么是反射?

反射,指的是加载类的字节码到内存,并以编程的方法解刨出类中的各个成分(成员变量、方法、构造器等)。

反射获取的是类的信息,那么反射的第一步首先获取到类才行。由于Java的设计原则是万物皆对象,获取到的类其实也是以对象的形式体现的,叫字节码对象 ,用Class类来表示。获取到字节码对象之后,再通过字节码对象就可以获取到类的组成成分了,这些组成成分其实也是对象,其中每一个成员变量用Field类的对象来表示每一个成员方法用Method类的对象来表示每一个构造器用Constructor类的对象来表示

获取类的字节码

比如有一个Student类,获取Student类的字节码代码有三种写法。不管用哪一种方式,获取到的字节码对象其实是同一个。

java 复制代码
public class Test1Class{
    public static void main(String[] args){
        Class c1 = Student.class;
        System.out.println(c1.getName()); //获取全类名
        System.out.println(c1.getSimpleName()); //获取简单类名
        
        Class c2 = Class.forName("com.reflect.Student");
        System.out.println(c1 == c2); //true
        
        Student s = new Student();
        Class c3 = s.getClass();
        System.out.println(c2 == c3); //true
    }
}

获取类的构造器

获取构造器,需要用到Class类提供的几个方法,如下图所示:

get :获取
Declared : 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Constructor: 构造方法的意思

后缀s: 表示可以获取多个,没有后缀s只能获取一个

假设现在有一个Cat类,里面有几个构造方法,代码如下

java 复制代码
public class Cat{
    private String name;
    private int age;
    
    public Cat(){
        
    }
    
    private Cat(String name, int age){
        
    }
}

写一个测试方法,来测试获取类中所有的构造器

java 复制代码
public class Test2Constructor(){
    @Test
    public void testGetConstructors(){
        //1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        
        //2、获取类的全部构造器
        Constructor[] constructors = c.getDeclaredConstructors();
        //3、遍历数组中的每一个构造器对象。
        for(Constructor constructor: constructors){
            System.out.println(constructor.getName()+"---> 参数个数:"+constructor.getParameterCount());
        }
    }
}

输出

java 复制代码
reflect.Cat---> 参数个数:0
reflect.Cat---> 参数个数:2

接下来,我们演示单个构造器试一试

java 复制代码
public class Test2Constructor(){
    @Test
    public void testGetConstructor(){
        //1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        
        //2、获取类public修饰的空参数构造器
        Constructor constructor1 = c.getConstructor();
        System.out.println(constructor1.getName()+"---> 参数个数:"+constructor1.getParameterCount());
        
        //3、获取private修饰的有两个参数的构造器,第一个参数String类型,第二个参数int类型
        Constructor constructor2 = 
            c.getDeclaredConstructor(String.class,int.class);
        
        System.out.println(constructor2.getName()+"---> 参数个数:"+constructor2.getParameterCount());

    }
}

输出

java 复制代码
reflect.Cat---> 参数个数:0
reflect.Cat---> 参数个数:2

获取成员变量

在Class类中提供了获取成员变量的方法,如下图所示:

get :获取
Declared : 有这个单词表示可以获取任意一个,没有这个单词表示只能获取一个public修饰的
Field : 成员变量的意思
后缀s: 表示可以获取多个,没有后缀s只能获取一个

测试

java 复制代码
public static void main(String[] args) throws Exception {
        //1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        //获取类的全部成员变量
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName() + "--->" + field.getType());
        }
        System.out.println("---------------------------");
        //定位某一个成员变量
        Field name = c.getDeclaredField("name");
        System.out.println(name.getName() + "--->" + name.getType());
        System.out.println("---------------------------");
        //给name设置值
        Cat cat = new Cat();
        name.setAccessible(true);//private修饰的需要暴力破解
        name.set(cat,"张三");
        System.out.println(cat);
        System.out.println("---------------------------");
        //取值
        Object o = name.get(cat);
        System.out.println("获取的值为"+o);
    }

输出

java 复制代码
name--->class java.lang.String
age--->int
---------------------------
name--->class java.lang.String
---------------------------
Cat{name='张三'}
---------------------------
获取的值为张三

Process finished with exit code 0

获取成员方法

在Java中反射包中,每一个成员方法用Method对象来表示,通过Class类提供的方法可以获取类中的成员方法对象。如下图所示

假设有一个Cat类,在Cat类中红有若干个成员方法

java 复制代码
public class Cat{
    private String name;
    private int age;
    
    public Cat(){
        System.out.println("空参数构造方法执行了");
    }
    
    private Cat(String name, int age){
        System.out.println("有参数构造方法执行了");
        this.name=name;
        this.age=age;
    }
    
    private void run(){
        System.out.println("(>^ω^<)喵跑得贼快~~");
    }
    
    public void eat(){
        System.out.println("(>^ω^<)喵爱吃猫粮~");
    }
    
    private String eat(String name){
        return "(>^ω^<)喵爱吃:"+name;
    }
    
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    public void setAge(int age){
        this.age=age;
    }
     public int getAge(){
        return age;
    }
}

通过反射获取Cat类中所有的成员方法,每一个成员方法都是一个Method对象

java 复制代码
public static void main(String[] args) throws Exception {
        //1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        //2、获取类中的全部成员方法
        Method[] methods = c.getDeclaredMethods();

        //3、遍历这个数组中的每一个方法对象
        for(Method method : methods){
            System.out.println(method.getName()+"-->"+method.getParameterCount()+"-->"+method.getReturnType());
        }
    }

输出

java 复制代码
run-->0-->void
getName-->0-->class java.lang.String
setName-->1-->void
eat-->1-->class java.lang.String
eat-->0-->void
setAge-->1-->void
getAge-->0-->int

下面我们演示一下,把run()方法和eat(String name)方法执行起来

java 复制代码
public static void main(String[] args) throws Exception {
        //1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        //2、获取private修饰的run方法,得到Method对象
        Method run = c.getDeclaredMethod("run");
        //执行run方法,在执行前需要取消权限检查
        Cat cat = new Cat();
        run.setAccessible(true);
        Object rs1 = run.invoke(cat);
        System.out.println("方法返回值-->"+rs1);

        //3、获取private 修饰的eat(String name)方法,得到Method对象
        Method eat = c.getDeclaredMethod("eat",String.class);
        eat.setAccessible(true);
        Object rs2 = eat.invoke(cat,"鱼儿...");
        System.out.println("方法返回值-->"+rs2);
    }

输出

java 复制代码
空参数构造方法执行了
(>^ω^<)喵跑得贼快~~
方法返回值-->null
方法返回值-->(>^ω^<)喵爱吃:鱼儿...

反射的应用

需求是让我们写一个框架,能够将任意一个对象的属性名和属性值写到文件中去。不管这个对象有多少个属性,也不管这个对象的属性名是否相同。

1.先写好两个类,一个Student类和Teacher类

2.写一个ObjectFrame类代表框本架

在ObjectFrame类中定义一个saveObject(Object obj)方法,用于将任意对象存到文件中去

参数:Object obj: 就表示要存入文件中的对象

3.编写方法内部的代码,往文件中存储对象的属性名和属性值

1)参数obj对象中有哪些属性,属性名是什么实现值是什么,中有对象自己最清楚。

2)接着就通过反射获取类的成员变量信息了(变量名、变量值)

3)把变量名和变量值写到文件中去

写一个ObjectFrame表示自己设计的框架,代码如下所示

java 复制代码
public class ObjectFrame{
    public static void saveObject(Object obj) throws Exception{
        PrintStream ps = 
            new PrintStream(new FileOutputStream("模块名\\src\\data.txt",true));
        //1)参数obj对象中有哪些属性,属性名是什么实现值是什么,中有对象自己最清楚。
		//2)接着就通过反射获取类的成员变量信息了(变量名、变量值)
        Class c = obj.getClass(); //获取字节码
        ps.println("---------"+class.getSimpleName()+"---------");
        
        Field[] fields = c.getDeclaredFields(); //获取所有成员变量
		//3)把变量名和变量值写到文件中去
        for(Field field : fields){
            String name = field.getName();
            Object value = field.get(obj)+"";
            ps.println(name);
        }
        ps.close();
    }
}

准备好Student类和Teacher类

java 复制代码
public class Student{
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;
}
java 复制代码
public class Teacher{
    private String name;
    private double salary;
}

创建一个测试类,在测试中类创建一个Student对象,创建一个Teacher对象,用ObjectFrame的方法把这两个对象所有的属性名和属性值写到文件中去。

java 复制代码
public class Test{
    @Test
    public void save() throws Exception{
        Student s1 = new Student("黑马吴彦祖",45, '男', 185.3, "篮球,冰球,阅读");
        Teacher s2 = new Teacher("播妞",999.9);
        
        ObjectFrame.save(s1);
        ObjectFrame.save(s2);
    }
}
相关推荐
0白露29 分钟前
Apifox Helper 与 Swagger3 区别
开发语言
Tanecious.1 小时前
机器视觉--python基础语法
开发语言·python
叠叠乐1 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
战族狼魂2 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
Tttian6223 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
xyliiiiiL3 小时前
ZGC初步了解
java·jvm·算法
杉之3 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
hycccccch4 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
独好紫罗兰4 小时前
洛谷题单2-P5713 【深基3.例5】洛谷团队系统-python-流程图重构
开发语言·python·算法
天天向上杰5 小时前
面基JavaEE银行金融业务逻辑层处理金融数据类型BigDecimal
java·bigdecimal