Java反射01-反射机制和Class对象

Java反射01-反射机制和Class对象

反射机制介绍

是啥?
1在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法
2对于任意一个对象,都能够调用它的任意一个方法
这种动态获取信息以及动态调用对象方法的功能就是Java 语言的反射机制。

怎么做到的?
把类的各个组成部分封装为对象(如把成员变量封装为Filed对象,成员方法封装为Method对象,构造方法封装为Constructor方法)
为了更深入的了解,我们先看下java类的加载过程。

1硬盘中的java源文件(xx.java)先编译为字节码文件(xx.class,还在硬盘中)。
2 类加载进内存:类加载器将class文件读入jvm的方法区(堆中),并创建一个java.lang.class对象,表示这个类的运行时元数据。
3 类中的所有属性又封装进 Field对象中,所有方法封装进 Method对象中,
所有构造方法封装进Constructor当中。

这样一个硬盘中的类文件,就读入了内存中,变成了某些特定的对象(Class,Field,Method),通过调用这些对象便能获取类的信息和调用类中的方法,后面会详细讲解如何调用这些对象。

有啥用?
1可以在程序运行中,操作反射生成的method,Filed,constructor对象,访问对象的属性,方法。
2 IDE开发工具的代码提示(对象或类后输入. 会自动提示其所有的方法和属性)
3生成动态代理,帮助我们创建框架。 比如spring框架的IOC容器,我们只在配置文件中提供类的信息,spring便可通过反射来动态创建bean对象。

Class对象

获取Class对象的三种方式

以下三种方式获取的Class对象是同一个对象,类的字节码文件(.class)在类的运行过程中只会被加载一次(内存堆中只有一个该类的class对象)

//创建一个类对应的Class对象的三种方式
//1类还未加载进内存时:通过Class类的forName方法把类加载进内存并生成Class对象
//多用于读取配置文件,加载类
Class<?> class01 = Class.forName("cn.yy.TestClassObject");
//2类已经加载,但是还没有创建实例对象:可以使用类的class属性获取class对象
//多用于调用方法时传递参数
Class<TestClassObject> class02 = TestClassObject.class;
//3类已经加载,且有实例对象:可通过实例对象的getClass方法来获取class对象
//多用于获取某个对象的字节码文件
TestClassObject testClassObject = new TestClassObject();
Class<? extends TestClassObject> class03 = testClassObject.getClass();
//经过比较三种方式获取的Class对象是同一个对象。
//可得出结论:类的字节码文件(.class)在类的运行过程中只会被加载一次(内存堆中只有一个该类的class对象)
System.out.println(class01 == class02);//true
System.out.println(class02 == class03);//true
//也可反向观察不同类对应的Class对象不同
Class<?> classReflection = Class.forName("cn.yy.Reflection01");
System.out.println(class01 == classReflection);//false

Class对象常用方法

在这里插入图片描述
(1)forName–根据类名返回类对象

Class<Game> gameClass = (Class<Game>) Class.forName("cn.yy.testClassObject.Game");

(2)getName()–获取类完整路径名

Class<Game> gameClass = (Class<Game>) Class.forName("cn.yy.testClassObject.Game");
String path = gameClass.getName();//获取类全路径名:cn.yy.testClassObject.Game

(3)cast()–类型转化
下面是几个测试的类,Game是游戏接口,ComputerGames 和MobileGames是Game的两个实现类。

public interface Game {
    String Name = "game";
    //展示游戏名
    String printGameName();
    //展示游戏类型
    String GameType();
}

public class ComputerGames implements Game {
    @Override
    public String printGameName() {
        return "I am Computer Games";
    }

    @Override
    public String GameType() {
        return "My Type is Computer Games";
    }
}

public class MobileGames implements Game {
    @Override
    public String printGameName() {
        return "I am Mobile Games";
    }

    @Override
    public String GameType() {
        return "My Type is  Mobile Games";
    }
}

下面是cast方法测试

//cast方法:(强制)类型转化
//获取Game类的Class对象
Class<Game> gameClass = (Class<Game>) Class.forName("cn.yy.testClassObject.Game");
MobileGames mobileGames = new MobileGames();
//调用cast方法,将mobileGames转为了Game类型
Game cast = gameClass.cast(mobileGames); //类型转化成功
//若被转化对象不是Game的子类,则报错
Car car = new Car();
Game cast1 = gameClass.cast(car); //因为car不是Game的实现类,所以报错:
//java.lang.ClassCastException: Cannot cast cn.yy.testClassObject.Car to cn.yy.testClassObject.Game

可以看下cast的源码:先调用isInstance判断能否被强制转换

public T cast(Object obj) {
        if (obj != null && !isInstance(obj))
            throw new ClassCastException(cannotCastMsg(obj));
        return (T) obj;
}

class.inInstance(obj)情况分析:
1一个对象是本身类的一个对象
2.一个对象能被转化为本身类所继承类(父类的父类等)和实现的接口(接口的父接口)强转
3.所有对象都能被Object的强转
4.凡是null有关的都是false class.inInstance(null)

(4)获取Field 属性对象
在这里插入图片描述
1 Declared的暴力获取所有Field,Method或者Constructor,无视权限修饰符
2 结尾带s的获取所有Field,Method或者Constructor,返回结果是数组。
3 结尾不带s的根据名称获取Field,Method,根据参数类型获取Constructor,返回结果是一个Field/Method/Constructor对象

测试类

public  class Car {
    //四种不同权限修饰符的属性
    public  String publicProperty="publicProperty";
    protected   String protectedProperty="protectedProperty";
    String defaultProperty="defaultProperty";
    private   String privateProperty="privateProperty";
    //四种不同权限修饰符的方法
    public  void showPublicMethod(){
        System.out.println("This is a Public Method");
    }
    protected   void showProtectedMethod(){
        System.out.println("This is a Protected Method");
    }
    void showDefaultMethod(){
        System.out.println("This is a Default Method");
    }
    private   void showPrivateMethod(){
        System.out.println("This is a Private Method");
    }
}

方法代码

Class<Car> carClass = (Class<Car>) Class.forName("cn.yy.testClassObject.Car");
//获取car类中所有权限修饰符为public的属性对应的Field对象
Field[] fields = carClass.getFields();
//获取car类中所有权限修饰符的属性对应的Field对象
Field[] declaredFields = carClass.getDeclaredFields();
//获取car类中指定名称的属性对应的Field对象
Field declaredField = carClass.getDeclaredField("protectedProperty");

Debug结果,可以看到declaredFields可以获取所有属性
在这里插入图片描述
(5)获取Method对象
在这里插入图片描述

1 Declared的暴力获取所有Field,Method或者Constructor,无视权限修饰符
2 结尾带s的获取所有Field,Method或者Constructor,返回结果是数组。
3 结尾不带s的根据名称获取Field,Method,根据参数类型获取Constructor,返回结果是一个Field/Method/Constructor对象

Class<Car> carClass = (Class<Car>) Class.forName("cn.yy.testClassObject.Car");
//根据方法名获取Method对象
Method showDefaultMethod = carClass.getMethod("showPublicMethod");
//获取car类中所有public的方法对应的Method对象
Method[] methods = carClass.getMethods();
//获取car获取car类中所有方法对应的Method对象
Method[] declaredMethods = carClass.getDeclaredMethods();

可以看到,getMethods(),方法除了获取car类本身的public方法,还获取了继承自Object类的方法。
在这里插入图片描述
(6)获取Constructor对象
在这里插入图片描述
测试代码

Class<Car> carClass = (Class<Car>) Class.forName("cn.yy.testClassObject.Car");
Constructor<?>[] constructors = carClass.getConstructors();
Constructor<?>[] declaredConstructors = carClass.getDeclaredConstructors();
//因为构造函数时重载的,名称一样,因此通过参数类型 来获取指定的Constructor对象
Constructor<Car> stringParameterConstructor = carClass.getDeclaredConstructor(String.class);

在这里插入图片描述

Field,Method和Constructor对象会在反射的后续文章中介绍。

aa

Java萌新,如有错误,请指正

创作不易,对您有帮助的话,劳烦您点赞支持啦~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值