反射

反射

反射的概念及演示:

  1. 反射:又被称为“反向加载”。(之前创建某个类的对象时:Student stu = new Student());//正向加载—缺点:使当前类与Student类产生了依赖。
  2. 反射不直接使用“类名”,可以通过一个字符串描述的一个类名(可以将其记录在配置文件中),去加载这个类,并创建它的对象,进而去调用它的一些属性和方法。
  3. 反射的好处:解开类和类之间的“耦合”
代码图解:

在这里插入图片描述

运行时class文件的加载:

在这里插入图片描述

获取Class对象的三种方式:

  1. Object类的getClass()方法:此方法会被任何类继承。

    Student student = new Student();//创建Class对象
    Class c1 = student.getClass();//获取

  2. 任何的数据类型(包括基本数据类型)都有一个静态的成员属性:Class
    Class c2 = student.class;//注意:必须通过“类名”调用,不能通过“对象”调用。

  3. 调用Class类的静态方法:forName(“全类名”);[常用]
    Class c3 = Class.forName(“day26作业代码.test01.Student”) ;
    注意:以上三种方式都是:如果有Class对象,就直接获取。如果没有Class对象,会创建Class对象,然后再获取。

代码演示:
public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取Class对象的第一种方式:
        Student student = new Student();
        Class c1 = student.getClass();
        System.out.println("第一种方式:"+c1.getMethods());
        //第二种方式:
        Class c2 = Student.class;
        System.out.println("第二种方式:"+c2.getMethods());
        //第三种方式:
        Class c3 = Class.forName("day26作业代码.test02.Student");
        System.out.println("第三种方式:"+c3.getMethods());

    }
}

获取构造方法并创建对象-Constructor

作用:可以通过获取“Constructor对象”,来调用某个构造方法,去创建它的对象。

  1. 批量获取:
    1. public Constructor[] getConstructors();//获取所有的“公有构造方法”。
    2. public Constructor[] getDeclaredConstructors();//获取所有的构造方法,包括:公有,受保护,默认,私有
  2. 获取单个:
    1. public Constructor getConstructor(Class … params);//获取“某个”,“公有”的构造方法。
    2. public Constructor getDeclaredConstructor(Class … params);//获取某个构造方法,可以是:共有,受保护,默认,私有
  3. 调用构造方法:Constructor类的newInstance(Object … params)
    注意:如果没有访问权限,需要设置“暴力访问”:Constructor了类的setAccessible(true);
代码演示:

测试类:

public class Demo04 {
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.itheima.demo04_获取构造方法并创建对象_Constructor.Student");

        //2.获取构造方法
        System.out.println("【获取所有[公有]构造方法】");
        Constructor[] cs1 = stuClass.getConstructors();
        for (Constructor c : cs1) {
            System.out.println(c);
        }
        System.out.println("【获取所有构造方法】");
        Constructor[] cs2 = stuClass.getDeclaredConstructors();
        for (Constructor c : cs2) {
            System.out.println(c);
        }

        System.out.println("【获取公有、无参的构造方法】");
        Constructor c1 = stuClass.getConstructor();
        System.out.println(c1);
        Object o1 = c1.newInstance();//相当于:Student stu = new Student();

        System.out.println("【获取公有、String、double参数的构造方法】");
        Constructor c2 = stuClass.getConstructor(String.class, double.class);
        System.out.println(c2);
        Object o2 = c2.newInstance("呵呵", 3.14);


        System.out.println("【获取私有的、String、int参数的构造方法】");
        Constructor c3 = stuClass.getDeclaredConstructor(String.class, int.class);
        System.out.println(c3);
        c3.setAccessible(true);//暴力访问——绕过权限检查
        Object o3 = c3.newInstance("哈哈", 120);

    }
}

Student类

public class Student {

    public Student(String s, double d) {
        System.out.println("调用了公有、String、double参数的构造方法:s = " + s + " d = " + d);
    }
    public Student(){
        System.out.println("调用了公有无参的构造方法...");
    }

    protected Student(int a) {
        System.out.println("调用了受保护的构造方法...");
    }

    Student(String s) {
        System.out.println("调用了默认的构造方法...");
    }

    private Student(String s, int a) {
        System.out.println("调用了私有的构造方法:s = " + s + " a = " + a);
    }
}
代码图解

在这里插入图片描述

获取成员属性并赋值和取值-Field

作用:获取一个类的“属性”,并且在创建此类对象后,为这个属性赋值,取值。

  1. 批量获取:
    1. public Field[] getFields();//获取所有的“公有”成员属性。
    2. public Field[] getDeclaredFields();获取所有的成员属性,包括:公有,受保护,默认,私有
  2. 获取单个:
    1. public Field getField(String fieldName);//获取“某个”,“公有”的成员属性
    2. public Field getDeclaredField(String fieldName);//获取某个成员属性,可以是:公有,受保护,默认,私有
  3. 为某个对象的属性设置值:
    Field类的set(Object targetObj,Object value)
  4. 获取某个对象的属性值:Field类的get(Object targetObj)
  5. 如果没有访问权限,需要设置“暴力访问”:Field类的setAccessible(true)
代码演示:

测试类

public class Demo05 {
    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.itheima.demo05_获取成员属性并赋值和取值_Field.Student");

        //2.获取成员属性
        System.out.println("【获取公有的name属性】");
        Field nameField = stuClass.getField("name");
        System.out.println(nameField);

        System.out.println("【获取私有的sex属性】");
        Field sexField = stuClass.getDeclaredField("sex");
        System.out.println(sexField);

        //要使用这个属性,必须要先创建对象
        Object o = stuClass.getConstructor().newInstance();

        System.out.println(o);

        //为o对象的name属性赋值为:成龙
        nameField.set(o, "成龙");
        System.out.println(o);

        //为o对象的sex属性赋值为:男
        sexField.setAccessible(true);
        sexField.set(o, '男');
        System.out.println(o);

        System.out.println("获取某个属性的值:" + nameField.get(o) + " , " + sexField.get(o));


    }
}

Student类

package com.itheima.demo05_获取成员属性并赋值和取值_Field;

public class Student {
    //编译器会自动添加一个:公有、无参、什么都不做的构造方法

    public String name;
    protected int age;
    double height;
    private char sex;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", sex=" + sex +
                '}';
    }
}
代码图解

在这里插入图片描述

获取成员方法并调用method

  1. 批量获取:
    1. public Method[] getMethods();//虎丘所有的“公有”成员方法。
    2. public Method[] getDeclaredMethods();//获取所有的成员方法,包括:公有,受保护,默认,私有
  2. 获取单个:
    1. public Method getMethod(String methodName,Class…params);//获取某个公有的成员方法
    2. public Method getDeclaredMethod(String methodName,Class … params);//获取某个成员方法,可以是:公有,受保护,默认,私有。
  3. 调用方法:Method类的invoke(ObjecttargetObj,Class … params)
  4. 如果没有访问权限,需要设置“暴力访问”:Method的setAccessible(true)
代码演示:
package com.itheima.demo06_获取成员方法并调用_method;

import java.lang.reflect.Method;

public class Demo06 {
    public static void main(String[] args) throws Exception {
        //1.获取Class
        Class stuClass = Class.forName("com.itheima.demo06_获取成员方法并调用_method.Student");

        System.out.println("【获取公有、无参、无返回值的show1】");
        Method m1 = stuClass.getMethod("show1");
        System.out.println(m1);

        System.out.println("【获取私有、有参、有返回值的show2】");
        Method m2 = stuClass.getDeclaredMethod("show2", String.class, double.class);
        System.out.println(m2);

        //要调用方法,必须创建对象
        Object o = stuClass.getConstructor().newInstance();

        //调用m1方法
        m1.invoke(o);

        //调用m2方法
        m2.setAccessible(true);
        Object result = m2.invoke(o, "成龙", 1.80);
        System.out.println("返回值:" + result);


    }
}

package day26练习代码;

public class Student {
    private String name;
    private int age;
    public String sex;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    public static void method1(){
        System.out.println("公共,无参,无返回值方法");
    }
    public static String method2(){
        System.out.println("公共,无参,有返回值方法");
        return "返回值";
    }
    public static String method3(String name,int age){
        System.out.println("公共,有参,有返回值方法:"+name+age);
        return "有返回值";
    }
    private int method04(String name,int age){
        System.out.println("公共,有参,有返回值方法:"+name+age);
        return 0;
    }

    //构造方法:
    public Student() {
        System.out.println("公有,无参构造方法");
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("公有,全参构造方法");
    }
    private Student(String name){
        System.out.println("私有,name属性构造方法");
    }

    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;
    }
}
代码图解:

在这里插入图片描述

反射练习(面试题)

现有一个集合ArrayList,要求程序要向这个集合对象中添加一个String对象

//泛型——只存在于编译期,编译后没有泛型——泛型擦除
//比如我们自定义MyArrayList类:
class MyArrayList<E>{//编译后,生成class文件,没有<E>泛型了
    public void add(E e) {//编译后,生成class文件,变为:add(Object o)

    }
}
public class Demo07 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1.现有一个集合
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(20);

        //2.要求程序向这个集合中添加一个String对象
//        list.add("30");//编译错误

        //通过"反射"绕过泛型检查——一个类的泛型,只存在于"编译期",编译后就没有泛型信息了,全部变为Object——泛型擦除

        //1.获取AraryList的Class对象
        Class listClass = list.getClass();
        //2.通过反射的方式获取add()方法的Method对象
        Method addMethod = listClass.getMethod("add", Object.class);
        //3.调用add
        addMethod.invoke(list, "呵呵");

        //遍历
        for (Object o : list) {
            System.out.println(o + " 类型:" + o.getClass().getName());
        }
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值