类型信息

1.java如何在运行时识别对象和类的信息

  • "传统的"RTTI run-time type identification ,假设我们在编译时已经知道了所有类型,在编译的时候打开和检查.class文件

  • 反射机制,允许在运行时发现和使用类的信息,在运行的时候打开和检查.class文件

运行时的类型信息使得你可以在程序运行时发现和使用类型信息

2.Class对象

Class对象这个特殊对象,包含了类有关的信息

每个类都有一个Class对象,保存在编译后的同名的 .class文件中

名词

类加载子系统

原生类加载器

所有的类都是对其第一次使用的时候,动态加载到JVM中,当程序创建第一个对类的静态成员引用时,就会加载这个类

构造器也是静态方法,new 在创建类的新对象的时候,也会被当做对类静态成员的引用

java程序运行时,不是将所有的类全部加载,而是需要的时候才进行加载

static初始化是在类加载的时候进行的

无论何时,只要想在运行时使用类型信息,就必须首先获得恰当的Class对象的引用

如何获得Class对象的引用?

  • Class.forName("the class name"),不需要持有该类型的对象 就可以获得对象

  • T.class ,类字面常量 (注意,这个方法创建对Class对象的引用时,不会自动地初始化该Class对象)

  • Object.getClass(),拥有类型对象,直接使用方法获得

  • getSuperclass() ,拥有Class对象,直接查询基类

类的实际工作步骤

  • 加载,类加载器执行
  • 链接,验证类中字节码,静态域分配存储空间
  • 初始化,超类的初始化,执行静态初始化器和静态初始化块

初始化被延迟到对静态方法(构造器也是静态的)或者非常数静态域首次引用才执行

import java.util.Random;
/**
* ClassInitialization
* @@author thinking in java
* @@version 1.1
*/
class Initable{
// 编译器常量
static final int staticFinal=1;
// 不是编译器常量
static final int staticFinal2=ClassInitialization.rand.nextInt(1000);
static{
System.out.println("initializing Initable");
}
}
class Initable2{
static int staticNonFinal=2;
static{
System.out.println("initializing Initable2");
}
}
class Initable3{
static int staticNonFinal=3;
static{
System.out.println("initializing Initable3");
}
}
public class ClassInitialization{ public static Random rand=new Random(47); public static void main(String[] args) throws Exception{
// 使用.class获得类的引用不会引发初始化
Class initable=Initable.class;
System.out.println("after creating initable ref");
// static final 编译器常量,可以不对类进行初始化就可进行读取
System.out.println(Initable.staticFinal);
// 触发类的初始化
System.out.println(Initable.staticFinal2);
// static 或 final 在读取前必须进行链接(分配存储空间)和初始化(初始化存储空间)
System.out.println(Initable2.staticNonFinal);
// Class.forName() 立即进行初始化
Class initable3=Class.forName("Initable3");
System.out.println("after creating initable3 ref");
System.out.println(Initable3.staticNonFinal); }
}
/*output:
after creating initable ref
1
initializing Initable
258
initializing Initable2
2
initializing Initable3
after creating initable3 ref
3
*///:~

instanceof

返回一个布尔值,告诉我们对象是不是某个特定类型的实例

Class中还有一个方法

public boolean isInstance(Object obj);

反射

RTTI的限制,想知道某个对象的确切类型,有个限制,这个类型在编译时必须已知

获取某个不在程序空间的引用, Class.forName("com.mysql.cj.DriverManger");

或者从网络,磁盘的字节中获取一个代表类

Class类 和 java.lang.reflect类库 完整支持整个反射概念

  • Filed ,使用get ,set来 修改Field相关字段
  • Method , invoke()来实现方法调用
  • Constructor,构建新的对象

反射是用来支持其他创建动态代码会用到的特性(序列化、javaBean)

创建反射实例

// Class的newInstance()
Class<?> c=String.class;
Object str=c.newInstance(); // Class的Constructor对象,可以指定构造器来实现
Class<?> c=String.class;
Constructor constructor=c.getConstructor(String.class);
Object obj=constructor.newInstance("456");

获取构造器信息

Class类的getConstructor方法得到Constructor类的一个实例

而Constructor类有一个newInstance方法可以创建一个对象实例

// 类的所有公有构造器
public Constructor[] getConstructors() // 类的所有构造器
public Constructor[] getDeclareConstructors()

获取方法

获取某个Class对象的方法集合

// 返回类的公有方法,包含继承的公有方法数组
public Method[] getMethods() throws SecurityException // 返回类的所有方法,不包括由超类继承的方法
public Method[] getDeclareMethods() throws SecurityException // 返回一个特定的方法 public Method getMethod(String name,Class<?>...parameterTypes);

获取字段信息

// 返回一个字段域,记录了类和超类的公有域
public Filed[] getFields() // 记录类的全部域,以声明的成员变量,不能得到父类的成员变量
public Field[] getDeclareFields()

调用方法

// 函数原型
public Object invoke(Object obj,Object ...args)
throws IllegalAccessException, IllegalArgumentException,InvocationTargetException // 一个测试用例
public class test1 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
}
class methodClass {
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}

反射的优缺点

如果一个功能不用反射完成,就不要用反射

优点:

  • 可拓展性,可以使用全限定名来创建可拓展实例对象,使用来自外部的自定类

  • 类浏览器和可视化开发工具,idea,escipse 中的显示类提示,就是反射的应用

  • 调试器和测试工具,

缺点:

  • 性能开销,动态类型解析,JVM无法对代码进行优化,反射的效率较低

  • 安全限制,必须在没有安全限制的环境中运行

  • 内部暴露,反射代码破坏了抽象性

参考:

深入解析Java反射(1) - 基础(sczyh30)

Thinking in java

Java核心技术(卷-)

技术面试必备-CyC2018

类型信息(反射,RTTI)的更多相关文章

  1. Java类型信息(RTTI和反射)

    要想在IT领域站得住脚,必须得不断地学习来强化自己,但是学过的技术不实践很容易便被遗忘,所以一直都打算开个博客,来记录自己学的知识,另外也可以分享给有需要的人! 最近在学习反射,为了更好地理解反射,就 ...

  2. JAVA类型信息——反射机制

    JAVA类型信息——反射机制 一.反射机制概述 1.反射机制:就是java语言在运行时拥有的一项自我观察的能力,java通过这种能力彻底了解程序自身的情况,并为下一步的动作做准备. 2.反射机制的功能 ...

  3. 类型信息(RTTI和反射)——反射

    运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就来说说反射. 重点说说通过反射获取方法以及调用方法,即类方法提取 ...

  4. 类型信息(RTTI和反射)——RTTI

    运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就先来说下RTTI. 1.RTTI: RTTI:在运行时,识别一个 ...

  5. 【JavaSE】运行时类型信息(RTTI、反射)

    运行时类型信息使得你可以在程序运行时发现和使用类型信息.--<Think in java 4th> **** 通常我们在面向对象的程序设计中我们经常使用多态特性使得大部分代码尽可能地少了解 ...

  6. JAVA编程思想——类型信息(反射)

    一.反射与RTTI RTTI:这个类型必须在编译的时候已知或者存在,如果不知道对象的确切类型,RTTI可以告诉你. 反射(个人认为就是能够利用Class获取或者调用.class这个文件中的数据):当我 ...

  7. Java编程思想——类型信息(RTTI)

    一.概念 编译时已知的到所有的类型:就是在写代码阶段就确定是这个类型了,当运行程序的时候,类型是不可改变的 举例:List<String> str = new ArrayList();   ...

  8. Java类型信息之RTTI

    软件工程的一个核心问题就是软件的复用和扩展.面向对象思想通过封装,继承,派生等机制有效地解决了这个问题.但需求总是变幻莫测,不可琢磨,在面向对象这栋恢宏的大厦旁,还漂浮着一朵乌云,从而导致了RTTI的 ...

  9. Java编程思想学习笔记——类型信息

    前言 运行时类型信息(RTTI:Runtime Type Information)使得我们可以在程序运行时发现和使用类型信息. Java在运行时识别对象和类的信息的方式: (1)一种是RTTI,它假定 ...

随机推荐

  1. 【Vue】状态管理

    页面应用需要Vuex管理全局/模块的状态,大型单页面组件如果靠事件(events)/属性(props)通讯传值会把各个组件耦合在一起.因 此需要Vuex统一管理,当然如是小型单页面应用,引用Vuex反 ...

  2. Mysql表的对应关系

    表关系 一对一一张表中的一条记录与另一张表中最多有一条明确的关系:通常,此设计方案保证两张表中使用同样的主键即可假设一张学生表:id 姓名 年龄 性别 籍贯 婚否 住址那么姓名 年龄 性别 这种字段比 ...

  3. 从头学pytorch(十三):使用GPU做计算

    GPU计算 默认情况下,pytorch将数据保存在内存,而不是显存. 查看显卡信息 nvidia-smi 我的机器输出如下: Fri Jan 3 16:20:51 2020 +------------ ...

  4. 箭头函数的this指向问题-一看就懂

    OK,对于箭头函数的this 用一句话概括:箭头函数中的this指向的是定义时的this,而不是执行时的this. 如果上面这句话听的是懂非懂或者完全不懂的,没关系,下面会有案例讲解. 举个栗子 来看 ...

  5. [函数] PHP取二进制文件头快速判断文件类型

    一般我们都是按照文件扩展名来判断文件类型,但其实不太靠谱,因为可以通过修改扩展名来伪装文件类型.其实我们可以通过读取文件信息来识别,比如 PHP扩展中提供了类似 exif_imagetype 这样的函 ...

  6. DZ的CURD

    Discuz二次开发-MySQL插入数据(insert) DB::insert($tableName,$data,$flag); $tableName:表名 $data:插入数据,以字段为键值的关联数 ...

  7. List of common SCSI KCQs

    Category Key ASC ASCQ Error Condition No Sense 0 00 00 No error 0 5D 00 No sense - PFA threshold rea ...

  8. 预测球队比赛结果及利用pyinstaller打包文件

    一.预测乒乓球球队比赛成绩 1.乒乓球比赛规则 一局比赛:在一局比赛中,先得11分的一方为胜方:10平后,先多得2分的一方为胜方. 一场比赛:单打的淘汰赛采用七局四胜制,双打淘汰赛和团体赛采用五局三胜 ...

  9. 【Linux网络基础】TCP/IP协议簇的详细介绍(三次握手四次断开,11种状态)

    一.TCP/IP协议簇(DoD参考模型) 用于简化OSI层次,以及相关的标准. 传输控制协议(tcp/ip)簇是相关国防部DoD所创建的,主要用来确保数据的完整性以及在毁灭性战争中维持通信 是由一组不 ...

  10. webpack前端构建angular1.0!!!

    webpack前端构建angular1.0 Webpack最近很热,用webapcak构建react,vue,angular2.0的文章很多,但是webpack构建angualr1.0的文章找来找去也 ...