欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

反射--简单入门讲解

程序员文章站 2022-05-19 13:19:24
...

一、反射的概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

反射的前提就是获取到类的字节码对象,有以下三种方式(以Student类来举例):

        //第一种:通过类的路径来获取
        Class<?> c1 = Class.forName("cn.tedu.reflection.Student");
        //第二种:通过类名点class来获取
        Class<?> c2 = Student.class;
        //第三种:通过创建对象调用getClass方法来获取
        Class<?> c3 = new Student().getClass();

注意:一般用第一种,第一种需要类填入路径,它是一个字符串,可以传入也可写在配置文件中等多种方法。第二种需要导入类的包,依赖太强,不导包就抛编译错误。第三种对象都有了还要反射作什么.......。

二、反射的实际操作以及API的使用

常用API:

        Class<?> c1 = Class.forName("cn.tedu.reflection.Student");

        System.out.println(c1);//打印字节码对象
        System.out.println(c1.getName());//获取类的全路径名
        System.out.println(c1.getSimpleName());//获取类名
        System.out.println(c1.getPackage());//获取包对象
        System.out.println(c1.getPackage().getName());//获取包名

实战用反射获取类里的内容:

普通反射:

1.创建物料类Student

package cn.tedu.jobo;
public class Student {
    public String name;
    public int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    public void cool(){
        System.out.println("coolboy 阎静辉");
    }
    public void like(String name,int age){
        System.out.println("我老婆是:"+name+"她"+age+"岁了");
    }
}

2.创建反射测试类进行内容获取

 //构造方法
    @Test
    public void getConstrct(){
        Class<Student> c = Student.class;
        Constructor<?>[] constructors = c.getConstructors();
        for (Constructor<?>  con:
             constructors) {
            System.out.println(con.getName());
            Class<?>[] parameterTypes = con.getParameterTypes();
            System.out.println(Arrays.toString(parameterTypes));
        }
    }

    //普通方法
    @Test
    public void getMethod(){
        Class<Student> c = Student.class;
        Method[] methods = c.getMethods();
        for (Method m :
                methods) {

            System.out.println(m.getName());
            Class<?>[] parameterTypes = m.getParameterTypes();
            System.out.println(Arrays.toString(parameterTypes));

        }
    }

    //成员变量
    @Test
    public void getFields(){
        Class<Student> c = Student.class;
        Field[] f = c.getFields();
        for (Field i :
                f) {
            System.out.println(i.getName());
            System.out.println(i.getType().getName());
        }
    }

    //创建对象并调用方法
    @Test
    public void getnewInstance() throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class<Student> c = Student.class;
        //无参
        Student student = c.newInstance();
        System.out.println(student);

        //含参
        Constructor<Student> cs = c.getConstructor(String.class,int.class);
        Student zzf = cs.newInstance("张子枫", 19);
        System.out.println(zzf);
        System.out.println(zzf.age);
        System.out.println(zzf.name);
        zzf.cool();
        zzf.like("张子枫", 19);
    }
}

注意点:

       1. 单元测试

                        好处:只涉及一个方法,使用灵活,方便
                        格式:@Test+public+void+无参

        2.八大基本类型会直接显示,引用类型会显示全路径

        3.通过含参构造来new对象需要先获取到这个指定的构造函数,且传入的参数必须是字节码对象

        4.普通反射只能获取到public的方法和成员变量

暴力反射:

1.创建物料类Person

package cn.tedu.jobo;
public class Person {
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    private void play(){
        System.out.println("玩");
    }
    private void eat(String su,int n){
        System.out.println("我喜欢吃:"+su+"我要吃"+n+"个");
    }
}

2.创建暴力反射测试类进行内容获取

package cn.tedu.controller;
//暴力反射
import cn.tedu.jobo.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class TestPerson {
    //获取私有成员变量
    @Test
    public void getField() throws NoSuchFieldException, InstantiationException, IllegalAccessException {
        Class<?> p = Person.class;
        Field[] fs = p.getDeclaredFields();
        for (Field f :
                fs) {
            System.out.println(f.getName());
            System.out.println(f.getType().getName());
        }
        //设置成员变量
        Field name = p.getDeclaredField("name");
        name.setAccessible(true);
        Object o = p.newInstance();
        name.set(o, "阎静辉");
        System.out.println(name.get(o));
    }

    //暴力反射获取使用私有方法
    @Test
    public void getMethod() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class<Person> p = Person.class;
        Method[] declaredMethods = p.getDeclaredMethods();
        for (Method d :
                declaredMethods) {
            System.out.println(d.getName());
            Class<?>[] parameterTypes = d.getParameterTypes();
            System.out.println(Arrays.toString(parameterTypes));
        }

        Method eat = p.getDeclaredMethod("eat", String.class, int.class);
        eat.setAccessible(true);
        Person person = p.newInstance();
        eat.invoke(person,"米饭",1);
    }
}

注意点:

        1.Declared暴力反射时需要添加

        2.暴力反射时需要手动设置私有资源可见的权限setAccessible(true)

        3.set和invoke的区别使用

        4.思想的转变:平常是通过对象名点属性获取值,反射就是反过来通过属性名点对象名和参数传入,通过方法名点哪个对象来执行加传入参数。

另外两种修饰符暴力反射获取

上述只讲了对于public和private权限修饰符的两种方法:普通反射和暴力反射的使用

对于另外两种默认(default)和protected权限修饰符同样可以用暴力反射来获取,示例如下:

1.物料类hhh

package cn.tedu.jobo;
public class hhh {
    public String name;
    protected int age;
    double dog;
    private char pig;
}

2.创建暴力反射测试类进行测试

package cn.tedu.controller;
import cn.tedu.jobo.hhh;
import org.junit.Test;
import java.lang.reflect.Field;
public class Testhhh {
    @Test
    public void getfields(){
        Class<hhh> h = hhh.class;
        Field[] declaredFields = h.getDeclaredFields();
        for (Field f :
             declaredFields) {
            System.out.println(f);
        }
    }
}

3.结果如下

public java.lang.String cn.tedu.jobo.hhh.name
protected int cn.tedu.jobo.hhh.age
double cn.tedu.jobo.hhh.dog
private char cn.tedu.jobo.hhh.pig

兄弟盟,到这里就结束了,有不对的地方和需要补充的评论或者私信留言!

fighting!

fighting!!

fighting!!!