Java类型信息
来源:互联网 发布:事业单位考试视频软件 编辑:程序博客网 时间:2024/06/05 16:18
运行时识别对象和类的信息的两种方式:
- RTTI(Run-Time Type Identification)
- “反射“机制
RTTI的含义就是运行时识别一个对象的类型,类型信息是由Class对象表示的,每个Java里面的类都对应一个Class对象(在编写并且编译后),这个对象被保存在这个类的同名class文件里。为了生成Class对象,运行这个程序的Java虚拟机将使用“类加载器”子系统。
Class对象是由JVM加载的,所有的类都是在对其第一次使用时,动态加载到JVM。当程序创建第一个对类的静态成员的引用,就会加载这个类。使用new关键字创建类的新对象也会被当做对类的静态成员的引用。因此,Java程序在它开始运行之前并非完全被加载,其各个部分是在必须时才被加载的。所以在使用该类时,类加载器首先会检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件(编译后Class对象保存在同名的class文件中),当这个类的字节码文件被加载时,它们必须接受验证,以确保其没有被破坏,并且不包含不良Java代码(这是Java的安全机制检测),完全没问题后就会被动态加载到内存中,此时相当于Class对象被载入内存(.class字节码文件保存的就是Class对象),它就用来创建这个类的所有对象。
如果想要在运行时使用类型信息,就必须首先获得对恰当的Class对象的引用。
Class对象加载的时机
Class对象仅在需要的时候才被加载,static初始化是在类加载时进行的。
调用Class.forName(“全限定名”)将会导致类被加载,前提是该类从来没有被加载过。
获取Class对象引用的3种方法:
- Class cc=Class.fotName(“全限定名”);
- Class cc=object.getClass();
- FancyToy.class;//类字面常量
使用类字面常量生成对Class对象的引用相对前面两种方法更简单,更安全,因为它在编译期就会受到检查,并且由于无需调用forName()方法而更高效。使用.class来创建对Class对象的引用时,不会自动地初始化该Class对象。
使用类字面常量生成对Class对象的引用不仅可以应用于普通的类,还可以应用于接口、数组以及基本数据类型。对于基本数据类型对应的包装类,还有一个标准字段TYPE。TYPE字段是一个引用,指向对应的基本数据类型的Class对象。建议使用.class的形式,以保持与普通类的一致性。
boolean.class = Boolean.TYPE;char.class = Character.TYPE;byte.class = Byte.TYPE;short.class = Short.TYPE;int.class = Integer.TYPE;long.class = Long.TYPE;float.class = Float.TYPE;double.class = Double.TYPE;void.class = Void.TYPE;
为了使用类而做的准备工作实际包含3个步骤:
加载:由类加载器执行,查找此类字节码文件,并从这些字节码中创建一个Class对象
链接:在链接阶段将验证类中的字节码,为静态域分配空间,不包含实例成员变量,并且如果必需的话,将解析这个类创建的对其他类的所有引用
初始化:如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块
class Initable { //编译期静态常量 static final int staticFinal = 47; //非编期静态常量 static final int staticFinal2 = ClassInitialization.rand.nextInt(1000); static { System.out.println("Initializing Initable"); }}class Initable2 { //静态成员变量 static int staticNonFinal = 147; static { System.out.println("Initializing Initable2"); }}class Initable3 { //静态成员变量 static int staticNonFinal = 74; 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值是编译期常量,那么这个值不需要对Initable类进行初始化就可以被读取 System.out.println(Initable.staticFinal); //会触发类初始化 //如果只是将一个域设置为static final,还不足以确保这种行为,访问这个域将强制进行类的初始话 System.out.println(Initable.staticFinal2); //会触发类初始化 //如果一个static域不是final的,那么在对它访问时,总是要求它在被读取之前,要先进行链接(为这个域分配空间)和初始化(初始化该存储空间) System.out.println(Initable2.staticNonFinal); //forName方法获取Class对象 触发初始化 Class initable3 = Class.forName("Initable3"); System.out.println("After creating Initable3 ref"); System.out.println(Initable3.staticNonFinal); }}
执行结果:
After creating Initable ref47Initializing Initable258Initializing Initable2147Initializing Initable3After creating Initable3 ref74
泛化的Class引用
public class ClazzDemo {
public static void main(String[] args){ //没有泛型 Class intClass = int.class; //带泛型的Class对象 Class<Integer> integerClass = int.class; integerClass = Integer.class; //没有泛型的约束,可以随意赋值 intClass= double.class; //编译期错误,无法编译通过 //integerClass = double.class}
}
普通的类引用不会产生警告信息,尽管泛型类引用只能赋值为指向其声明的类型,但是普通的类引用可以被重新赋值为指向任何其他的Class对象,通过使用泛型语法,可以让编译期强制执行额外的类型检查。
//编译无法通过Class<Number> numberClass=Integer.class;//Integer继承自Number 但Integer Class 不是Number Class对象的子类
为了在使用泛化的Class引用时放松限制,可以使用通配符,它是Java泛型的一部分。通配符就是“?”,表示“任何事物”。因此可以在普通Class引用中添加通配符,并产生相同的结果。
Class<?> intClass=int.class;intClass=double.class;
这样的语句并没有什么问题,毕竟通配符指明所有类型都适用,那么为什么不直接使用Class还要使用Class
//编译通过Class<? extends Number> clazz=Integer.class;clazz=double.class;clazz.Number.class;
向Class引用添加泛型语法的原因仅仅是为了提供编译期类型检查,因此如果你操作有误,稍后立即就会发现这一点。
类型转换/Class引用的转型语法
cast()方法接收参数对象,并将其转型为Class引用的类型。
class Building{}class House extends Building{}public class ClassCasts{Building b=new House();Class<House> houseType=House.class;House h=houseType.cast(b);h=(House)b;}
关于instanceof 关键字,它返回一个boolean类型的值,意在告诉我们对象是不是某个特定的类型实例。如下,在强制转换前利用instanceof检测obj是不是Animal类型的实例对象,如果返回true再进行类型转换,这样可以避免抛出类型转换的异常(ClassCastException)
public void cast2(Object obj){ if(obj instanceof Animal){ Animal animal= (Animal) obj; }}
而isInstance方法则是Class类中的一个Native方法,也是用于判断对象类型的,看个简单例子:
public void cast2(Object obj){
//instanceof关键字
if(obj instanceof Animal){
Animal animal= (Animal) obj;
}
//isInstance方法 if(Animal.class.isInstance(obj)){ Animal animal= (Animal) obj; }
}
事实上instanceOf 与isInstance方法产生的结果是相同的。对于instanceOf是关键字只被用于对象引用变量,检查左边对象是不是右边类或接口的实例化。如果被测对象是null值,则测试结果总是false。一般形式:
//判断这个对象是不是这种类型
obj.instanceof(class)
而isInstance方法则是Class类的Native方法,其中obj是被测试的对象或者变量,如果obj是调用这个方法的class或接口的实例,则返回true。如果被检测的对象是null或者基本类型,那么返回值是false;一般形式如下:
//判断这个对象能不能被转化为这个类
class.inInstance(obj)
最后这里给出一个简单实例,验证isInstance方法与instanceof等价
class A{}class B extends A {}public class C { static void test(Object x) { print("Testing x of type " + x.getClass()); print("x instanceof A " + (x instanceof A)); print("x instanceof B "+ (x instanceof B)); print("A.isInstance(x) "+ A.class.isInstance(x)); print("B.isInstance(x) " + B.class.isInstance(x)); print("x.getClass() == A.class " + (x.getClass() == A.class)); print("x.getClass() == B.class " + (x.getClass() == B.class)); print("x.getClass().equals(A.class)) "+ (x.getClass().equals(A.class))); print("x.getClass().equals(B.class)) " + (x.getClass().equals(B.class))); } public static void main(String[] args) { test(new A()); test(new B()); } }Testing x of type class com.zejian.Ax instanceof A truex instanceof B false //父类不一定是子类的某个类型A.isInstance(x) trueB.isInstance(x) falsex.getClass() == A.class truex.getClass() == B.class falsex.getClass().equals(A.class)) truex.getClass().equals(B.class)) falseTesting x of type class com.zejian.Bx instanceof A truex instanceof B trueA.isInstance(x) trueB.isInstance(x) truex.getClass() == A.class falsex.getClass() == B.class truex.getClass().equals(A.class)) falsex.getClass().equals(B.class)) true
RTTI3种形式:
1传统的类型转换,由RTTI保证类型转换的正确性,如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常
2代表对象类型的Class对象
3关键字instanceof,告诉我们对象是不是某个特定类型的实例。
原文地址:http://blog.csdn.net/javazejian
- java类型信息
- Java 类型信息
- java基础-类型信息
- Java中的类型信息
- Java类型信息:RTTI
- java 类型信息
- java 类型信息 笔记
- Java类型信息
- Java 类型信息知识点
- Thinking in Java :类型信息
- java反射---获取类型信息
- java基础之类型信息
- thingking in Java 类型信息
- Thinking in Java -- 类型信息
- 理解Java的类型信息
- java学习笔记-----类型信息
- Java泛型中类型信息的擦除
- 《Java 编程思想》--第十四章:类型信息
- 顺时针打印矩阵
- 过滤器解决全站乱码
- 本地服务:无法访问此网站 localhost 拒绝了我们的连接请求。ERR_CONNECTION_REFUSED
- inline函数的一些总结
- Java NIO系列教程
- Java类型信息
- JS中数组的操作
- Spark App自动化分析和故障诊断
- sql
- 线程池的原理?
- 我是一个进程
- 《敏捷流程》---读书笔记
- hdu
- POJ 1873 The Fortified Forest 笔记