Java高级API-Day06-反射

一、定义

反射是指在程序运行期间,能够观察和修改类或者类的对象的属性和行为的特性
项目开发中常见的使用反射的场景

使用JDBC连接数据库
Servlet在Web容器中的加载和运行

二、作用

Java反射机制提供了以下的功能

1、在运行时获取类的修饰符,包名,类名,实现的接口,继承的父类
2、在运行时获取类的所有属性名,修饰符,属性类型
3、在运行时获取所有方法,方法的返回值类型,方法名,方法参数数量,方法参数类型
4、在运行时调用加载类的方法

三、常用类

Java反射API常用的类
java.lang.Class
java.lang.reflect.Method
java.lang.Constructor
java.lang.Field
java.lang.Modifier

四、获取class对象的方式

public class TestClass {
    
    
    public static void main(String[] args) throws Exception{
    
    
        //第一种获取class对象的方式(常用方法)
        //Class.forName(),括号内是字符串,表示想要获取类的全类名
        //比如我想要获取当前类,获取的是当前类的class类型
        Class<?> tClass = Class.forName("cn.kgc.kb11.TestClass");
        //第二种获取class对象的方式
        //用对象获取类型
        //建一个对象,用对象.getClass()来获取
        TestClass tc=new TestClass();
        Class<? extends TestClass> tcClass = tc.getClass();
        //第三种获取class对象的方式
        //直接使用类型来获取class对象
        Class<TestClass> typeClass = TestClass.class;
    }
}

五、获取class对象的构造方法

public class Student {
    
    
    public int id;
    String name;
    private String gender;

    private Student() {
    
    
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    private String getGender() {
    
    
        return gender;
    }

    private void setGender(String gender) {
    
    
        this.gender = gender;
    }
}

public class TestStudent {
    
    
    public static void main(String[] args) throws Exception{
    
    
       //使用反射获取某个类的属性和方法以及构造方法
        //1、获取Class对象,直接使用类型来获取
        Class<Student> c = Student.class;
        //获取包名
        System.out.println(c.getPackage().getName());
        //获取全类名
        System.out.println(c.getName());
        //获取构造方法
        //当构造方法为公共的时候,可以用c.getConstructor()来获取
        //当构造方法为私有的时候,用c.getDeclaredConstructor()来获取
        Constructor<Student> cons = c.getDeclaredConstructor();
        //虽然获取到构造方法了,但没有权限,还是私有的
        // 这时候需要用setAccessible(true)来强行破解
        cons.setAccessible(true);
        //再用newInstance方法就可以获取到Student类型的对象了
        Student s = cons.newInstance();
        //打印一下,结果就是Student类型的地址
        System.out.println(s);
    }
}

注:一些公司为了安全,采用枚举的方法,枚举可以防反射

六、获取属性以及给属性赋值

public class Student {
    
    
    public int id;
    String name;
    private String gender;
    @Override
    public String toString() {
    
    
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
    private Student() {
    
    
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    private String getGender() {
    
    
        return gender;
    }

    private void setGender(String gender) {
    
    
        this.gender = gender;
    }
}

public class TestStudent {
    
    
    public static Student getStudent()throws Exception{
    
    
        //把获取类的代码放进一个方法里,便于后续操作
        Class<Student> c = Student.class;
        Constructor<Student> cons = c.getDeclaredConstructor();
        cons.setAccessible(true);
        Student s = cons.newInstance();
        return s;
    }
    public static void main(String[] args) throws Exception{
    
    
        //1.创建对象,调用之前写好的方法
        Student s = getStudent();
        //获取对象
        Class<? extends Student> aClass = s.getClass();
        //获取属性
        Field id = aClass.getField("id");
        //给属性赋值,用set(赋值到哪个对象里,赋值的值是多少)来进行赋值
        id.set(s,3);
        System.out.println(s);
        //但无法给私有属性赋值,编译不会出错,但运行是会出错
        //要想给私有属性赋值,用如下的方法
        Field df = aClass.getDeclaredField("gender");
        df.setAccessible(true);
        df.set(s,"男");
        System.out.println(s);
        //第二种给属性赋值的方法,获取属性数组
        Field[] dfs = aClass.getDeclaredFields();
        //然后遍历数组来给每个属性进行赋值
        for (int i = 0; i < dfs.length; i++) {
    
    
            //前提先破解
            dfs[i].setAccessible(true);
            if (null!=dfs[i].getName()&&"id".equals(dfs[i].getName())) {
    
    
                dfs[i].set(s,6);
            }else if (null!=dfs[i].getName()&&"name".equals(dfs[i].getName())){
    
    
                dfs[i].set(s,"小宇");
            }else if (null!=dfs[i].getName()&&"gender".equals(dfs[i].getName())){
    
    
                dfs[i].set(s,"女");
            }
        }
        System.out.println(s);
    }
}

七、获取方法

public class Student extends Parent{
    
    
    public int id;
    String name;
    private String gender;
    private String show(int cnt,String good){
    
    
        return "我叫"+name+",我的学号是:"+id+",我的性别是:"+gender
                +",老师叫我拿"+cnt+"杯"+good+"来给大家";
    }
    @Override
    public String toString() {
    
    
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                '}';
    }
    private Student() {
    
    
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    private String getGender() {
    
    
        return gender;
    }

    private void setGender(String gender) {
    
    
        this.gender = gender;
    }

}

父类Parent
放在cn.kgc.kb11包中

public class Parent {
    
    
    private double money;
}

测试类
放在cn.kgc.kb11.ref包中

public class TestStudent {
    
    
    public static Student getStudent()throws Exception{
    
    
        //把获取类的代码放进一个方法里,便于后续操作
        Class<Student> c = Student.class;
        Constructor<Student> cons = c.getDeclaredConstructor();
        cons.setAccessible(true);
        Student s = cons.newInstance();
        return s;
    }
public static void main(String[] args) throws Exception{
    
    
        Student s = getStudent();
        Class<? extends Student> aClass = s.getClass();
        //获取方法(私有方法的获取就不用多说了,参照私有属性的获取)
        //getDeclaredMethod(方法名,参数类型的反射方式)
        Method gender = aClass.getDeclaredMethod("setGender", String.class);
        gender.setAccessible(true);
        //方法用invoke进行传参
        gender.invoke(s,"man");
        //两个公共方法就正常传参就行
        s.setId(1);
        s.setName("123");
        System.out.println(s);
        //多参数类型私有方法的传参
        Method show = aClass.getDeclaredMethod("show", int.class, String.class);
        show.setAccessible(true);
        Object o = show.invoke(s, 22, "123");
        System.out.println(o);
        //获取父类的类型名
        Type dad = aClass.getGenericSuperclass();
        System.out.println(dad.getTypeName());
        //获取父类的类型
        Class<?> superclass = aClass.getSuperclass();
        System.out.println(superclass);
    }
}

Student{
    
    id=1, name='123', gender='man'}
cn.kgc.kb11.Parent
class cn.kgc.kb11.Parent

八、总结

1、Java反射机制是Java语言被视为准动态语言的关键特性
2、Java反射机制有优点也有缺点
3、一般用于构建框架

扫描二维码关注公众号,回复: 12713607 查看本文章

猜你喜欢

转载自blog.csdn.net/weixin_43901457/article/details/113927939