Java 编程思想 Chapter_14 类型信息
本章内容绕不开一个名词:RTTI(Run-time Type Identification) 运行时期的类型识别
知乎上有人推断作者是从C++中引入这个概念的,反正也无所谓,理解并能串联本章知识才是最重要的
本章的内容其实都是为类型信息服务的,主要内容有

一.Class对象
问题:
1.Class对象的创建过程是怎么样的
2.Class对象有哪几种创建方式,之间有什么差异
3.使用泛型
在了解类型信息之前,需要了解class对象
创建class对象,需要先查找这个这个类的.class文件, 查找到的class文件会以字节码的形式加载到内存, 这时便可以通过内存中的Class对象 创建这个类的所有对象
本章中创建对象的方式有三种
第一种: 通过new 构造器 的方式
第二种: Class cls = Class.forName(“全限定名”); cls.newInstance();
第三种 Class cls = 类:.class; cls.newInstance();
说3种比较牵强,第二种和第三种通过虚拟构造器newInstance()的方式创建了对象, newInstance()有2点需要注意: ①接口不能newInstance;②类必须有的空构造器
这三种方式有什么差别呢,在这里会牵涉到其他的知识点
1.调用一个类的静态方法,有没有创建了一个对象
答案是没有的,因为没有涉及到以上3种创建对象的方式,只是将.class文件载入到了内存,对类进行了初始化, 并没有去创建对象
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
A.print();
}
}
class A{
static{
System.out.println("static 静态块");
}
public A(){
System.out.println("构造方法");
}
public static void print(){
System.out.println("打印class A");
}
}
打印的结果如下:
static 静态块
打印class A
2. Class.forName(“全限定名”) 和 .class有没有差别
有差别, Class.forName会主动去在加载静态方法块, 而.class不会, .class对静态方法或非常数静态域首次引用后才进行初始化
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Class.forName("chapter_14.A");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
打印: static 静态块
public static void main(String[] args) {
// TODO Auto-generated method stub
Class cls = A.class;
}
没打印
提一点题外话, 为什么我们平时看到的被访问的静态常量通常是这样的
public static final int CONSTANT = 5;
而不是
public static int CONSTANT = 5;
原因在于static final 是编译期常量, 类.CONSTANT 不需要对类进行初始化就可以被读取
引入泛型的意义仅仅是为了提供编译期检查,第15章会着重讲讲泛型,在这里提供了几个概念
和平凡.class不一样, 泛型newInstance()返回该对象的确切类型
class A{}
class B extends A{}
Class<A> clsA = A.class;
A objA = clsA.newInstance();
那么超类呢?
Class<? super B> clsA = B.class.getSuperclass(); Object objA = clsA.newInstance();
超类得到不是精确类型,而只是Object
那继承类呢?
Class<? extends A> clsB = B.class; A objA = clsB.newInstance();
此时得到的是父类的类型,在接下来的学习中,我们会经常用这种方式来创建对象,说白了这属于多态,属于类型信息
二.类型转换前先做检查
问题:
1.类型转换前先做的检查的意义和检查的方式
通过显式的向下转型,避免出现ClassCastException
常见的检查方式有3种,instanceof, isInstance, isAssignableFrom
举个例子:
class A implements Iface{}
class B extends A{}
interface Iface{}
第一种 instanceof
//类检查 本身类实例化对象的类型 Class<? super B> clsA = B.class.getSuperclass(); Object objA = clsA.newInstance(); System.out.println(objA instanceof A);//true //类检查 子类实例化对象的类型 Class clsB = B.class; Object objB = clsB.newInstance(); System.out.println(objB instanceof A);//true //接口检查 实现类实例化对象的类型 System.out.println(objA instanceof Iface);//true System.out.println(objB instanceof Iface);//true
第二种:isInstance
Class<? super B> clsA = B.class.getSuperclass(); Object objA = clsA.newInstance(); Class clsB = B.class; Object objB = clsB.newInstance(); //类的Class对象检查 类本身的实例化对象 System.out.println(clsA.isInstance(objA));//true System.out.println(clsB.isInstance(objB));//true //类的Class对象检查 子类的实例化对象 System.out.println(clsA.isInstance(objB));//true //接口的Class对象检查 实现类的实例化对象 Class clsIface = Iface.class; System.out.println(clsIface.isInstance(objA));//true System.out.println(clsIface.isInstance(objB));//true
第三种 isAssignableFrom
Class<? super B> clsA = B.class.getSuperclass(); Object objA = clsA.newInstance(); Class clsB = B.class; Object objB = clsB.newInstance(); //类的Class对象检查 类本身的Class对象 System.out.println(clsA.isAssignableFrom(clsA));//true //类的Class对象检查 子类的Class对象 System.out.println(clsA.isAssignableFrom(clsB));//true //接口的Class对象检查 实现类的Class对象 Class clsIface = Iface.class; System.out.println(clsIface.isAssignableFrom(clsA));//true System.out.println(clsIface.isAssignableFrom(clsB));//true
对以上3种方式进行总结,便是以下这张图了

类型检查在另一方面也说明了 类与类的关系,类与接口的关系。
三.注册工厂
问题:
1.注册工厂有什么用
注册工厂是将工厂方法设计模式和添加融合在一起,在本章中,还是和类型信息有关系,在基类中添加实现类的对象,不过都是根据工厂设计模式去实现的,这样做的好处在于“避免新添加的数据对结构产生破坏”。本章中的例子很形象,也非常好,如果我有好的例子,也一定会放上链接
四.空对象
问题:
1.什么是空对象
2.使用空对象的意义
通常,空对象是一个单例,它具有无法修改的特性
假设一个类的 某个变量默认情况下是空对象,那么想要改变这个变量的属性,就需要重新创建一个对象来代替这个空对象,感觉我说的是废话,不过这是空对象的本质了,结合下以下代码,好好考虑下
interface Null{}
class Person{
private final String first;
private final String last;
private final String address;
public Person(String first, String last, String address) {
super();
this.first = first;
this.last = last;
this.address = address;
}
@Override
public String toString() {
return "Person [first=" + first + ", last=" + last + ", address=" + address + "]";
}
static class NullPerson extends Person implements Null{
private NullPerson(){
super("None", "None", "None");
}
@Override
public String toString() {
return "NullPerson";
}
}
public static final Person NULL = new NullPerson();
}
这段代码抄自Java编程思想的空对象一节,另外有个知识点:不是每个类都会有默认的空构造器,像上面的Person类其实是没有空构造器的,问题在于构造器的参数用final修饰,可以去探究下。
五.反射
1.反射机制是怎么样的
2.如何通过动态代理的方式使用反射机制
反射是程序在运行时打开和检查.class文件,因此反射是动态的,JDK中使用Class类和java.lang.reflect类库对反射的概念进行了支持
使用反射是由于 某些类的属性,方法对外 没有包访问权限,而我们不得不进行访问,才能完成一些事情
可想而知,包访问权限对反射而言起不了作用,这里包括了private修饰, 私有内部类和匿名内部方法
应用到反射的例子有android中组件通信的EventBus,可以下载下来看源码
反射也可以用于动态代理(多说一句,动态代理本质还是类型信息)主要代码抄自书上
public class Test {
public static void main(String[] args) {
A objA = new A();
Iface iface = (Iface) Proxy.newProxyInstance(Iface.class.getClassLoader(),
new Class[]{Iface.class}, new DynamicProxyHandler(objA));
doSomething(iface);
}
public static void doSomething(Iface iface){
iface.doSomething();
}
}
class A implements Iface{
@Override
public void doSomething() {
System.out.println("A doSomething");
}
}
interface Iface{
public void doSomething();
}
//所有的调用都会重定向到这个单一的处理器上
class DynamicProxyHandler implements InvocationHandler{
private Object proxied;
public DynamicProxyHandler(Object proxy){
proxied = proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
return method.invoke(proxied, args);
}
}
这里有3点需要注意的:1..重定向单一的处理器,调用的对象是什么; 2.创建的iface必须是接口对象,创建接口对象要传递的第二个参数是Class数组, 它包含了所有proxied的接口名称.class ; 3.动态代理与类型信息之间的关系
Java 编程思想 Chapter_14 类型信息的更多相关文章
- java编程思想-枚举类型思维导图
- 《Java编程思想》学习笔记(二)——类加载及执行顺序
<Java编程思想>学习笔记(二)--类加载及执行顺序 (这是很久之前写的,保存在印象笔记上,今天写在博客上.) 今天看Java编程思想,看到这样一道代码 //: OrderOfIniti ...
- [Java编程思想-学习笔记]第3章 操作符
3.1 更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...
- Java编程思想重点笔记(Java开发必看)
Java编程思想重点笔记(Java开发必看) Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...
- Java编程思想——初始化与清理
PS:最近一直忙于项目开发..所以一直没有写博客..趁着空闲期间来一发.. 学习内容: 1.初始化 2.清理 1.初始化 虽然自己的Java基础还是比较良好的..但是在解读编程思想的时候还是发现了 ...
- 注解的基本盘点 -- 《Java编程思想》
注解(元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在之后的某一个时刻非常方便地使用这些数据. ---<Java编程思想> 其实注解可以理解为一个工具类,只要使用了这个工 ...
- java编程思想
Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而且在大型项目开发中也是常用的知识,既有简单的概念理 ...
- Java编程思想(11~17)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第十一章 持有对象 11.1 泛型和类型安全的容器>eg: List<St ...
- Java编程思想 (1~10)
[注:此博客旨在从<Java编程思想>这本书的目录结构上来检验自己的Java基础知识,只为笔记之用] 第一章 对象导论 1.万物皆对象2.程序就是对象的集合3.每个对象都是由其它对象所构成 ...
随机推荐
- 并发是个什么鬼之同步工具类CountDownLatch
扯淡 写这篇文章,我先酝酿一下,实不相瞒,脱离底层太久了,更确切的情况是,真没曾认真研究过.就目前来说,很多框架包括工具类已经把实现封装的很深,你只需轻轻的调用一下API,便不费半点力气.以至于大家会 ...
- 又一流氓推广Microsoft Edge,我勒个去
最新的Windows10 的升级也是醉了,不得不吐槽一个非常流氓的浏览器推广:Microsoft Edge(这小婊砸). 为了将之前的历史包袱IE干掉,这次微软也是蛮拼的,直接把IE从电脑里干掉了,你 ...
- Spring Security学习笔记
Spring Web Security是Java web开发领域的一个认证(Authentication)/授权(Authorisation)框架,基于Servlet技术,更确切的说是基于Servle ...
- Django创建博客
拜读http://www.cnblogs.com/fnng/p/3737964.html 后自操作步骤,mark一下 我的想法: modles.py中只负责添加类,定义数据结构,至于将该类添加到adm ...
- 对 响应数据写在config文件的再次优化
之前写过 [基于moco的mock server 简单应用]这篇文章,然后自己这段时间也在做基金的接口测试,逛了一些论坛,然后对 响应数据写在config文件的再次优化,之前是把所有的响应数据都写到c ...
- 深入浅出数据结构C语言版(16)——插入排序
从这一篇博文开始,我们将开始讨论排序算法.所谓排序算法,就是将给定数据根据关键字进行排序,最终实现数据依照关键字从小到大或从大到小的顺序存储.而这篇博文,就是要介绍一种简单的排序算法--插入排序(In ...
- 从源码分析java.lang.String.isEmpty()
今天在写代码的时候用到了java.lang.String.isEmpty()的这个方法,之前也用过,今天突发奇想,就看了看源码,了解了解它的实现方法,总结出来,大家可以交流交流. 通常情况下,我们使用 ...
- input[type="button"]与<button>的区别
<button>标签 浏览器支持 所有主流浏览器都支持<button>标签. 重要事项:如果在HTML表单中使用button元素,不同的浏览器会提交不同的值.IE将提交& ...
- poj2942(双联通分量,交叉染色判二分图)
题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1.2.总人数为奇数.3.有仇恨的骑士不能挨着坐.问有几个骑士不能和任何人形成任何的圆圈. 思路:首先 ...
- jQuery插件——ajax
一.ajax请求 1.load(url, [data], [callback]) 概述:加载远程的HTML文件代码,并插入到指定的DOM节点中. 参数:url:待装入 HTML 网页网址. data: ...