Java类型信息之RTTI
软件工程的一个核心问题就是软件的复用和扩展。面向对象思想通过封装,继承,派生等机制有效地解决了这个问题。但需求总是变幻莫测,不可琢磨,在面向对象这栋恢宏的大厦旁,还漂浮着一朵乌云,从而导致了RTTI的登场。
正是因为RTTI的存在,在软件世界里,无间道是会分分钟暴露的:

1.缘起
考虑一下面向对象思想发源地之一的CAD系统:
package typeinfo._01_rtti; import java.util.Arrays;
import java.util.List; interface Shape {
void draw();
} class CAD {
public void draw(List<Shape> shapes) {
for (Shape shape : shapes) {
shape.draw();
}
}
} class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle draw()");
}
} class Square implements Shape {
@Override
public void draw() {
System.out.println("Square draw()");
}
} class Triangle implements Shape {
@Override
public void draw() {
System.out.println("Triangle draw()");
}
} public class Shapes {
public static void main(String[] args) {
List<Shape> shapes = Arrays.asList(
new Circle(), new Square(), new Triangle()
); CAD cad = new CAD();
cad.draw(shapes);
}
}
输出结果:
Circle draw()
Square draw()
Triangle draw()
代码点评:
Shape是基类,根据多态机制,Shape引用可以被它的子类引用赋值,并通过动态绑定在虚函数draw调用时正确调用子类的draw。
依靠这种机制,我们可以轻松的在上层的CAD类中写出通用的draw方法,而不用管Shape到底会有多少子类。
现在忽然来了新的需求,要求CAD在draw的时候把用户指定类型的对象高亮显示,假设用户指定了Circle类型,那就是要求把当前图形中的所有的Circle对象高亮显示。因为上层的CAD代码无法分辨具体的子类类型,所以功能无法实现。
痛定思痛,这些面向对象的大师们决定引入RTTI(Run-Time Type Identification)运行时类型识别,简单的说就是运行时你只要给我一个引用,就我能准确的告诉你它是什么具体类型的。
尽管RTTI名声不好,大师们的建议是能少用就少用,但是具有讽刺意味的是,几乎没有哪门语言能跳过RTTI,不同的只是各种各样的语法区别:
Python语言的type
Java语言的getClass
javascript语言的typeof
C++语言的typeid
C#语言的GetType
。。。
2.Java语言的class
Java语言的class其实是一个Class类的对象,任何类都有一个这样的对象,实际上,这是对象又是Java类加载器加载类时自动带上的,要理清这些角色之间的复杂关系,请看下图:

所有new出来的对象共享该类型的class对象
class对象是Class类的一个实例
Class类是被ClassLoader带进来的
ClassLoader通过加载class字节码导入类
口说无凭,直接来段测试代码吧:
@Test
public void testClassLevel() {
class Test {
} Test a = new Test();
System.out.println(a.getClass());
Test b = new Test();
System.out.println(b.getClass()); System.out.println(a.getClass() == a.getClass()); System.out.println(Test.class);
System.out.println(Test.class.getClassLoader());
}
输出结果:
class typeinfo._01_rtti.ClassClassTest$1Test
class typeinfo._01_rtti.ClassClassTest$1Test
true
class typeinfo._01_rtti.ClassClassTest$1Test
jdk.internal.loader.ClassLoaders$AppClassLoader@726f3b58
代码点评:
new出来的对象可以通过getClass得到该类型的class对象
所有new出来的对象getClass得到的class对象都是同一个
class对象可以通过Test.class的形式快速引用
class对象可以通过getClassLoader得到类加载器
关于类加载器的细节,将单独有一篇文章介绍
2.引用class
引用class最简单的方式就是通过XXX.class的语法直接引用:
public void print(Class meta) {
System.out.println(meta);
}
@Test
public void testClassClass() {
print(boolean.class);
print(char.class);
print(byte.class);
print(short.class);
print(int.class);
print(long.class);
print(float.class);
print(double.class);
print(void.class);
print(Object.class);
print(String.class);
}
输出结果:
boolean
char
byte
short
int
long
float
double
void
class java.lang.Object
class java.lang.String
代码点评:
没错,基本类型也有class,甚至是void也有class
class及其Class就是Java类型体系的核心
还有内置的数组呢?同样不能例外:
@Test
public void testClassClassArray() {
print(boolean[].class);
print(char[].class);
print(byte[].class);
print(short[].class);
print(int[].class);
print(long[].class);
print(float[].class);
print(double[].class); //print(void[].class);
print(Object[].class);
print(String[].class);
}
输出结果:
class [Z
class [C
class [B
class [S
class [I
class [J
class [F
class [D
class [Ljava.lang.Object;
class [Ljava.lang.String;
代码点评:
void[]是不存在的
输出的这些奇怪的字符,这是历史原因造成的,其实它就表示数组
通过对象得到class要用getClass:
@Test
public void testClassGetClass() {
Boolean t = true;
Character c = 'A';
Byte b = 0;
Short s = 0;
Integer i = 0;
Long l = 0L;
Float f = 1.0f;
Double d = 1.0; print(t.getClass());
print(c.getClass());
print(b.getClass());
print(s.getClass());
print(i.getClass());
print(l.getClass());
print(f.getClass());
print(d.getClass()); //Void v = new Void();
Object obj = new Object();
String str = new String();
//print(v.getClass());
print(obj.getClass());
print(str.getClass());
}
输出结果:
class java.lang.Boolean
class java.lang.Character
class java.lang.Byte
class java.lang.Short
class java.lang.Integer
class java.lang.Long
class java.lang.Float
class java.lang.Double
class java.lang.Object
class java.lang.String
代码点评:
基本类型不能生成对象引用,只好用它们的包装类对象引用
除了Void,其它的与XXX.class是一致的
其实数组也是对象,所以下面的代码也是成立的:
@Test
public void testClassGetClassArray() {
boolean[] t = {true};
char[] c = {'A'};
byte[] b = {0};
short[] s = {0};
int[] i = {0};
long l[] = {0L};
float f[] = {1.0f};
double[] d = {1.0}; print(t.getClass());
print(c.getClass());
print(b.getClass());
print(s.getClass());
print(i.getClass());
print(l.getClass());
print(f.getClass());
print(d.getClass()); Object[] obj = {new Object()};
String[] str = {new String()};
print(obj.getClass());
print(str.getClass());
}
输出结果:
class [Z
class [C
class [B
class [S
class [I
class [J
class [F
class [D
class [Ljava.lang.Object;
class [Ljava.lang.String;
对于Java的基本类型,还可以通过XXX.TYPE的形式引用class,这是基本类型所特有的绿色通道:
@Test
public void testClassType() {
print(Boolean.TYPE);
print(Character.TYPE);
print(Byte.TYPE);
print(Short.TYPE);
print(Integer.TYPE);
print(Long.TYPE);
print(Float.TYPE);
print(Double.TYPE); print(Void.TYPE);
//print(Object.TYPE);
//print(String.TYPE);
}
输出结果:
boolean
char
byte
short
int
long
float
double
void
3.class与泛型
原则上,所有的class都是Class类的对象,但是这太粗略了。我们可以通过泛型进一步细化Class类:
@Test
public void testGeneric() {
Class intClass = int.class;
intClass = double.class; Class<Integer> genericIntClass = int.class;
genericIntClass = Integer.class; // Same thing
// genericIntClass = double.class; // Illegal
}
代码点评:
默认的Class即可以引用int.class,也可以引用double.class
Class<Integer>就只能引用int.class了,不可以引用double.class
当然了,在泛型的世界里,更习惯用通配符Class<?>代替Class,以表明它那高贵的泛型身份:
@Test
public void testWildcard() {
Class<?> intClass = int.class;
intClass = double.class;
intClass = String.class;
}
当然了,还不能忘了泛型的限定符:
@Test
public void testBounded() {
Class<? extends Number> numberClass = int.class;
numberClass = double.class;
numberClass = Number.class;
//numberClass = String.class;
}
这里通过限定符的限制,有效的避免了String.class的引用。
Java类型信息之RTTI的更多相关文章
- Java类型信息(RTTI和反射)
要想在IT领域站得住脚,必须得不断地学习来强化自己,但是学过的技术不实践很容易便被遗忘,所以一直都打算开个博客,来记录自己学的知识,另外也可以分享给有需要的人! 最近在学习反射,为了更好地理解反射,就 ...
- Thinking in Java -- 类型信息RTTI
Thinking in Java – 类型信息 个人感觉 java 中的比較难的部分了,在看了些netty源代码发现事实上这块很实用. 这章重点是RTTI和反射.先说下自己的理解 RTTI是执行时识别 ...
- JAVA类型信息——反射机制
JAVA类型信息——反射机制 一.反射机制概述 1.反射机制:就是java语言在运行时拥有的一项自我观察的能力,java通过这种能力彻底了解程序自身的情况,并为下一步的动作做准备. 2.反射机制的功能 ...
- JAVA类型信息——Class对象
JAVA类型信息——Class对象 一.RTTI概要 1.类型信息RTTI :即对象和类的信息,例如类的名字.继承的基类.实现的接口等. 2.类型信息的作用:程序员可以在程序运行时发现和使用类型信息. ...
- Java基础 -- 深入理解Java类型信息(Class对象)与反射机制
一 RTTI概念 认识Claa对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RT ...
- Java类型信息
一.引言 最近在阅读<Java编程思想>,学习一下java类型信息,现在做一下总结.Java如何让我们在运行时识别对象和类的信息的.主要有两种方式:一种是传统的“RTTI”,它假定我们在编 ...
- JAVA类型信息——Class对象(转载)
JAVA类型信息--Class对象 一.RTTI概要 1.类型信息RTTI :即对象和类的信息,例如类的名字.继承的基类.实现的接口等. 2.类型信息的作用:程序员可以在程序运行时发现和使用类型信息. ...
- Java 类型信息
<Thinking in Java 4th>第14章 类型信息 运行时类型信息(Run-Time Type Identification)使得你可以在程序运行时发现和使用类型信息. 14. ...
- 类型信息(RTTI和反射)——反射
运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就来说说反射. 重点说说通过反射获取方法以及调用方法,即类方法提取 ...
随机推荐
- mysql安装了半天参考了文章搞定了
https://blog.csdn.net/yelllowcong/article/details/79641313 mysql -uroot -pbrucelee 总结下: 1.安装时注意具体的路径 ...
- JQuery 目录树jsTree插件用法
PHP循环构造目录树结构 <ul> <php> function digui($fid,$level){ $class=M("wangpan_class") ...
- RTMP 摄像头推流至七牛云直播
设置图 报警设置 可以图片和视频保存到服务器,通过 ftp sd 卡数据 http://192.168.1.101/sd/20190127/ rtmp 推流 参考文档 淘宝凯锐视讯RTMP推流说明书 ...
- HDFS的WEB页面访问常见问题
HDFS的WEB UI管理页面 50070 端口 无法访问解决办法! 本文基于HADOOP-3..1.0,Cecntos7.0环境下进行测试,所以遇到很多新鲜的问题: 特别注意:HaDoop3.0之前 ...
- Android makefile
LOCAL_PATH := $(call my-dir) { call函数:根据不同的参数和函数得到不同的值my-dir函数: 获取当前含有.mk的路径LOCAL_PATH: 定位源文件的位置 } # ...
- Python全栈-magedu-2018-笔记3
第三章 - Python 内置数据结构 分类 数值型 int.float.complex.bool 序列对象 字符串 str 列表 list tuple 键值对 集合set 字典dict 数值型 数值 ...
- tomcat之过滤器
过滤器是一种特殊的servlet,也需要在配置文件中进行配置,通过它可以将指定的请求拦截下来,之后对请求处理,处理完之后,将拦截请求放行.实现过滤器也需要实现一个接口叫javax. servlet.F ...
- treesoft,couchDB,
下载 docker 镜像:docker pull docker.io/lu566/treesoft:1.0启动容器:docker run -d -p 127.0.0.1:18080:8080 dock ...
- k8s-No.1-概述与架构
本章目录 k8s概述 k8s系统架构 k8s工作流程图 一 概述 k8s是什么 k8s是谷歌公司基于内部容器管理系统borg开源出的一个容器集群管理工具,它是用go语言开发,提供了容器的应用部署,规 ...
- Spark入门到精通--(外传)Cloudera CDH5.5.4搭建
http://www.mamicode.com/info-detail-601202.html continue...