java基础-反射1(类型信息,Class对象简介,Class对象初始化)

Java基础-反射1(反射基础,运行时类型信息,Class对象简介)

在学习反射之前,先来了解一下类型信息,类型信息就是JAVA类的一些信息,包括(包,方法,属性等),运行时类型信息可以让你在程序运行时了解类的信息并且使用类,那么如何在运行时获取类的信息?在JAVA中有两种方式:

  1. 传统的RTTI
  2. 反射

RTTI (Run-Time Type identification)

传统的RTTI的使用是假定我们在编译时就已经知道了类的信息。先来看一个例子:有一个People的抽象类,然后American类和Chinese类继承至People如下:

public abstract  class  People {
     public abstract void say();
}
public class American extends People {
    @Override
    public void say() {
        System.out.println("Americaen say: hello");
    }
}
public class Chinese extends People {
    @Override
    public void say() {
        System.out.println("中国人 说: 你好");
    }
}
public class Test {
    public static void main(String agrs[]){
        List<People> peoples= new ArrayList<>();
        peoples.add(new American());
        peoples.add(new Chinese());

        for (int i = 0 ;i <peoples.size();i++){
             peoples.get(i).say();
        }
    }
}

这里写图片描述
这是一个简单的类的继承例子,People是父类,American 和Chinese 是子类,在Test中我们创建一个List,放入American和Chinese,然后我们取出,调用say()方法.
在这里我们List中定义需要放的类型是父类People,而不是子类,面向对象的目的是让程序只操作父类而不是子类,但是我们实际上往List中添加的类型是子类(American,Chinese),这里就发生了向上转型(子类对象赋值给父类引用)但是我们在调用People的say()方法时却又打印出子类的信息(这就是多态

下面我们来看把对象从List中取出来的代码:
ArrayList底层是通过数组实现的 下面是ArryList源码中的其中一个构造方法

    transient Object[] elementData; 

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

通过源码可以看出 elementData 是一个Object 数组。所以
List peoples= new ArrayList<>(); 其实是储存的Object[]数组,但是当我们从List中取出来时,如下面代码:

  for (int i = 0 ;i <peoples.size();i++){
             peoples.get(i).say();
        }

当我们从List中取出来时却又表现出People的特点,那是因为我们从List<People> peoples中取出来时自动将Object转化为了People(向下转型,相当于People people = (People)object) 这就是RTTI的最基本的使用形式:在运行时进行类型检查因为我们在编译时已经知道List<People> peoples 储存的都是People。所以在我们从容器中取出元素时系统自动会将Object转化为People。

那么RTTI是如何工作的喃?要理解RTTI的工作原理就必须要类型信息在运行时如何表示的。

Class对象简介

java 在运行时表示类型信息是通过class这个特殊对象来完成的,
class对象属于Class类,Class类用来表示一般类的信息,所以class对象包含了与类相关的信息,它主要有以下几个特点:

  1. 每个类都有一个与其相关的Class对象。
  2. Class对象含有与其相关类的类信息。
  3. Class对象用来创建与其相关类的“常规对象“
  4. Class对象保存在与其同名的.class文件中。

那么Class对象是如何产生的喃?

Class对象是通过类加载器加载的,并且只有在第一次使用类时才会被加载。

当使用一个类时,JVM的类加载器会先检查这个类的class对象是否已经被加载,如果没有被加载,则查找同名的.class文件。如果一旦发现类的class对象已经被加载到内存了,则使用这个class对象来创建这个类的所有对象。

那么如何获取Class对象?

Class对象的获取

下面看下这个例子

public class Dog {
    static {
        System.out.println("狗");
    }
}
public class Cat {
    static {
        System.out.println("猫");
    }
}
public class People {
    static {
        System.out.println("人");
    }
}
public class Test {
    public static void main(String agrs[]){

        try {
            //获取Class 的第一种方法
            Class catClass=  Class.forName("com.hbcode.Test.Cat");

            Dog dog1 = new Dog();
            //获取Class 的第二种方法
            Class dog =dog1.getClass();
            //获取Class 的第三种方法
            Class people =People.class;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

上面就是获取类的class对象的三种方法,下面我们看下打印的信息
这里写图片描述

我们发现没有打印出来“人”那是因为使用.class来获取类的class对象并不会初始化类的class对象,实际上在获取class对象时做了一下三步:

  1. 类的加载:由类加载器执行,根据类名查找.class文件,并从中创建一个class对象
  2. 类的链接:验证.class文件(字节码文件)看其结构是否完整,并且为静态域分配空间。
  3. 类的初始化:如果类有父类则初始化父类,执行父类的静态初始化块,和静态初始化器,然后执行自己的。

延伸:笔试题,变量的初始化顺序
根据《java编程思想》一书上面的讲解,类的初始化其实是被延迟到了对静态方法的引用(构造函数也是隐式的静态方法)或者是非常数的静态域进行引用。
从上面可以看出Class.forName()其实就是调用的是类的静态函数可以被初始化。创建对象 new 对象时其实也是对构造函数(隐式的静态方法)的调用。

现在我们获取到了class对象,就可以获取其相对应的类型信息了,下一篇文章我们就来通过class对象来获取类的类型信息,并且通过反射来操作类

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值