• thinking in java笔记 14 类型信息


    ***识别对象和类的信息

       1 RTTI,它假定在编译时已知所有类型
       2 反射,它允许在运行时发现和使用类的信息

    ***RTTI
        RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
       1 传统的类型转换 如 (Shape)shape
       2 通过查询Class对象可以获得运行时所需的信息。
       3  if (pet instanceof Pet)
       4  if (pair.getKey().isInstance( pet ))
       
    ***Class对象
       java使用Class对象来执行其RTTI。每个类都有一个Class对象。JVM使用类加载器来生成这个类的对象。当程序创建第一个对类的静态成员的引用(包括构造器)时,动态加载到JVM中的。类加载器检查这个类的Class对象是否已经加载,如果没有,就根据类名查找.class文件。一旦某个类的Class对象被载入内存,就被用来创建这个类的所有对象。

        Class cls =Class. forName ( "typeinfo.Sport" );获得对Class对象的引用
       cls.getInterfaces () class类实现的接口列表
      cls.getSuperclass()    得到class类的父类
      cls.newInstance();    创建class类的实例,被创建的类必须具有无参数构造器
      baseType . isAssignableFrom (superClass) 判断superClass是否在baseType的类继承结构中
    ***获取Class引用
       1  Class. forName ( "typeinfo.Sport" );
      此方法可以获得对Class对象的引用。

       2 obj.getClass()
       若已有一个对象,可以用obj.getClass()得到Class的引用。

       3 Sport.class
       
    ***类字面常量
       用   Sport.class的形式获取Class的引用,简单、安全高效,编译时会进行检查。可以应用于类、接口、数组以及基本类型。且这种方式不会自动初始化该Class对象,初始化动作被延迟到了对静态方法或者非常数静态域进行首次引用时才执行。

    ***泛化的Class引用
             Class< Sport > cls1= Sport . class ;
       可在编译期进行类型检查。
        Class<BaseSport> cls1= Sport. class ; 错误
        Class<? extends BaseSport> cls1 =Sport. class //正确
         Class<?> cls1=Sport. class ;  //可接受任何类,与不用泛型的区别是此处为有意使用非具体类,而非失误。   

    ***instanceof与Class的等价性
        class Base {}
         class Derived extends Base {}
        instanceof Base true
    x instanceof Derived true
    Base.isInstance(x) true
    Derived.isInstance(x) true
    x.getClass() == Base.class false
    x.getClass() == Derived.class true
    x.getClass().equals(Base.class)) false
    x.getClass().equals(Derived.class)) true
    instanceof保持了类型的概念,指的是:你是这个类或者它的派生类吗?
    == equals指的是确切的类型

    ***反射
       在运行时获取类的信息,反射检查可用的方法,并返回方法名。
       RMI(远程方法调用):运行时获取类的信息的一个动机是希望提供在跨网络的远程平台上创建和运行对象的能力,它允许一个java程序将对象分布到多台机器上。
       Class类和java.lang.reflect;类库一起为反射的概念提供了支持,该类库包含Field Method Constructor类。
       使用含参构造函数初始化对象:
        Toy t=Toy. class . getDeclaredConstructor ( int . class ).newInstance(3);

    ***java反射机制
        JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 
       java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

    ***代理
       为了提供额外的操作而插入的用来代替“实际”对象的对象。这些操作通常涉及与实际对象的通信,代理通常充当中间人的角色。当需要将额外的操作从实际对象中分离到不同的地方,特别是当希望能灵活地从没有使用额外操作转换为使用它们,代理用处很大。

    ***动态代理
       它可以动态地创建代理并动态地处理对所代理方法的调用,在动态代理商所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。

    ***空对象
       引入空对象后,它可以接受传递给它的所代表的对象的消息,但返回表示“不存在对象”的值,因此,就可以假设所有对象都是有效的,避免每次去检查null。它最有用的地方在于它更靠近数据,因为对象表示的是问题空间内的实体。
        
    class Person {
    public final String first;

    public final String last;

    public final String address;

    // etc.
    public Person(String first, String last, String address) {
    this.first = first;
    this.last = last;
    this.address = address;
    }

    public String toString() {
    return "Person: " + first + " " + last + " " + address;
    }

    public static class NullPerson extends Person implements Null {
    private NullPerson() {
    super("None", "None", "None");
    }

    public String toString() {
    return "NullPerson";
    }
    }

    public static final Person NULL = new NullPerson();
    }


    ***接口与类型信息
    class B implements A {
    public void f() {
    }

    public void g() {
    }
    }

    public class InterfaceViolation {
    public static void main(String[] args) {
    A a = new B();
    a.f();
    // a.g(); // Compile error
    System.out.println(a.getClass().getName());
    if (a instanceof B) {
    B b = (B) a;
    b.g();
    }
    }
    }

       有时,需要让客户端程序员围绕接口A来编程,而非实体类B(B为不公开的类),需要将class B设为包访问权限。
       但不管是采用包访问权限,还是采用私有内部类,匿名内部类,都不能阻止使用反射来获取类的成员信息(包含private)。
       
       使用反射调用非public的成员和方法的过程如下:(final成员不可被修改,但不会报错)
    class WithPrivateFinalField {
    private int i = 1;

    private final String s = "I'm totally safe";

    private String s2 = "Am I safe?";

    private void getName() {
    System.out.println("test");
    ;
    }

    public String toString() {
    return "i = " + i + ", " + s + ", " + s2;
    }
    }

    public class ModifyingPrivateFields {
    public static void main(String[] args) throws Exception {
    WithPrivateFinalField pf = new WithPrivateFinalField();
    Field f = pf.getClass().getDeclaredField("i");
    f.setAccessible(true); // 修改访问权限
    f.setInt(pf, 47); // 修改数据
    System.out.println("f.get(pf): " + f.get(pf));

    Method m = pf.getClass().getDeclaredMethod("getName");
    m.setAccessible(true); // 修改访问权限
    m.invoke(pf); // 调用方法
    }
    }



  • 相关阅读:
    vue $refs的静态绑定使用与动态绑定使用
    net core中Vue.component单独一个文件不运行,不报错的处理
    C语言之指针基础
    C语言之指针函数
    指针强化
    C语言之指针数组
    C语言之数组
    C语言之数据类型
    C语言之内存管理
    C语言之流程控制
  • 原文地址:https://www.cnblogs.com/myparamita/p/2203980.html
Copyright © 2020-2023  润新知