java的类型信息在运行时如何表示?

        通过Class对象,class类是程序运行期间,为所有的对象维护一个运行时的类型标识,保存这些信息的类被称为class。

        如何获取类的class对象引用?

        1. Class.forName();forname是Class类的静态方法。

        2. 如果已经有一个对象,可以调用对象的getClass(),此方法属于根类object。

        3. 使用类字面常量.class;不仅可以用于普通的类,还可以用于接口,数组,以及基本数据类型。

       注意,一个class对象表示一个类型,未必一定是一种类。如Class c = int.class,c不是类,但是一个class类型对象。

        

        .class和forName()的区别:

        通过.class得到Class对象引用,不会触发类的初始化,而使用forName()会使类进行初始化。

        

        Class类是泛型的。我们可以用泛型语法,让编译器进行额外的类型检查。

        如 Class<?> intClass = int.class;    

            Class<House> houseType = House.class;

        我们可以根据得到的class引用,判断一个对象obj是不是某个Class类型的实例(如类名为Base)。

        1. obj instanceof Base

        2. Base.class.isInstance(obj)

        instanceof 和isInstance都保持了类型的概念,即可以识别出继承的关系。

        区别:isInstance是instanceof的动态实现

        对obj.instanceof(Class),在编译时编译器需要知道类的具体类型

        对Class.isInstance(obj),编译器在运行时才进行类型检查,故可用于反射,泛型中 

    class Father{}
   class Son extends Father{}

   public class InstantTest{
       public static boolean DynamicEqual(Object fatherObj,Object sonObj){
           return fatherObj.getClass().isInstance(sonObj); // true
           // return sonObj instanceof Father; // true,Father是一个具体的Class类型
           // return sonObj instanceof (fatherObj.getClass()); //编译错误,编译时编译器需要知道Class的具体类型
       
}
       public static void main(String[] args){
           //same using
           
Father father = new Father();
           Son son = new Son();
           System.out.println(son instanceof Son); // true
           
System.out.println(son instanceof Father); // true
           
System.out.println(son instanceof Object); // true
           
System.out.println(null instanceof Object); // false
           
System.out.println();

           System.out.println(Son.class.isInstance(son)); // true
           
System.out.println(Father.class.isInstance(son)); // true
           
System.out.println(Object.class.isInstance(son)); // true
           
System.out.println(Object.class.isInstance(null)); // false
           
System.out.println();
           //different using
           
System.out.println(DynamicEqual(father, son));
       }
   }

        若我们想要在运行时获取类的信息呢?在编译时不能确定需要的是哪个类,所以类名.class和obj.getClass()是显然不好用的。

        Java反射机制主要提供了以下功能: 

        在运行时判断任意一个对象所属的类;

        在运行时构造任意一个类的对象;

        在运行时判断任意一个类所具有的成员变量和方法;

        在运行时调用任意一个对象的方法;

        生成动态代理。

        Class类与java.lang.reflect类库一起对反射的概念进行了支持

        

        在Class类中:

        Static Class forName(String className)可以得到该类型的对象引用

        Object newInstance()创建该类型实例

                默认使用类的无参数构造器,如果创建有参数实例,需要先调用getConstructors(),得到一个Constructor构造器的实例。

                Eg.e.getClass().newInstance()    

                    e.getConstructor(String.class).newInstance(“233”)

        Field[] getFields()

        Method[] getMethods()

        Constructor[] getConstructors()

        

        java.lang.reflect类库中有三个类:
        Field:描述类的域

        Method:描述类的方法

        Constructor:描述类的构造器

        在Method类中:

            Public Object invoke(Object implicitPara,Object[] explicitPara) 调用任意方法。

        通过这些类库中类的方法可以实现动态获取类型信息。


        代理是基本的设计模式之一,代理通常充当着中间人的身份。一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

        静态代理:写在代码里,通过中间类去操作实际类,也就是被代理的类

        动态代理:动态地创建代理,动态地实现对实际类的调用。

        反射和java.lang.reflect.Proxy等相关类实现了动态代理


        动态代理分为3个步骤:

            1. 建立委托类,即被代理的类,包括Interface接口和实现类;

            2. 创建实现了InvocationHandler接口的代理类,在invoke()内执行代理操作;

            3. 创建委托类对象

            4. 创建代理类对象

            5. 创建动态代理,通过调用proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

                这个方法需要三个参数:

                        1. ClassLoader loader指明生成委托类对象使用的类装载器

                        2. Class<?>[] interfaces指定代理器实现的接口列表

                        3. InvocationHandler接口的一个实现,就是代理类对象

        通过动态代理,不管调用代理对象的什么方法,都是调用代理器的invoke方法,在这里人为地决定了如何调用被代理对象的原始方法,如何进行额外的处理。相当于对被代理对象直接方法调用的拦截。


interface PersonDao {   //被代理的类的接口
   
public void say();
}  

class PersonDaoImpl implements PersonDao{   //被代理的类
   
@Override
   
public void say() {
       System.out.println("这个方法被代理了");
   }
}

class PersonHandler implements InvocationHandler {  //代理类
   
private Object obj;
   public PersonHandler(Object obj){
       this.obj=obj;
   }
   @Override
   
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  //invoke方法实现代理的操作
       
System.out.println("before");
       Object result = method.invoke(obj, args);
       System.out.println("after");
       return result;
   }
}  

public class Test {
   public static void main(String[] args){
       PersonDao pDao = new PersonDaoImpl();       //创建被代理类对象
       
PersonHandler handler = new PersonHandler(pDao);    //创建代理类对象
       
PersonDao proxy = (PersonDao)Proxy.newProxyInstance(    //创建动态代理
               
pDao.getClass().getClassLoader(), //参数1:代理对象的类装载器
               
pDao.getClass().getInterfaces(),    //参数2:代理器实现的接口,即代理的方法列表
               
handler);   //参数3:代理类
       
proxy.say();
   }
}



执行结果

before

这个方法被代理了

after


这也是spring AOP的实现原理,但是有限制是被代理类必须是实现了一个接口,否则用第二种实现方式,CGLIB