只想把基础打好之-类型信息

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

  1. 为什么需要RTTI(运行时类型信息):比如,我们使用```
    Interface inter=new InterfalceImp();
为了知道这个inter到底是哪个实现类型的实例来方便做对应的操作,例如,三角形是Shape的实现类型,圆也是Shape的实现类型,那我们要针对Shape做旋转操作,这就要判断shape倒底是什么类型的对象,因为对圆做旋转操作毫无意义。
2. Class对象:生成Class对象的引用:Class.forName("全类名")还有使用类字面量:ClassType.class。前一种会抛出异常(ClassNotFoundException),后一种不会。**当使用后一种来创建Class对象的引用时,不会自动地初始化该Class对象**,为了类的使用而做的准备工作有三个:1:加载,2:链接,3:初始化。初始化被延迟到了静态方法(构造器隐式地是静态的)或者非常数表态域进行首次引用时才执行:
```java
class Initable{
    static final int staticFinal=47;
    static final int staticFinal2=ClassTest.rand.nextInt(1000);
    // static final int staticFinal2=78;
    static {
        System.out.println("Initializing Initable");
    }
}
class Initable2{
    static int staticNotFinal=147;
    static {
        System.out.println("Initializing Initabl2");
    }
}
class Initable3{
    static int staticNotFinal=74;
    static {
        System.out.println("Initializing Initabl3");
    }
}
public class ClassTest {
    public static Random rand=new Random(47);
    public static void main(String[] args){
     Class initable=Initable.class;
     System.out.println("After creating Initable ref");
     System.out.println(Initable.staticFinal);
     System.out.println(Initable.staticFinal2);
     System.out.println(Initable2.staticNotFinal);

        try {
            Class initable3=Class.forName("classtest.Initable3");
            System.out.println("After Initable3 create ref");
            System.out.println(Initable3.staticNotFinal);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

运行结果:

After creating Initable ref
47
Initializing Initable
258
Initializing Initabl2
147
Initializing Initabl3
After Initable3 create ref
74

如果一个static不是final的,那么在对它访问时,总是要求在它读取之前,首先进行链接(为这个域分配存储空间)和初始化(初始该存储空间)。

  1. cast()转型:
interface Building{}
class House implements Building{}
public class ClassTest {
    public static void main(String[] args){
         Building building=new House();
         Class  houseType=House.class;
         House house=houseType.cast(building);
         //或者也可以这样
        house=(House) building;
    }
}

cast方法接受参数对象,它与上面main方法最后一行相比,做了很多额外的工作 。新的转型语法对于无法使用普通转型的情况显得非常有用,在你编写泛型代码时,如果你存储了Class引用,并希望以后通过这个引用来执行转型,这种情况就会发生。不过很少有用到,在JAVA SE5中另一个没有任何用处的新特性就是Class.asSubclass()。该方法允许你将一个对象转型为一个更具体的对象。

  1. 动态的instanceof:Class.isInstance方法提供了一种动态地测试对象途径。instanceof与isInstance保持了类型的概念,它指的是"你是这个类吗或是你是这个类的派生类吗?",而如果用==比较实际的Class对象,就没有考虑继承-它是不是影视个确切的类型。
    5.动态代理:代理是基本的设计模式之一,它是你为了提供额外的或不同操作,而插入的用来代替"实际"对象的对象。Java的动态代理比代理的思想更近一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理所做的调用都会被重定向到单一的调用处理器上。
interface Interface{
    void doSomething();
    void somethineElse(String string);
}
class DynamicProxyHandler implements InvocationHandler{
    private Object proxied;
    public DynamicProxyHandler(Object proxied){
        this.proxied=proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("*** proxy:"+proxy.getClass()+".method:"+method+".args:"+args);
        if(args!=null){
            for(Object arg:args){
                System.out.println(" "+arg );
            }
        }
        return method.invoke(proxied,args);
    }
}
class  RealObject implements Interface{

    @Override
    public void doSomething() {
        System.out.println("realobject doSomething");
    }

    @Override
    public void somethineElse(String string) {
System.out.println("realobject somethingelse:"+string);
    }
}
class SimpleDynamicProxy{
    public static void consumer(Interface iface){
        iface.doSomething();
        iface.somethineElse("kwkw");
    }
}
public class ClassTest {
    public static void main(String[] args){
RealObject real=new RealObject();
SimpleDynamicProxy.consumer(real);
Interface inter= (Interface) Proxy.newProxyInstance(
        Interface.class.getClassLoader(),new Class[]{Interface.class},new DynamicProxyHandler(real)
);
SimpleDynamicProxy.consumer(inter);
    }
}

运行结果:

realobject doSomething
realobject somethingelse:kwkw
*** proxy:class classtest.$Proxy0.method:public abstract void classtest.Interface.doSomething().args:null
realobject doSomething
*** proxy:class classtest.$Proxy0.method:public abstract void classtest.Interface.somethineElse(java.lang.String).args:[Ljava.lang.Object;@4dc63996
 kwkw
realobject somethingelse:kwkw

可以通过静态方法Proxy.newProxyInstance可以创建动态代理。

  1. 空对象:当使用内置的null表示缺少对象时,这显得枯燥。问题在于null除了在你试图用它执行任何操作来产生NullPointerException之外,它自己没有任何用处。你可以假设所有对象都是有效的,而不必浪费编程精力支检查null。
 interface Null{}
 class Person{
     public final String first;
     public final String second;
     public final String address;
     public Person(String first,String second,String address){
         this.first=first;
         this.second=second;
         this.address=address;
     }
     public static class NullPerson extends Person implements Null{
         private NullPerson(){
             super("None","None","None");
         }

     }
     public static final Person NULL=new NullPerson();
 }

你就可以使用Person.NULL来表示Person的空对象。也可以用Person.NULL来判断空对象了。空对象的逻辑变体是模拟对象与桩。但是模拟对象与桩都只是假扮可以传递实际信息的存活对象,而不是像空对象那样可以成为null更加智能化的替代物。

  1. 接口与类型信息:当我们用B继承A接口时,并不希望在使用"A a=new B()"初始a之后再将a向下转型为B的对象实体,这个时候你需要将限定的B的访问控制符,使得在访问控制以外的地方不能访问B,再提供一个public的初始化B的地方。但是我们通过反射任然可以访问这个B的信息。即使我们发布编译之后的文件,任然可以使用JDK自带的javap反编译。但是反射也带来它的好处。在类中留下后门这一事实,也许可以让你解决某些特定的问题。

你可能感兴趣的:(只想把基础打好之-类型信息)