第14章-类型信息

首先,知道一种区别:

  编译时可操作类型信息;

  运行时识别类型信息{1-RTTI;2-反射机制};

RTTI:在运行时,识别对象的类型。

1-运行时类型识别的必要性:

  多态中,向上转型,动态绑定的场景,方法和方法体在运行时才关联起来。

接口类引用=具体对象;

接口类引用.function();运行时识别具体对象类型,方法动态绑定。

从数组中取出数据时,数组将所有事物当成Object类型,会自动转型成对应类型,这是RTTI最基本的使用形式

所有的类型转换,都是在运行时进行正确性检查。

抛出问题:怎样知道泛化引用的确切类型?

使用RTTI可以知道。

2-Class对象

类型信息在运行时如何表示?--->由Class对象来表示--包含类信息的对象。

Class对象作用:1.用来创建类的所有常规对象。

         2.RTTI.

每个类都有一个Class对象,编写并且编译了一个新类,就会产生一个Class对象,保存在.class文件中。

jvm使用-类加载器-生成-Class对象。

所有类的加载,是在其第一次被使用时,动态加载到jvm.

创建第一个对类的静态成员的引用时,就会加载这个类。因此可以知道:构造器也是类的静态方法,即使没有static关键字。因此,使用构造方法也是对类的静态成员的引用。

java程序在运行前并非完全加载完毕,而是“按需加载”。

当把Class对象加载到内存,便可用它来创建类的所有对象。

Class.forName()-----获取Class对象的引用,若没被加载则加载。

必须先获取Class对象的引用,才能在运行时获取类型信息。

获取Class对象的引用3种方法:

(1) Class.forName()----不需要具体对象就可以获取Class对象的引用;

(2) 具体对象.getClass()-----也可以获取Class对象的引用;

(3) 类字面常量:ClassName.class;简单安全高效,注意:不会自动初始化该类。  也就是说,static final 常量 不会初始化类,也即  不用初始化类就可以获取其值。static final 非常量则会初始化类。

Class对象有一些有用的方法:getName();getSimpleName();getSuperclass();

加载:类的加载是指把.class文件中的二进制数据读入到内存中,把他放在运行时的数据区的方法区内,后在堆区创建一个Class的对象。

java虚拟机可以从多种来源加载类的二进制数据,
a) 从本地文件系统中加载类的.class文件,常用的方式
b) 通过网络下载.class文件
c) 从ZIP、JAR或其他类型提取.class文件
d) 从一个专有数据库中提取.class文件
e) 把一个Java源文件动态编译为.class文件

初始化:为类的静态变量赋予正确的初始值,执行静态块。若有超类则对其进行初始化。

  易混点:1.对类的静态变量赋予正确的初始值,执行静态块,是在初始化时进行的,并非是在类加载时执行的。

      2.初始化!=实例化

3-泛化的Class引用

对Class对象的类型进行限定,提供编译期类型检查---用到泛型。--通过泛型可以让编译器强制执行额外的类型检查。--若想放松该限制,可用通配符“?”。

java泛型的通配符“?”表示任何事物。

Class<?>优于普通的Class,前者表明是我明确选择了非具体类型,不是碰巧和疏忽。

 Class<? extends SuperClass>   ---SuperClass的任何子类。

 Class<? super sonClass>          ---sonClass的任何超类。

可以使用Class引用来创建类的实例。方法:newInstance().

易错点:该类必须与它一同工作的任何类都有一个无参构造器。否则会运行时异常。

RTTI在Java中的三种存在形式:

1,经典造型,首字母大写的类型名,如“Shape”,它用RTTI确保造型的正确性。

2,代表对象类型的Class对象。可查询Class对象,获取有用的运行期资料。 

3.,instanceof 告诉我们对象是不是一个特定类型的实例。

类型转换前先做检查---instanceof : 只可与类型名称进行比较,不可与Class对象做比较。

动态的instance----isInstance(obj) : 动态体现在哪里???

instanceof与Class的等价性:

区别:

a)直接判断Class对象;                            ---比较实际的Class对象,未考虑继承关系。

b)使用instanceof或isInstance()判断对象。--考虑了继承关系。

例子:

x.getClass()==y.getClass();

x instanceof y

class Xx{}
class Yy extends Xx{}
public class Bj {
public static void main(String[] args) {
System.out.println(new Xx().getClass()==new Yy().getClass());
System.out.println(new Xx().getClass().equals(new Yy().getClass()));
System.out.println(new Yy() instanceof Xx);
System.out.println(Xx.class.isInstance(new Yy()));
}
}

4-反射

---使用反射机制,可以在运行时通过类名获得类信息;通过对象获得对象信息。

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意方法和属性;

这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

Class类与java.lang.reflect类库共同对反射概念进行了支持。

该类库包含了Field,Method,Constructor类。

这些类型的对象由jvm在运行时创建,用以表示未知类里对应的成员。

Constructor---创建新对象,

get()与set()--获取和修改与Field对象关联的字段,

invoke()------调用与Method对象关联的方法。

反射与RTTI区别:  反射比RTTI更懒。

RTTI:在编译时打开和检查.class文件;

反射:在运行时打开和检查.class文件。

{动态语言,静态语言}---划分---:在运行时是(动态)否(静态)可以改变程序的结构和变量类型。

用点菜的例子比喻反射和RTTI:
反射:菜单(.class文件),点菜记录表。我在点菜记录表上手写的菜名,在菜单上可以找到,在记录表内我可以动态得写下菜名;

RTTI:直接在菜单(.class文件)上勾出你想点的菜。

Class.forName()-----生成的结果在编译时是未知的,所有信息实在执行时被提取出来。

通过反射机制,可以创建编译时完全未知的对象,并调用此对象的方法。

5-动态代理

代理:中间人。不直接操作实现对象,通过代理对象间接操作实现对象。

实现对象--也称被代理对象。

动态代理:动态体现在{1.动态创建代理对象;2.动态调用方法}

Proxy.newProxyInstance(); 创建动态代理对象

实现InvocationHandler调用处理器接口,重写invoke(),将请求发送给被代理对象,并传入必要参数。

原文地址:https://www.cnblogs.com/mjbenkyo/p/9226953.html