类型信息

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

  • 为什么需要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 = 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());
    }
}

注意如果把默认的构造器注释掉,则会出现java.lang.InstantiationException 错误,因为需要这个默认的构造器创建对象
例子中有三种获得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 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 {
    private Class type;
    public FilledList(Class type){
        this.type = type;
    }
    public List create(int ele){
        List result = new ArrayList();
        try{
            System.out.print(type.newInstance() instanceof CounterInteger);
            for(int i=0;i list = new FilledList(CounterInteger.class);
         System.out.println(list.create(10));
    }
}
  • 反射,运行时的类信息

你可能感兴趣的:(类型信息)