运行时的类型信息使得你可以在程序运行时发现和使用类型信息
- 为什么需要RTTI(Runtime Type Information)
public abstract class School {
String name;
public String getName(String name){
this.name = name;
System.out.println(this.getClass().getName()+name);
return this.name;
}
public abstract String toString();
}
public class Primary extends School{
@Override
public String toString() {
// TODO Auto-generated method stub
return "Primary";
}
}
public class University extends School{
@Override
public String toString() {
// TODO Auto-generated method stub
return "University";
}
}
import java.util.Arrays;
import java.util.List;
public class test {
public static void main(String[] args) {
List<School> school = Arrays.asList(new Primary(),new High(),new University());
for(School str : school){
str.getName("hello");
}
}
}
面向对象编程的基本目的是:让代码只操纵对基类引用。在这个例子的School接口中动态的绑定了draw()方法,目的就是让程序员使用泛化的School引用来调用getName()方法
因此:它解放了程序在编期间执行的面向类型的操作,不管是程序的安全性还是可扩展性和可维护性,都得到了大大的加强。
- Class对象
Class对象是RTTI在Java中工作机制的核心。Java程序是由一个一个的类组成的。而对于每一个类,都有一个class对象与之对应,所有的类都是在对其第一次使用时,动态的加载到JVM中去的。当程序创建第一个对类的静态成员时用时,就会加载这个类,这个也证明构造器也是类的静态方法
类加载器首先检查这个类的Class对象是否已经加载,如果未加载。默认的类加载器就会根据累吗查找.class文件,一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象
interface HasBatteries{}
interface WaterProof{}
interface Shoots{}
class Toy{
Toy(int i){
}
}
class FancyToy extends Toy implements HasBatteries,WaterProof,Shoots{
//FancyToy(){}
FancyToy(int i){super(i);}
}
public class ToyTest {
static void printInfo(Class c){
System.out.println("class name is \t"+c.getName()+"\tis intercace?"+c.isInterface());
System.out.println("getSimpleName:\t"+c.getSimpleName());//产生类名
System.out.println("getCanonicalName\t"+c.getCanonicalName());//产生全限定的类名 包括包名
}
public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
Class cc= null;
try{
cc = Class.forName("FancyToy");
}catch(ClassNotFoundException ex){
throw new ClassNotFoundException("这个类未发现");
}
System.out.println(cc);
for(Class c : cc.getInterfaces()){
System.out.println(c);
}
Class up = cc.getSuperclass();//得到基类
Object obj = null;
try {
obj = up.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
printInfo(obj.getClass());
}
}
<b>注意如果把默认的构造器注释掉,则会出现java.lang.InstantiationException 错误,因为需要这个默认的构造器创建对象</b>
例子中有三种获得Class对象的方法:
Class.forName();最简单的,也是最快捷的方式,因为我们并不需要为了获得class对象而持有该类的对象实例。
obj.getClass;当我们已经拥有了一个感兴趣的类型的对象时,这个方法很好用
obj.class;类字面常量,这种方式很安全,因为它在编译时就会得到检查(因此不需要放到try语句块中),而且高效。
- 类型转换前先做类型的检查
class A{
}
class B extends A {
}
class C extends B {
}
public class IsInstance {
public static void main(String[] args) {
// TODO Auto-generated method stub
C c = new C();
B b = new B();
A a = new A();
B bc = new C();
A ac = new C();
System.out.println(c instanceof C);
System.out.println(c instanceof B);
System.out.println(c instanceof A);
System.out.println();
System.out.println(c.getClass().isInstance(c));
System.out.println(c.getClass().isInstance(b));
System.out.println(c.getClass().isInstance(a));
System.out.println();
System.out.println(c.getClass().isInstance(bc));
System.out.println(c.getClass().isInstance(ac));
System.out.println();
System.out.println(A.class.isInstance(a));
System.out.println(A.class.isInstance(b));
System.out.println(A.class.isInstance(c));
System.out.println(A.class.isInstance(ac));
System.out.println(A.class.isInstance(bc));
System.out.println();
System.out.println(B.class.isInstance(a));
System.out.println(B.class.isInstance(b));
System.out.println(B.class.isInstance(c));
System.out.println(B.class.isInstance(ac));
System.out.println(B.class.isInstance(bc));
}
}
需要判断一个对象是否his一个类的实力上时,可以用.isInstance()和instanceof 方法
instanceof运算符 只被用于对象引用变量
Class类的isInstance(Object obj)方法,obj是被测试的对象,如果obj是调用这个方法的class或接口 的实例,则返回true。这个方法是instanceof运算符的动态等价。
- 泛化的Class引用
Class引用总是指向某个Class对象,可以制造类的实例,并包含课可作用于这些实例的所有方法的代码,还包含该类的静态成员,因此,Class引用表示的就是他所指的对象的确切的类型,而该对象便是Class的一个对象
public class Generic_1 {
public static void main(String[] args) {
Class initClass = int.class;
Class<Integer> generClass = int.class;
generClass = Integer.class;
initClass = double.class;
}
}
如果希望稍微放松一些这种限制,应该怎么办呢?我们使用了通配符? 它是java泛型的一部分
import java.util.ArrayList;
import java.util.List;
class CounterInteger{
private static long couter;
private final long id = couter++;
public String toString(){
return Long.toString(id);
}
}
public class FilledList<T> {
private Class<T> type;
public FilledList(Class<T> type){
this.type = type;
}
public List<T> create(int ele){
List<T> result = new ArrayList<T>();
try{
System.out.print(type.newInstance() instanceof CounterInteger);
for(int i=0;i<ele;i++){
result.add(type.newInstance());
}
}catch(Exception ex){
throw new RuntimeException();
}
return result;
}
public static void main(String[] args) {
FilledList<CounterInteger> list = new FilledList<CounterInteger>(CounterInteger.class);
System.out.println(list.create(10));
}
}
- 反射,运行时的类信息
网友评论