Thinking in Java学习笔记——Type Information

孔昱
• 阅读 1675

有两种形式在运行时获取类型信息:

  1. 传统的RTTI
  2. 反射

Class对象

  • 运行时的类型信息是通过Class对象表现的,它包含了类的信息。所有“普通的”对象都是通过Class对象创建的。Java通过Class对象实现RTTI。
  • 在你的程序中每个类都对应一个Class对象。每次编写并编译一个新的类时都会创建一个相应的Class对象,并且以.class文件储存起来。JVM用class loader子系统创建对象。
  • JVM有一个原生的class loader用来加载“可信类”,包括JAVA API中的类。你也可以实现自己的带有特殊目的的class loader并与原生的串联起来。
  • 在一个类第一次被访问static成员时,这个类则被加载到JVM。构造函数也是静态的,所以用new创建对象时也算访问了static成员。因此Java程序运行前并不是完全加载了。
  • class loader先检查类型的Class对象是否加载了,如果没加载,class loader会找到.class文件(其他的class loader可能会从别处加载二进制码,比如从数据库)。字节被加载之后会被验证一下有没有损坏或者有没有不安全的代码。
  • Class对象被加载到内存之后,将被用来创建这个类型的所有对象。
  • 所有Class对象都属于Class类,和其他类一样可以使用引用操作Class对象。一种获得Class对象的方法是调用静态的forName()方法,这个方法接收一个字符串类型,是类的名字,需要使用包括报名的全名。如果找不到.class文件,会抛出一个ClassNotFoundException
  • 在运行时,使用类型信息之前要先获取Class对象。Class.forName()是比较方便的做法。如果已经有一个这个类型的对象了,可以调用对象getClass()方法,这个方法是在Object里定义的。

Class literals

除了forName()外,Java还提供一种获得Class对象引用的方法,比如Toy.class。这种方法更简洁和更安全,因为这种方法的类型在编译时就会被检查。

基本类型的包装类有一个标准字段TYPE,提供了基本类型的Class对象,例如:boolean.class <=> Boolean.TYPE

__使用.class获得Class对象引用不会初始化Class对象__。获得一个可用的类需要三步

  1. 加载,由类加载器完成。找到字节码并创建一个Class对象。
  2. 链接,检验字节码,为static字段分配存储空间,解决其对他类的引用。
  3. 初始化,如果有父类则初始化父类,执行静态初始化器和静态初始化区块

直到第一次访问静态成员时初始化才执行。

Class.forName()获得引用则会引起初始化。

如果static final成员是编译时常量,访问这个成员则不会引起初始化。如果static final成员不是编译时常量(由初始化器赋值),也会引起初始化。访问不是final的static成员总会引起链接和初始化,即分配存储和初始化值。

Generic class references

Class<?> <=> Class

使用generic语法可以让你在编译时就发现类型不对的错误。只用Class的话,如果犯了错误到运行时才会发现。

New cast syntax

//: typeinfo/ClassCasts.java
class Building {}
class House extends Building {}

public class ClassCasts {
      public static void main(String[] args) {
        Building b = new House();
        Class<House> houseType = House.class;
        House h = houseType.cast(b);
        h = (House)b; // ... or just do this.
      }
} ///:~

Checking before a cast

RTTI的三种形态:

  1. 传统的类型转换,使用RTTI来确保类型转换时正确,如果不正确会抛出ClassCastException异常
  2. Class object表示对象的类型。Class对象可以提供很有用的运行时信息。
  3. instanceof,检验对象是不是某类型。(动态Class.islnstance())

反射

RTTI可以提供类型信息,但是如果在编译时并不知道对象所属类的信息(比如从硬盘或网络读取的字节所组成的类),则无法使用RTTI。

Class类和java.lang.reflect中的Field, Method, and Constructor(实现了Member接口)一起支持了反射的概念。在运行时,JVM会创建这些类型的对象来表示未知类的成员。

使用反射前提是JVM可以找到未知类型的.class文件(从硬盘中的文件或者网络)。

  • RTTI在编译时,由编译器打开和检查.class文件。
  • 在反射机制中,.class在编译时是不可用的,.class是由运行环境在运行时打开和检查的。

接口和类型信息

利用反射可以访问对象的方法和成员变量,不论访问修饰符是什么。但是反射不能修改final的变量,在运行时试图修改final字段不会报错,但是实际上修改并没有生效。

概念

class type .class文件 Class Class object Class reference
java中的类 类型,对应于一个类,每个类都是一个类型 用来储存Class对象,程序中编写的每个类,都会被编译成一个.class文件 一种叫“Class”的类 Class类的一个实例,这个类由.class文件而来,负责创建它所表示的类的实例 Class object的引用,包括了这个类的statics

其他小知识

  • 一个类默认的构造器和这个类有相同的访问修饰符
点赞
收藏
评论区
推荐文章
待兔 待兔
4年前
一篇文章弄懂 Java 反射的使用
说到Java反射,必须先把Java的字节码搞明白了,也就是Class,大Class在之前的文章中,我们知道了Java的大Class就是类的字节码,就是一个普通的类,里面保存的是类的信息,还不太明白Java的大Class的,可以先看一下之前的文章先想一个问题1.给我们一个类,我们如何使用?这还不简单,通过这个类,创建一个类的对象,再通过这个
Wesley13 Wesley13
4年前
java反射大全
作者对反射的理解:方法的调用(正常的调用:对象.方法()。反射调用方法:方法.对象())静态属性的调用(正常的调用:类.属性。反射调用:属性.类)常见反射的用法:        1.通过反射获取类Class<?demo1Class
Wesley13 Wesley13
4年前
java面试(反射)05
1.什么是反射JAVA反射机制是在运行状态中,对于任意一个类,都能够获取这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取类信息以及动态调用对象内容就称为java语言的反射机制。2.反射的作用在运行时判断任意一个对象所属的
浪人 浪人
4年前
如果有人再问你 Java 的反射,把这篇文章扔给他
在Java中,并不是所有的类型信息都能在编译阶段明确,有一些类型信息需要在运行时才能确定,这种机制被称为RTTI,英文全称为RunTimeTypeIdentification,即运行时类型识别,有没有一点“知行合一”的味道?运行时类型识别主要由Class类实现。在日常的学习工作当中,有一些知识是我们在读书的时候就能够习得;但有一些知识不是的
Wesley13 Wesley13
4年前
Java反射机制
反射:运行时,对任意类,都能知道这个类的所有属性和方法;对任意一对象,都能够调用它的每个方法和属性。1、获取类的Class对象调用getClassBoolean var1  true;运用.class语法Class<? classType4  Boolean.class;运用静态方法C
Wesley13 Wesley13
4年前
Java基础之反射(非常重要)
反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))一、反射的概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法
Wesley13 Wesley13
4年前
Java反射技术概述
1.什么是Java反射?  就是正在运行,动态获取这个类的所有信息2.反射机制的作用  a.反编译:.class.java  b.通过反射机制,访问Java对象的属性,方法,构造方法等3.反射机制的应用场景  Jdbc加载驱动  SpringIOC实现  Java框架4.创建对象的两种方式  a.直
Stella981 Stella981
4年前
EKT Java企业级关键技术强化 Enterprise Edition
EKTenterprisekeytechlology企业关键技术本章目标:1.理解Class类2.理解JAVA类加载体系结构3.理解类的加载过程Class对象由JVM自动产生,每当一个类被加载时,JVM就自动为其生成一个Class对象,通过Class对象可以获得类的相关信息。将类信息读到内存中过程,称为类加载
Stella981 Stella981
4年前
Python对象相关内置函数
针对一个对象,通过以下几个函数,可以获取到该对象的一些信息。1、type(),返回某个值的类型type(123)<class'int'type('str')<class'str'type(None)<type(None)'NoneType'使用就是括号
Wesley13 Wesley13
4年前
Java总论及三大特性理解
1、对象(object)   万物皆为对象(根类Object类)。   程序是对象的集合(面向对象程序设计语言OOP)。   每个对象都有自己的由其他对象所构成的存储(对象有成员属性)。   每个对象都拥有其类型(每个对象都是某个类class的一个实例instance)。某一特定类型的所有对象都可以接收
Wesley13 Wesley13
4年前
Java反射的使用
在Java中,并不是所有的类型信息都能在编译阶段明确,有一些类型信息需要在运行时才能确定,这种机制被称为RTTI,英文全称为 RunTimeTypeIdentification,即运行时类型识别,有没有一点“知行合一”的味道?运行时类型识别主要由Class类实现。在日常的学习工作当中,有一些知识是我们在读书的时候就能够习得;但有一些知识不
孔昱
孔昱
Lv1
宁愿做过了后悔,也不愿错过了后悔
文章
3
粉丝
0
获赞
0