一天一个java知识点----反射

反射

认识反射

可以允许程序在运行过程中动态地获取类的信息(成员变量、方法、构造器等),还可以创建对象。

反射的步骤:

  1. 反射第一步:加载类,获取类的字节码:Class对象
  1. 获取类的构造器:Constructor对象
  1. 获取类的成员变量:Field对象
  1. 获取类的成员方法:Method对象

获取类

获取类的三种方式:

  • Class c1 = 类名.class
  • 调用Class提供方法:public static Class forName(String package);
  • Class.forName("全类名");
  • Object提供的方法: public Class getClass();  Class c3 = 对象.getClass();
  • c3.getName()获取全类名
  • c3.getSimpleName()获取类简名

Java
Cat
public class Cat extends CatParent{

    private String name;
    private Integer age;
    public String hobby;

    public Cat(){
        System.out.println("++++公有构造+++++");
    }

    public Cat(Integer age){
        System.out.println("++++公有构造+++++"+age);
    }

    public Cat(String name,Integer age){
        System.out.println("++++公有构造+++++"+name+"+"+age);
    }

    private Cat(String name){
        System.out.println("++++私有构造+++++"+name);
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public String dance1(String a,Integer b){
        return "跳舞1";
    }

    public String dance2(String a,int b){
        return "跳舞2";
    }

    private String sing(){
        return "唱歌";
    }

}

Java
CatParent
public class CatParent {

    private String a;
    protected String b;
    public String c;

    public void a1(){
        System.out.println("+++++++a1+++++++");
    }

    private void a2(){
        System.out.println("+++++++a2+++++++");
    }

    protected void a3(){
        System.out.println("+++++++a3+++++++");
    }

}

Java
System.out.println("----------------获取class对象---------------------");

System.out.println("----------------通过类名获取---------------------");
Class catClass1 = Cat.class;
System.out.println(catClass1);

System.out.println("----------------通过class.forname方法获取---------------------");
//不存在的类会抛出异常
//Class noExistClass2 = Class.forName("com.example._01reflect.Cat2");
Class catClass2 = Class.forName("com.example._01reflect.Cat");
System.out.println(catClass2);

System.out.println("----------------通过对象的getClass方法获取获取---------------------");
Class CatClass3 = new Cat().getClass();
System.out.println(CatClass3);
//同一个类的class对象全局只有一个,返回true
System.out.println(catClass1 == catClass2);

面试题

为什么返回的是true?

Java
//同一个类的class对象全局只有一个,返回true
System.out.println(catClass1 == catClass2);

答:同一个类加载器下,每个类的Class对象在JVM中是唯一的单例。无论通过类名.classClass.forName()还是对象getClass()获取的Class对象,只要属于同一个类,它们都指向JVM中同一块内存地址的Class实例,因此catClass1 == catClass2比较的是同一引用,结果为true这体现了Java类加载机制的一致性。

获取类中的成分并对其进行操作

获取构造器的方法。

获取类构造器的作用:依然是初始化对象返回(就是创建对象)

Java
System.out.println("----------------获取构造器---------------------");
System.out.println("----------------获取所有public的构造器---------------------");
Constructor[] constructors1 = catClass1.getConstructors();
for (Constructor constructor : constructors1) {
    System.out.println(constructor);
}

System.out.println("----------------获取所有构造器---------------------");
Constructor[] constructors2 = catClass1.getDeclaredConstructors();
for (Constructor constructor : constructors2) {
    System.out.println(constructor);
}

System.out.println("----------------获取特定参数的构造器(只能获取public)---------------------");
Constructor constructor1 = catClass1.getConstructor(Integer.class);
System.out.println(constructor1);
Constructor constructor2 = catClass1.getConstructor(String.class, Integer.class);
System.out.println(constructor2);
//不存在会抛异常
//Constructor notExistConstructor = catClass1.getConstructor(Long.class);
//获取私有也会抛异常
//Constructor privateConstructors = catClass1.getConstructor(String.class);

System.out.println("----------------获取特定参数的构造器---------------------");
Constructor privateConstructor = catClass1.getDeclaredConstructor(String.class);
System.out.println(privateConstructor);

System.out.println("----------------创建对象---------------------");
//要严格根据构造方法的参数类型和顺序进行传参
// Cat cat = (Cat) constructor1.newInstance("小花");
Cat cat1 = (Cat) constructor1.newInstance(18);
// Cat cat = (Cat) constructor2.newInstance(18,"小花");
Cat cat2 = (Cat) constructor2.newInstance("小花", 18);
System.out.println(cat1);
System.out.println(cat2);

System.out.println("----------------使用私有构造器创建对象---------------------");
//必须先设置权限
privateConstructor.setAccessible(true);
Cat cat3 = (Cat) privateConstructor.newInstance("");
System.out.println(cat3);

获取类的成员变量

Class提供了从类中获取成员变量的方法。

获取到成员变量的作用:依然是赋值、取值

Java
System.out.println("----------------获取成员变量---------------------");
System.out.println("----------------获取所有public的成员变量---------------------");
Field[] fields1 = catClass1.getFields();
for (Field field : fields1) {
    System.out.println(field);
}

System.out.println("----------------获取所有成员变量(不包含父类)---------------------");
Field[] fields2 = catClass1.getDeclaredFields();
for (Field field : fields2) {
    System.out.println(field);
}

System.out.println("----------------获取特定名称的成员变量(只能获取public)---------------------");
Field hobbyField = catClass1.getField("hobby");
System.out.println(hobbyField);
//不存在会抛异常
// Field notExistField = catClass1.getField("hobby2");
//获取私有会抛异常
// Field privateField = catClass1.getField("name");

System.out.println("----------------获取特定名称的成员变量(不包含父类)---------------------");
Field privateNameField = catClass1.getDeclaredField("name");
System.out.println(privateNameField);

//赋值和取值
System.out.println("兴趣爱好是"+cat1.getHobby());
hobbyField.set(cat1,"游泳");
System.out.println("兴趣爱好是"+cat1.getHobby());
//还可以通过反射获取字段值
System.out.println("兴趣爱好是"+hobbyField.get(cat1));
//私有字段的赋值和取值
privateNameField.setAccessible(true);
System.out.println("名字是"+privateNameField.get(cat2));
privateNameField.set(cat2,"小花");
System.out.println("名字是"+privateNameField.get(cat2));

获取类的成员方法

成员方法的作用:依然是执行

Java
System.out.println("----------------获取成员方法---------------------");
System.out.println("----------------获取所有public的成员方法---------------------");
Method[] methods1 = catClass1.getMethods();
for (Method method : methods1) {
    System.out.println(method);
}

System.out.println("----------------获取所有成员方法(不包含父类)---------------------");
Method[] method2 = catClass1.getDeclaredMethods();
for (Method method : method2) {
    System.out.println(method);
}

System.out.println("----------------获取特定名称的成员方法(只能获取public)---------------------");
//无参
Method getNameMethod = catClass1.getMethod("getName");
System.out.println(getNameMethod);
//有参
Method setNameMethod =  catClass1.getMethod("setName", String.class);
System.out.println(setNameMethod);
//多个参
Method dance1Method = catClass1.getMethod("dance1", String.class, Integer.class);
System.out.println(dance1Method);
//要注意基本数据类型和包装类的情况,基本数据类型也有class对象,不然会抛出异常
// Method dance2Method = catClass1.getMethod("dance2", String.class, Integer.class);
Method dance2Method = catClass1.getMethod("dance2", String.class, int.class);
System.out.println(dance2Method);
//不存在会抛异常
//Method notExistDance3Method = catClass1.getMethod("dance3",String.class);
//参数列表不对应也会抛异常
//Method wrongArgDance1Method = catClass1.getMethod("dance1",Long.class);
//参数顺序不对应也会抛异常
//Method wrongArgDance1Method = catClass1.getMethod("dance1",Integer.class,String.class);
//获取私有会抛异常
//Method privateSingMethod = catClass1.getMethod("sing");

System.out.println("----------------获取特定名称的成员方法(不包含父类)---------------------");
Method privatesingMethod = catClass1.getDeclaredMethod("sing");
System.out.println(privatesingMethod);

System.out.println("----------------成员方法执行---------------------");
String result = (String) getNameMethod.invoke(cat1);
System.out.println(result);
//有参数
setNameMethod.invoke(cat2,"小花");
System.out.println(cat2.getName());
//多个参数
String dance1Result = (String) dance1Method.invoke(cat2, "小花", 18);
System.out.println(dance1Result);
//参数列表有误,会抛异常
// String dance2Result = (String) dance2Method.invoke(cat2, "小花", "b");
//调用私有方法会抛异常
privatesingMethod.setAccessible(true);
String singResult = (String) privatesingMethod.invoke(cat2);
System.out.println(singResult);

作用、应用场景

反射的作用

  • 基本作用:可以得到一个类的全部成分然后操作。(除了静态代码块和实例代码块)
  • 可以破坏封装性。
  • 可以绕过泛型的约束
  • 最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。

Java
这里的代码要用jdk11运行
System.out.println("----------------反射可以绕过泛型检查---------------------");
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
//不允许
//list.add(1);
//使用反射
Field elementDataFiled = list.getClass().getDeclaredField("elementData");
elementDataFiled.setAccessible(true);
Object[] elementData = (Object[]) elementDataFiled.get(list);
elementData[0] = 123;
System.out.println(list);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值