- 1 为什么需要RTTI(Run-Time Type Information)
- 2 Class对象
- 3 类型转换前先做检查
- 4 注册工厂
- 5 instanceof 与class的等价性
- 6 反射:运行时的类信息
- 7 动态代理
- 8 空对象
- 9 接口与类型信息
- 10 总结
本章主要学习如何让我么在运行时识别对象和类的信息的.主要有两种方式:一种是传统的RTTI它假定我们在编译时已经知道了所有的类型. 另一种是反射机制它允许我们在运行时发现和使用类的信息.
1 为什么需要RTTI
- RTTI :在运行时识别一个对象的类型
2.反射 允许在运行时发现和使用类型信息
3.传统的RTTI 在编译期通过Class文件识别类型信息,反射在运行期通过Class文件识别类型信息。
4.Java类型转换都发生在运行时期。
2 Class对象
Class对象是用来创建类的所有的"常规"对象的.java使用Class对象来执行其RTTI,即使你正在执行的是转型这样的操作.
Java使用Class对象来执行RTTI。
每个类都有Class对象,即编译了一个新类就会产生一个该类的Class对象,并且保存在.class文件中。Class对象就是用来产生“常规”对象的。
类加载器
所有类都是第一次使用时动态加载到jvm中。
动态加载就是需要时再加载不使用不加载。
只要创建了对一个类的静态成员的引用就会加载该类。new 的时候加载类说明
类的构造器虽然没写static但也是静态方法。因此,使用new操作符创建类的新对象也会被当作对类对静态成员对引用
一旦某个类的Class对象载入内存后,他就会用来创建该类的对象。
运行时要获得一个类的信息(类型信息)可以通过一个该类的Class对象获得,使用Class.forName()就可以做到,而不必持有该类型的对象通过该对象获得。
package typeinfo;
import static net.mindview.util.Print.print;
class Candy {
static {
print("Loading Candy");
}
}
class Gum { // 口香糖
static {
print("Loading Gum");
}
}
class Cookie {
static {
print("Loading Cookie");
}
}
public class SweetShop {
public static void main(String[] args) {
print("inside main");
new Candy();
print("After creating Candy");
try {
Class.forName("typeinfo.Gum"); // 与书有区别 typeinfo.Gum 全限定名 // 返回的是一个Class对象的引用
Class.forName("Gum"); // 如果获取失败会抛出异常 ClassNotFoundException
} catch (ClassNotFoundException e) {
print("Couldn't find Gum");
}
print("After Class.forName(\"Gum\")");
new Cookie();
print("After creating Cookie");
}
}
/*
inside main
Loading Candy
After creating Candy
Couldn't find Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
*/
如果有了一个实例对象可以调用getClass()方法来获得Class对象, 这个方法属于根类Object的一部分
Class包含很多有用的方法,下面是其中的一部分
getName() 获得全限定类名, getCanonicalName()也是获得全限定类名。对于普通类来说,二者没什么区别,只是对于特殊的类型上有点表示差异。
getSimpleName()只获得类名,没有包名。
isInterface()判断是否为接口。
getInterfaces() 返回一个Class对象数组,数组元素是该类实现的接口,元素顺序和实现顺序一致。
getSuperclass() 返回直接基类(不是接口)的Class对象,可以用来发现对象完整的类继续结构。
newInstance()创建该类实例对象并返回,但该类必须要有默认构造器,这个方法相当于一个虚拟构造器。
package typeinfo.toys;
import static net.mindview.util.Print.print;
interface HasBatteries{}
interface Waterproof{}
interface Shoots{}
class Toy{
// Comment out the following default constructor
// to see NoSuchMethodError from (*1*)
// Toy(){}
Toy(int i){}
}
class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{
FancyToy(){
super(1);
}
}
public class ToyTest {
static void printInfo(Class cc){
print("Class name: " + cc.getName() +
" is interface ? [" + cc.isInterface() +"]");
print("Simple name: " + cc.getSimpleName());
print("Canonical name: " + cc.getCanonicalName());
}
public static void main(String[] args) {
Class c = null;
try{
c = Class.forName("typeinfo.toys.FancyToy");
}catch (ClassNotFoundException e){
print("Can't find FancyToy");
System.exit(1);
}
printInfo(c);
for (Class face:c.getInterfaces())
printInfo(face);
Class up = c.getSuperclass();
Object obj = null;
try{
// Requires default constructor:
obj = up.newInstance();
}catch (InstantiationException e){
print("Cannot instantiate");
System.exit(1);
}catch (IllegalAccessException e){
print("Cannot access");
System.exit(1);
}
printInfo(obj.getClass());
}
}
/*
Class name: typeinfo.toys.FancyToy is interface ? [false]
Simple name: FancyToy
Canonical name: typeinfo.toys.FancyToy
Class name: typeinfo.toys.HasBatteries is interface ? [true]
Simple name: HasBatteries
Canonical name: typeinfo.toys.HasBatteries
Class name: typeinfo.toys.Waterproof is interface ? [true]
Simple name: Waterproof
Canonical name: typeinfo.toys.Waterproof
Class name: typeinfo.toys.Shoots is interface ? [true]
Simple name: Shoots
Canonical name: typeinfo.toys.Shoots
Cannot instantiate
*/