1.RTTI:在运行时识别一个对象类型

  • JAVA在运行时 有时要 识别对象和类的信息这个机制叫RTTI。Java提供了两种机制去做这件事。传统的RTTI 和 反射。
  • 传统的RTTI  假定编译时就已经知道了所有的类型。
  • 反射   允许在运行时发现和使用类型信息
  • 传统的RTTI 在编译期通过Class文件识别类型信息,反射在运行期通过Class文件识别类型信息。
  1. Java类型转换都发生在运行时期。

2.Class对象

  • Class对象是由Class这个类产生的,它包含了与某个类有关的信息。
  1. 每个类都有Class对象,即编译了一个新类就会产生一个该类的Class对象,并且保存在.class文件中。Class对象就是用来产生“常规”对象的。
  2. Java使用Class对象来执行RTTI。
  3. 所有类都是第一次使用时动态加载到jvm中。 动态加载就是需要时再加载不使用不加载。
  4. 只要创建了对一个类的静态成员的引用就会加载该类。new 的时候加载类说明 类的构造器虽然没写static但也是静态方法。
  5. 一个类的Class对象载入内存后,他就会用来创建该类的对象。

2.1 获得Class对象

  1. Class类的静态方法forName()可以通过传入一个全限定类名(包含包名)返回一个该类的Class类对象引用,此时该类会被加载到内存。

    Class.forName("thinking14class.Test")
  2. 运行时要获得一个类的信息(类型信息)可以通过一个该类的Class对象获得,使用Class.forName()就可以做到,而不必持有该类型的对象通过该对象获得。
  3. 如果有了一个实例对象可以调用getClass()方法来获得Class对象。

2.2 Class类的一些方法

  1. getName() 获得全限定类名, getCanonicalName()也是获得全限定类名。对于普通类来说,二者没什么区别,只是对于特殊的类型上有点表示差异。
  2. getSimpleName()只获得类名,没有包名。
  3. isInterface()判断是否为接口。
  4. getInterfaces() 返回一个Class对象数组,数组元素是该类实现的接口,元素顺序和实现顺序一致。
  5. getSuperclass() 返回直接基类(不是接口)的Class对象,可以用来发现对象完整的类继续结构。
  6. newInstance()创建该类实例对象并返回,但该类必须要有默认构造器,这个方法相当于一个虚拟构造器。

3.类字面常量

  • 类名.class 就是字面常量,代表的就是该类的Class对象引用。常量需要赋值给变量
  1. 简单,安全。 编译期接受检查,不需要像forName一样至于try/catch块中。
  2. 加载后不会进行初始化,初始化被延迟到静态方法静态域首次使用时。
  3. 类字面常量可用于 类 接口 数组 基本数据类型
  4. 基本数据类型也有类字面常量如int.class, 对应的包装器的 Integer.TYPE。
            System.out.println(int.class); //int
    System.out.println(Integer.TYPE); //int
    System.out.println(Integer.class); //class java.lang.Integer
  5. Integer继承自Number 但 Integer Class 对象不是 Number Class对象的子对象,也就是说Class<Number> cn  = int.class; 是错误的。

4 泛化的class引用

  1. Class引用指向Class对象,该Class对象是Class类的实例,该对象可以制造一个类的实例,并包含一个类的各种信息。
  2. Class引用表示的就是Class对象的确切类型。
  3. Class<?> 优于Class 因为Class在编译期不会产生警告,而Class<?>当指向一个非具体的类引用时会产生警告。
  4. a.newInstance()如果Class引用a不是泛型引用,在编译期就不知道它会返回什么类型那么只能返回Object。
            Class a = A.class;
    Object t = a.newInstance();
    //A t = (A) a.newInstance();//无法确定类型需要强制转换
    System.out.println(t.getClass().getName());//thinking14class.A
  5. a.newInstance()  a 是泛型引用并且能确定类型则会返回确切的类型。
            Class <A> a= A.class;
    Class <? extends C> c= C.class; //上界
    Class <? super A> d= A.class;
    A ta = a.newInstance(); // 可以确定
    A tc = c.newInstance(); // 上界至少它是一个C可以确定
  6. a.newInstance()  a 是泛型引用但不能确定类型则只能返回Object。

            Class <A> a= A.class;
    Class <? extends C> c= C.class; //上界
    Class <? super A> d= A.class; //下界
    //A ta = a.newInstance(); // 通配符无法确定 A tc = c.newInstance(); // 上界至少它是一个C可以确定 //A td = d.newInstance();// 下界无法确定
  7. 利用Class类的cast()方法来转换类型
            A a  = new C();
    Class<C> cType = C.class;
    C c = cType.cast(a);
    c = (C) a; //与上一步一样的效果

6.类型转换前先做检查

  1. 传统的类型转换由RTTI确保正确性。
  2. instanceof关键字(二元操作符) ,返回一个Boolean值,告诉我们对象是不是某个类或该类派生类的实例,他判断的是类型。
    if (a instanceof A) //对象a是不是属于A类型,A可能是a父类的父类,如果是这样也返回true
  3. instanceof 不能比较Class对象,对于Class对象使用isAssignableFrom()判断
    if (as.isAssignableFrom(cs))// Class对象cs所在类是不是属于Class对象as所在类或者派生类 
  4. 动态的instanceof :Class对象的isInstance(Object o)方法判断该Class对象是不是o类的(如果o是class对象所在类则返回true,否则返回false哪怕o是所在类的父类)。
    if (cs.isInstance(c)) //如果c是class对象所在类则返回true,否则返回false,哪怕c是所在类的父类

7.反射

  • 反射机制:用来检查可用方法,并返回方法名。
  • Class类和java.lang.reflect类库对反射提供了支持 点击查看
  1. reflect包中有Field类,Method类,Constructor类,这些类对象由jvm在运行时创建,用来表示未知类里的字段,方法,构造器。
  2. 使用Constructor创建新对象,Filed的get() set()方法修改Filed对象关联的字段,Class类的invoke()调用Method关联的方法。
  3. 调用Class类的getFileds()返回表示字段的Filed数组,getMethods()返回表示方法的Method数组,getConstructor()返回表示构造器的Constructor数组。
  4. 通过以上方法一个匿名对象的类信息便可在运行时被确定下来,再在运行时通过.class文件获得相关信息构造该类。
  5. 没有任何方法可以阻止反射调用那些非公共访问权限的方法,哪怕是private方法或者private域。
package thinking14class;

import java.lang.reflect.Field;
import java.lang.reflect.Method; public class ReflectDemo { public static void main(String[] args) { Class<Student> class1 = Student.class;
Field[] field = class1.getFields(); //所有公共字段包括继承的,不包含 private 默认 权限的字段
Field[] fields = class1.getDeclaredFields();//所有字段,但不包括继承的方法 for (Field field2 : field) {
System.out.println(field2.getName());
} System.out.println("-------分割线1-------"); for (Field field2 : fields) {
System.out.println(field2.getName());
}
System.out.println("-------分割线2-------");
Method[] method = class1.getMethods(); //所有公共方法包括继承下来的 Method[] methods = class1.getDeclaredMethods();//包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法 for (Method method2 : method) { System.out.println(method2.getName());
} System.out.println("-------分割线3-------"); for (Method method2 : methods) {
System.out.println(method2.getName());
} } } class Student extends People{
public int id;
public String name;
private String sex; public String getSex() {
return sex;
}
private void setSex(String sex) {
this.sex = sex;
} } class People{ public String birthday; }

ReflectDemo

id
name
birthday
-------分割线1-------
id
name
sex
-------分割线2-------
getSex
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
-------分割线3-------
getSex
setSex

输出结果

8.动态代理

  • 设计模式一种

9.空对象

  • 设计模式一种

知识点:

  1. 如果某个对象出现在字符串表达式(涉及 + 和字符串对象的表达式)中,对象的toStrin()方法会自动调用,以生成对象的string。
  2. 接收常量要用变量,接收方法返回值也需要变量,但有时只需要方法调用的副作用,不用接收方法返回的结果。
  3. 若一个值是 static final 那么他就是编译期常量,该值不用初始化就可以通过类访问,访问时也不会引起初始化,如果是 static final 域则会初始化。

  4. final域绝对安全,虽然会接受任何修改的尝试,但实际上不会发生任何修改。

《Java编程思想》笔记 第十四章 类型信息的更多相关文章

  1. java编程思想第四版第十四章 类型信息习题

    fda dfa 第三题u package net.mindview.typeinfo.test4; import java.util.ArrayList; import java.util.Array ...

  2. java编程思想第四版第十四章 类型信息总结

    1. Class 对象: 所有的类都是在对其第一次使用的时候,动态加载到JVM中的.当程序创建第一个对类的静态成员的引用时,就会加载这个类.这说明构造器也是类的静态方法.即使在构造器之前并没有stat ...

  3. 《Thinking in Java》十四章类型信息_习题解

    1~10    Page 318 练习1. 在ToyTest.java中,将Toy的默认构造器注释掉,并解释发生的现象. 书中代码如下(略有改动): package org.cc.foo_008; p ...

  4. java编程思想笔记(1)

    java编程思想笔记(1) 一,对象的创建和生命周期 对象的数据位于何处?怎样控制对象的生命周期? 在堆(heap)的内存池中动态地创建对象. java完全采用了动态内存分配方式. 二,垃圾回收器 自 ...

  5. Java编程思想 笔记

    date: 2019-09-06 15:10:00 updated: 2019-09-24 08:30:00 Java编程思想 笔记 1. 四类访问权限修饰词 \ 类内部 本包 子类 其他包 publ ...

  6. 一起读《Java编程思想》(第四版)

    空余时间看<Java编程思想>(第四版)这本书,遇到不懂的知识点就记录在本博客内. 1.复用具体实现 Java代码复用的三种常见方式:继承.组合.代理. 1.继承:使用extends关键字 ...

  7. 20190908 On Java8 第十九章 类型信息

    第十九章 类型信息 RTTI(RunTime Type Information,运行时类型信息)能够在程序运行时发现和使用类型信息. Java 主要有两种方式在运行时识别对象和类信息: "传 ...

  8. 《Linux命令行与shell脚本编程大全》 第十四章 学习笔记

    第十四章:呈现数据 理解输入与输出 标准文件描述符 文件描述符 缩写 描述 0 STDIN 标准输入 1 STDOUT 标准输出 2 STDERR 标准错误 1.STDIN 代表标准输入.对于终端界面 ...

  9. #Java编程思想笔记(一)——static

    Java编程思想笔记(一)--static 看<Java编程思想>已经有一段时间了,一直以来都把笔记做在印象笔记上,今天开始写博客来记录. 第一篇笔记来写static关键字. static ...

随机推荐

  1. 一篇文章解决django中时区问题

    首先要明确的是,当在Django项目的setting.py文件中设置了USE_TZ=True时,我们给定的时间存储到数据库的时候都会变成UTC时间(使用auto_now_add和auto_now为Tr ...

  2. poj1200 字符串hash 滚动哈希初探

    假如要判断字符串A“AABA”是否是字符串B“AABAACAADAABAABA”的子串 最朴素的算法是枚举B的所有长度为4的子串,然后逐个与A进行对比,这样的时间复杂度是O(mn),m为A的长度,n为 ...

  3. 利用java中的BigInteger实现进制转换

    [原创] java中的进制BigInteger十分的强大,而且好用,他可以表示任意大的整数,同时还可以进行进制转换,十分的方便, 代码示例: package com.jiajia.demo_1; im ...

  4. SSH答疑解惑系列(三)——Struts2的异常处理

    Struts2的异常采用声明式异常捕捉,具体通过拦截器来实现. 在项目中,我们可以在Action中直接抛出异常,剩下的就交给Struts2的拦截器来处理了.当然,我们需要进行相关配置. Struts2 ...

  5. 【bzoj2326】[HNOI2011]数学作业 矩阵乘法

    题目描述 题解 矩阵乘法 考虑把相同位数的数放到一起处理: 设有$k$位的数为$[l,r]$,那么枚举从大到小的第$i$个数(即枚举$r-i+1$),考虑其对$Concatenate(l..r)$的贡 ...

  6. 【bzoj2287】[POJ Challenge]消失之物 背包dp

    题目描述 ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN. 由于她的疏忽, 第 i 个物品丢失了. “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢? ...

  7. 【bzoj2330】[SCOI2011]糖果 差分约束系统

    题目描述 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配 ...

  8. P1196 [NOI2002]银河英雄传说

    题目描述 公元五八○一年,地球居民迁至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压顶 ...

  9. [LINUX]警告:检测到时钟错误。您的创建可能是不完整的。

    [LINUX]警告:检测到时钟错误.您的创建可能是不完整的.   原因:     如果上一次编译时为20071001,你把系统时间改成20070901后再编译就会报这样的错误. 解决:     把时间 ...

  10. 【题解】APIO2007动物园

    首先一眼感受到这题特别的性质……5个?这么小的,感觉就像是状压.脑补了一下,如果没有环的话应该很好做吧……有环怎么办?5真的很小的,随便乱搞肯定也可以.那就放在外面暴力枚举吧.然后正解就出来了. 然而 ...