運(yùn)行時的類型信息使得你可以在程序運(yùn)行時發(fā)現(xiàn)和使用類型信息
- 為什么需要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");
}
}
}
面向?qū)ο缶幊痰幕灸康氖牵鹤尨a只操縱對基類引用。在這個例子的School接口中動態(tài)的綁定了draw()方法,目的就是讓程序員使用泛化的School引用來調(diào)用getName()方法
因此:它解放了程序在編期間執(zhí)行的面向類型的操作,不管是程序的安全性還是可擴(kuò)展性和可維護(hù)性,都得到了大大的加強(qiáng)。
- Class對象
Class對象是RTTI在Java中工作機(jī)制的核心。Java程序是由一個一個的類組成的。而對于每一個類,都有一個class對象與之對應(yīng),所有的類都是在對其第一次使用時,動態(tài)的加載到JVM中去的。當(dāng)程序創(chuàng)建第一個對類的靜態(tài)成員時用時,就會加載這個類,這個也證明構(gòu)造器也是類的靜態(tài)方法
類加載器首先檢查這個類的Class對象是否已經(jīng)加載,如果未加載。默認(rèn)的類加載器就會根據(jù)累嗎查找.class文件,一旦某個類的Class對象被載入內(nèi)存,它就被用來創(chuàng)建這個類的所有對象
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());//產(chǎn)生類名
System.out.println("getCanonicalName\t"+c.getCanonicalName());//產(chǎn)生全限定的類名 包括包名
}
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("這個類未發(fā)現(xiàn)");
}
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>注意如果把默認(rèn)的構(gòu)造器注釋掉,則會出現(xiàn)java.lang.InstantiationException 錯誤,因?yàn)樾枰@個默認(rèn)的構(gòu)造器創(chuàng)建對象</b>
例子中有三種獲得Class對象的方法:
Class.forName();最簡單的,也是最快捷的方式,因?yàn)槲覀儾⒉恍枰獮榱双@得class對象而持有該類的對象實(shí)例。
obj.getClass;當(dāng)我們已經(jīng)擁有了一個感興趣的類型的對象時,這個方法很好用
obj.class;類字面常量,這種方式很安全,因?yàn)樗诰幾g時就會得到檢查(因此不需要放到try語句塊中),而且高效。
- 類型轉(zhuǎn)換前先做類型的檢查
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一個類的實(shí)力上時,可以用.isInstance()和instanceof 方法
instanceof運(yùn)算符 只被用于對象引用變量
Class類的isInstance(Object obj)方法,obj是被測試的對象,如果obj是調(diào)用這個方法的class或接口 的實(shí)例,則返回true。這個方法是instanceof運(yùn)算符的動態(tài)等價。
- 泛化的Class引用
Class引用總是指向某個Class對象,可以制造類的實(shí)例,并包含課可作用于這些實(shí)例的所有方法的代碼,還包含該類的靜態(tài)成員,因此,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;
}
}
如果希望稍微放松一些這種限制,應(yīng)該怎么辦呢?我們使用了通配符? 它是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));
}
}
- 反射,運(yùn)行時的類信息