zoukankan      html  css  js  c++  java
  • 《Java编程思想》笔记 第十四章 类型信息

    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域绝对安全,虽然会接受任何修改的尝试,但实际上不会发生任何修改。
  • 相关阅读:
    HTML 标签元素的 align 属性
    JS计算时间差值
    ICPC Southeastern Europe Contest 2019 BDFIJ
    ICPC Latin American Regional Contests 2019 EGIKLM
    UCF Local Programming Contest 2017 ABCDEFGHI
    Codeforces #631 Dreamoon Likes Coloring
    Problem Palindrome
    Problem Toki’s function
    UCF “Practice” Local Contest — Aug 25, 2018 Boots Exchange 水题
    UCF “Practice” Local Contest — Aug 25, 2018 Rummy Score
  • 原文地址:https://www.cnblogs.com/mibloom/p/9136496.html
Copyright © 2011-2022 走看看