java学习笔记 --14-- 类型信息

Java / 2020-04-01

类型信息

java提供了两种在运行时识别类型信息的方式:

  • RTTI
  • 反射

RTTI

RTTI:Run-time type information
面向对象编程的基本目的:
让代码只操作对基类的引用

package com.company;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * @ClassName Test
 * @Description
 * @Auther liuxiansen
 * @Date 2020/3/29 8:55 上午
 **/
public class Test{

    public static void main(String [] args){

        List<Test1> list = new ArrayList<>();
        Collections.addAll(list,new Test2(),new Test3());

        Iterator<Test1> iterator = list.iterator();

        while (iterator.hasNext()){
            iterator.next().print();
        }
    }

}

interface Test1{
    void print();
}

class Test2 implements Test1{
    public void print(){
        System.out.println("this is Test2");
    }
}

class Test3 implements Test1{
    @Override
    public void print() {
        System.out.println("this is Test3");
    }
}

把Test2和Test3对象放进类型为Test1的容器中,Test2和Test3向上转型为Test1
当调用容器中的Test1的引用的时候又根据实现不同输出结果不同

使用RTTI可以知道接口引用所指的对象的具体类型,然后就可以对不同的实现进行不同的操作

Class对象

  • 要知道RTTI的工作原理,就需要先知道类型信息是怎么表现出来的
  • 每个类在编译的时候都会产生一个Class对象在.Class文件中
  • 为了生成这个对象,JVM将使用被称为“类加载器”的子系统
  • java采用动态加载的方式,new一个对象这个对象就会被挂在类加载器上
  • java不是程序启动的时候生成所有的对象并挂在类加载器上
    而是在运行过程中new一个对象的时候再把这个对象挂在类加载器上
  • java会检查摸个类的Class对象是否加载到类加载器上,如果没有加载,就查找.Class文件找到Class对象
  • 加载之后,Class对象在内存中,然后就用这个Class对象创建这个类的所有的对象

Class.forName方法:参数:类名,返回:类的引用

类字面常量

package com.company;
/**
 * @ClassName Test
 * @Description
 * @Auther liuxiansen
 * @Date 2020/3/29 8:55 上午
 **/
public class Test{
    public static void main(String [] args) throws ClassNotFoundException {
        System.out.println(Class.forName("com.company.Test2"));
        System.out.println(Test2.class);
        System.out.println(Test1.class);
        System.out.println(String.class);
    }

}

interface Test1{
    void print();
}

class Test2 implements Test1{
    public void print(){
        System.out.println("this is Test2");
    }
}

class Test3 implements Test1{
    @Override
    public void print() {
        System.out.println("this is Test3");
    }
}

使用.class比Class.forName更简单,而且不需要检查异常
同时.class也可用于接口,基本类型,数组

package com.company;
/**
 * @ClassName Test
 * @Description
 * @Auther liuxiansen
 * @Date 2020/3/29 8:55 上午
 **/
public class Test{
    public static void main(String [] args) throws ClassNotFoundException {
        System.out.println(Class.forName("com.company.Test2"));
        System.out.println(Test2.class.getSimpleName());
        System.out.println(Test2.class.getAnnotatedInterfaces());
        System.out.println(Test1.class);
        System.out.println(String.class);

        System.out.println(int.class);
        System.out.println(char.class);

        System.out.println(Boolean.TYPE);
        System.out.println(Character.TYPE);
        System.out.println(Integer.TYPE);
    }

}

interface Test1{
    void print();
}

class Test2 implements Test1{
    public void print(){
        System.out.println("this is Test2");
    }
}

class Test3 implements Test1{
    @Override
    public void print() {
        System.out.println("this is Test3");
    }
}

基本类型的.TYPE字段 = 对应包装类的.class
拿到对象的引用之后可以得到对象的父类,接口,类名等一些信息

使用.class创建对象的引用时不会初始化而是:

  • 加载:类加载器查找字节码
  • 链接:验证字节码,分配存储空间,解析这个类的其他所有引用
  • 初始化:如果有超类,对超类初始化

instanceof:X instanceof Y , 判断X是否是Y的子类

泛化Class引用

public static void main(String [] args) {
        Class<?> c = int.class;
    }

?表示任何事物
即使Class< ?>与Class是等价的,但Class< ?>是更好的,他表示你是选择了非具体的版本

public static void main(String [] args) {
        Class<? extends Number> c = int.class;
        c = double.class;
        c = float.class;
    }

结合extends关键字,表示一个范围,Number类的所以子类

  • 加入泛型语法是为了可以在编译器检查出错误

反射

用来检查可用的方法,返回方法名
RTTI:编译时检查.class文件查找类
反射:运行时打开和检查.class文件

类方法提取器

反射支持特性:对象序列化,JavaBean

public static void main(String [] args) {
        for(Method method : Test2.class.getMethods()){
            Matcher matcher = Pattern.compile("(.*)throws").matcher(method.toString());
            if(matcher.find()){
                System.out.println(matcher.group(1));
            } else {
                System.out.println(method.toString());
            }
        }
        for(Constructor constructor : Test2.class.getConstructors()){
            System.out.println(constructor.toString());
        }
    }

getMethods:返回类的所有方法的数组
getConstructors:返回类的构造器数组
使用正则表达式删除throws后面的内容

未完。。。