之前看java编程思想第十四章类型信息,直接跳过了对RTTI概念的理解,只看了class、instanceof等的用法,发现这样的做法是不可取的,因为这样就只是会用这些提供的类而忽略了真正的原理。
RTTI假定我们在编译时已经知道了所有类型,然后RTTI才能在运行时进行正确性检查,这里是比较容易误解的地方,举个例子:
public class RuntimeClass {
public void test(){
List runtime = new LinkedList();
runtime.add(new RuntimeClass());
String runtimeStr = (String) runtime.get(0);
runtimeStr.toString();
}
public static void main(String[] args){
RuntimeClass runtimeclass = new RuntimeClass();
runtimeclass.test();
}
}
上图中我们先向list放入RuntimeClass类型的对象,然后通过强制转换变成String类型,在编译时成功生成class文件并且不报错。但是当我们运行main函数的时候,抛出了ClassCastException,这就说明了RTTI是在运行时才进行类型的正确性检查。在上图中模糊了list的类型(默认为object),举个不恰当的例子在编译的时候编译器只会看你对象设置的范围是否大于你要转换的范围,如果你要转换的类型在你对象设置的范围内,则编译通过,上面的例子还有一个小细节,向上转型的时候不需要显示的写出转换类型而向下转型的时候却要显示的类型,这是因为编译器知道向上转型的类型就是你要转的类型 而向下转型的类型是不确定的,所以编译器需要你显示的写出转换类型以便编译器进行检查是否合理。其实这是向下转型的一种情况,只是先做了向上转型成Object类型,然后在向下转型时编译器识别object可以转换成Runtime(由于在编译器还拿不到实际引用的类型信息所以只能对显示类型进行检查),但是在运行时发现实际类型不对应才报错。
public void test(){
RuntimeClass runtimeClass = (RuntimeClass)"test";
}
如果像上图一样,直接进行不同类型的强制转换,编译肯定是不能通过的,因为两者类型没有任何关系,既不是向上转型也不是向下转型所以在编译期就会检查出来。
介绍了概念我们来介绍下类型信息的使用:
class对象
通过类加载器jvm为每个类生成一个class对象保存在.class文件中,这里的class对象就包含了与类有关的信息。class对象并不是一开始就存在的,而是在这个类第一次被静态引用(调用构造器,构造器默认是静态的)时动态加载到jvm中,此class对象被用于所有目标类对象的创建。
class对象有几种方式获取:
1、getClass()方法
这种方式需要你拥有目标类的对象,runtime.getClass();这个方法是Object中的方法,它返回的是目标类的class对象。
2、 Class.forName()
Class.forName()是Class类的一个静态方法,它并不需要目标类的对象即可加载类,一般用来静态语句的初始化; 它的输入是一个包含目标类名的字符串,返回的是目标类的引用;如果找不到指定路径的类,这个方法会抛出ClassNotFoundException。
这里额外介绍下ClassNotFoundException和NoClassDefFoundError的区别:
ClassNotFoundException是在使用常见的三种方式(class类的forName方法、classloader类中的findSystemClass方法、classloader类中的loadclass方法)加载类的时候找不到需要加载的类,从名字可以看出这个是异常可以被捕获处理;而NoClassDefFoundError则是编译时能够加载类,运行时发现类不见了属于错误;
public class RuntimeClass {
class Circle extends RuntimeClassInterface{
}
public void test(){
try {
Class runtimeClass = Class.forName("Circle");
}catch (ClassNotFoundException e){
System.out.println("Not found Class !");
}
}
}
3、类字面常量
public void test(){
Class runtimeClass =RuntimeClass.class;
}
和forName、getClass的方式相比这种方式简单,而且更安全,因为他在编译时就会受到检查(因此不需要至于try语句块中),也不需要调用任何方法,生成任何对象,所以效能也更高。
类的初始化:
static初始化是在类加载的时候进行的,通俗理解一下就是static块或者static属性只有在类第一次加载时才会被执行;
类字面常量这种方式不会自动初始化目标类,而forName为了得到class引用会先初始化目标类。如果一个static final值是“编译器常量”那么这个值不需要初始化就可以被读取,反过来读取这个值也不会引起类的初始化加载;如果将一个域(值是在第一次加载时才确定)设置成static final是不能确保这种行为的。如果一个static不是final,那么在读取之前要求先进行链接和初始化。
泛化的class引用
为了使class的引用更加具体可以通过泛型进行类型限制class<RuntimeClass>,也可以通过Class<?>通配符来放松限制,通过泛型可以在编译器检查类型正确性。也可以组合使用 Class<? extends RuntimeClass>.
instanceof用于特定类型判断
public void test(){
RuntimeClass runtimeClass = new RuntimeClass();
if(runtimeClass instanceof RuntimeClass){
System.out.println(" This is true !");
}
}
动态instanceof
public void test(){
Class runtimeClass =RuntimeClass.class;
if( runtimeClass.isInstance(new RuntimeClass()) ){
System.out.println(" This is true !");
}
if( runtimeClass.isInstance( RuntimeClass.class) ){
System.out.println(" This is true !");
}
instanceof和Class的区别
instanceof在判断类型的时候范围是这个类的或者这个类的派生类,而用class进行==判断时 ,只判断是不是这个类不会判断是不是这个类的派生类。
反射
前面介绍的是在编译器已知的情况下,RTTI可以告诉你类型信息、检查你类型转换的正确性,但是在有些特殊情况下,在编译时无法得知对象所属的类。反射提供了这种可能,通过反射告知jvm类信息。RTTI和反射的区别在于,RTTI可以在编译的时候打开和检查.class文件,而对于反射来说编译时获取不到.class文件,只能在运行时打开和检查。java通过class和java.lang.reflect实现反射。
public void test()throws Exception{
Class c = Class.forName("RuntimeClass");
Field field = c.getField("");
Constructor constructor = c.getConstructor(RuntimeClass.class);
Method method = c.getMethod("");
}
类型信息的应用 动态代理
由于java中存在三种形式的动态代理内容较多,所以放在《动态代理扩展》中讲解。
关于类型信息就介绍到这。欢迎评论指正写的不好的地方。
分享到:
相关推荐
- **解读**:这里创建了一个名为`9203`的信息类型。信息类型是用于存储业务数据的一种高级数据结构,它通常由一个或多个结构组成,用于描述业务实体的详细信息。 - **信息类型**:在SAP中,信息类型是用于存储特定...
朱巍、王四新、支振锋、郑宁、谢永江、马澈六位专家分别从不同角度对《规定》进行了解读,他们认为《规定》的出台不仅有助于解决近年来互联网公众账号信息服务领域出现的新问题,如商业化、团队化和专业化程度提高等...
解读上市公司重组:交易类型、信息披露及流程b240204.pptx
二维码生成解读工具是一种实用软件,专门用于创建和解析二维码,以方便信息的快速传递和读取。二维码(Quick Response Code)是二维条形码的一种形式,可以存储比传统条形码更多的数据,如网址、文本、联系信息、...
71页ppt解读上市公司重组-交易类型、信息披露及流程.rar
在解读数据可视化时,关键是要理解每个图表元素的意义,如轴的刻度、颜色编码、图例等,并能够从中提取关键信息。此外,还要注意避免常见的可视化误区,如误导性的比例、不合适的颜色选择等,确保信息传递的准确性和...
总的来说,QR二维码是一种高效、灵活的信息传递工具,它的全面解读涵盖了从基本结构到高级应用的多个层面。无论是对于普通用户还是IT专业人士,理解并掌握QR二维码的相关知识都具有很高的实用价值。
VB可以通过 Declare 语句调用操作系统级别的API函数,获取更底层的功能,如系统信息、硬件操作等。API调用让VB的潜力得以进一步扩展。 总之,《VB源程序代码加解读》这份资源集将带你深入理解VB编程的各个方面,...
41. **.TLB**:OLE类型库文件,存储COM对象的接口和类型信息。 了解这些文件扩展名及其功能,可以帮助开发者更好地管理和组织VC项目,提高开发效率。在开发过程中,根据具体需求选择保留或删除某些文件,可以优化...
在5G网络中,还有其他类型的信令,包括 NAS信令、MIB(Master Information Block,系统信息块)等。NAS信令是 UE与基站之间的非接入层信令,用于承载上层协议的数据。MIB是系统信息块,用于承载系统信息,包括系统帧...
### 解读ORACLE_AWR报告 #### 基本信息概览 ORACLE_AWR(Automatic Workload Repository)报告是Oracle数据库系统中的一个重要工具,它提供了数据库性能的深入洞察,帮助管理员诊断问题并优化系统性能。AWR报告...
### SOEM函数解读 SOEM(Simple Open EtherCAT Master)作为一个免费开源的EtherCAT软件库,在工业自动化领域扮演着至关重要的角色。它为开发者提供了一种简单高效的方式来实现EtherCAT主站的功能。以下是对SOEM中...
根据提供的文件信息和部分内容,关于《城市居住区规划设计标准》的解读,我们可以从以下方面展开: 1. 标准编号与修订信息:文件中提到的“STACOISO3.117”可能指的是某个标准的编号,ISO可能是国际标准组织的缩写...
#### 五、字符集与数据类型 为了适应全球范围内的应用,SSH协议在字符集和信息本地化方面进行了灵活性设计: 1. **内部算法标识与协议名字**:必须使用US-ASCII字符集,这是协议直接处理的信息,不用于用户界面...
11. **泛型与反射**:泛型类型在反射中表现为闭合类型,即在运行时具有实际的类型信息。因此,泛型类和方法可以与其他反射特性结合使用。 12. **泛型与性能**:泛型的主要优势之一是提高了性能。由于编译器可以生成...
由于提供的文件信息中【部分内容】并非实际的内容,而是由数字和标点符号组成的无意义组合,因此无法从中提取出具体的语文课程标准习作部分的解读知识点。但是,我可以根据标题“语文课程标准习作部分解读.pdf”来...
第二条“条文解读”中,规范强调了无纸化管理是有条件的。企业内部生成的会计资料,如满足所记载事项为重复发生的日常业务、由信息系统自动生成、可即时查询和输出、具备防篡改机制、建立电子备份制度和完善的索引...
9. **反射机制**:反射是Java的一个强大特性,允许程序在运行时动态地获取类的信息并调用其方法。 10. **泛型**:泛型引入了类型安全,使得在编译时就能检查类型错误,提高了代码的可读性和可维护性。 11. **JVM...