• 第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(),将请求发送给被代理对象,并传入必要参数。

  • 相关阅读:
    Redis学习笔记(九、Redis总结)
    菜鸟刷面试题(二、RabbitMQ篇)
    RabbitMQ学习笔记(八、RabbitMQ总结)
    MongoDB学习笔记(七、MongoDB总结)
    菜鸟刷面试题(一、Java基础篇)
    朋友圈点赞
    队列变换
    犯二的程度
    猴子选大王
    最大销售增幅
  • 原文地址:https://www.cnblogs.com/mjbenkyo/p/9226953.html
Copyright © 2020-2023  润新知