黑马程序员--高新技术(2)

来源:互联网 发布:卖狗狗的软件 编辑:程序博客网 时间:2024/05/17 06:28

http://edu.csdn.net/heima android培训http://edu.csdn.net/heima ; java培训期待与您交流!

JavaBean

IntroSpector内省,可以用来对JavaBean进行操作。

什么是JavaBean

JavaBean是一种特殊的java类,这个类中的方法名符合某种规则,类中的方法主要用于访问似有的字段。

使用JavaBean来操作的好处:

一个符合JavaBean的类可以当做普通类来操作,但把他当做JavaBean来操作会给我们带来一些方便。

而且在javaEE开发中经常都会要求用javaBean的操作。

JDK中提供了对javaBean操作的API,这套API就称为内省。

JavaBean的作用:

       如果要在两个模块之间传递信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用似有字段来存储,想要读取或设置这些字段的值,则需要通过一些相应的方法来访问。

如何获取JavaBean的属性?

JavaBean中的属性是根据setget方法来确定的,而不是根据成员变量来确定。

例如:Age-->如果第二个字母是小的,则把第一个字母变成小的-->age

       gettime()的属性名-->属性为time

       setTime()的属性名-->time

       getCPU()的属性名-->CPU

代码:

class Person{

       private int x;

       public int getAge(){

              return x;

       }

       public void setAge(int age){

              this.x = age;//注意:如果当做普通类,那么这个类中的属性就是x,如果当做JavaBean来操作,那这个类中的属性就是age

       }

}

 

PropertyDescriptor:对属性进行描述的类。

主要方法:

       getReadMethod():获得应该用于读取属性值的方法。

       getWriteMethod() 获得应该用于写入属性值的方法。

代码示例:

需求:用JavaBean的方式来读取一个类的属性。

知道属性名,然后可以获取这个属性的setgetmethod对象,并对属性进行设置和获取。

 

publicclass IntroSpectorTest {

    publicstaticvoid main(String[] args)throws Exception{

       ReflectPoint pt1 = new ReflectPoint(3,5);

      

       String propertyName = "x";

       //提供属性名将这个属性进行属性对象的封装,这个对象中提供了获取关于这个属性的setgetmethod对象。

       PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());

          

       //获取X属性的get方法。

       Method methodGetX = pd.getReadMethod();

       Object retVal = methodGetX.invoke(pt1);

       System.out.println(retVal);

      

       //获取X属性的set方法,并调用方法,设值。

       Object value = 6; //为什么是Object类型的?

      

       Method methodSetX = pd.getWriteMethod();

       methodSetX.invoke(pt1, value);

       System.out.println(pt1.getX());

    }

}

代码抽取:

可以将多行代码重构,抽取成一行代码。

步骤:SourceàExternalize Strings…来抽取。

 

还有一种方式能实现JavaBean的操作。(这种方式太麻烦,不建议使用。)

       采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性,在程序中把一个类当做JavaBean来看,就是调用IntroSpector.getBeanInfo方法,得到的Beaninfo对象封装了把这个类当做JavaBean看的结果信息。

类加载器

java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader。

类加载器也是java类,因为其他是java类的加载器本身也要被加载器加载,所以必定有一个加载器不是java类,这个加载器是BootStrap。

jar包:就是别人已经写好的类封装成的包,我们可以直接在网上下载。

Jrert.jar包:java系统提供的那些类通常都放在这个jar包中。

Classpath指定的jar或目录:平常我们写好的程序都是由AppClassLoader来加载。

Lib下的ext扩展包:我们可以把我们的一些jar包放到这个目录下,这样就可以被ExtClassLoader类加载器加载。

类加载器的委托机制:

java虚拟机要加载个类时,到底派出哪个类加载器去加载呢?

      首先当前线程的类加载器去加载线程中的第一个类

      如果类A中引用类Bjava虚拟机将使用加载类A的类加载器来加载类B

      还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又现委托给其上级类加载器。

      当所有父类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛给ClassNoFoundException

自定义自己的类加载器:

自定义的类加载器必须继承ClassLoader覆盖findClass()方法。

需求:编写一个对文件内容进行简单加密的程序。

类加载器是一个类,自定义加载器就是描述这个类。

获取类加载器。

package cn.itcast.p2.classloader;

publicclass ClassLoaderDemo {

    publicstaticvoid main(String[] args) {

       //获取加载本类的类加载器。

    System.out.println(ClassLoaderDemo.class.getClassLoader().getClass());//

       //结果为null,说明加载器System类的加载器不是java类。

       System.out.println(System.class.getClassLoader());

       //获取这个加载器的所有父类加载器。

       ClassLoader loader = ClassLoaderDemo.class.getClassLoader();

       while(loader!=null){

           System.out.println(loader.getClass().getName());

           //getParent()方法用于获取类加载器的父类加载器。

           loader = loader.getParent();

       }

       System.out.println(loader);

    }

}

 

动态代理

代理的作用?

       代理类中的每个方法都调用目标类的相同方法,并在调用方法时加上一些系统功能的代码。也就是说代理不仅完成了目标的功能还能添加一些其他功能。所以代理可以提供方便。

静态代理:就是需要自己手写代理类,这样比较麻烦。

动态生成代理类:

      要为系统中的各种接口的类增加代理功能,采用静态代理方式是很麻烦的,所以就有了动态代理。

JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用做代理类,即动态代理类。

JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用做具有相同接口的目标类的代理。

CGLIB库可以动态生成一个类的子类,一个类的子类也可以作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。

代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置添加上系统功能代码:

1、  在调用目标方法前。

2、  在调用目标方法后。

3、  在调用目标方法前后。

4、  在处理目标方法异常的cath块中。

AOP:面向方面编程。

Proxy类:Proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。‘

常见方法:

static Class<?>getProxyClass(ClassLoader loader,Class<?>... interfaces)

返回代理类的java.lang.Class对象,并向其提供类加载器和接口数组。

 

InvocationHandler类:

方法只有一个:

       Object  invoke(Object proxy,Method method,Object[] args)

在代理实例上处理方法调用并返回结果。

 

分析JVM动态生成的类:

1、创建实现了Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数。

2、编码列出动态类中的所有构造方法和参数签名。

3、编码列出动态类中的所有方法和参数签名。

4、创建动态类的实例对象。

创建动态类的实例对象:

        

要让JVM创建动态类其实例对象,需要提供哪些信息?(重点)

         三个方面:

1、   生成的类中有哪些方法,通过让其实现哪些接口的方式来告知。

2、   产生的类字节码必须有一个关联的类加载器对象。

3、   生成的类中的方法的

 

动态生成的类的内部代码:

         动态生成的类实现了Collection接口(可以实现若干个接口),生成的类有Collection接口中的所有方法和一个接收的InvocationHandler参数的构造方法。

InvocationHandler类:

方法只有一个:

       Object  invoke(Object proxy,Method method,Object[] args)

在代理实例上处理方法调用并返回结果。

 

分析InvocationHandler对象的运行原理:

Proxy构造方法接受一个InvocationHandler对象,接收有什么用,该构造方法在内部怎么实现?

         接收了InvocationHandler方法,那么生成的代理对象就可以调用InvocationHandler中的invoke()方法。

         该方法内部的实现也是平常的实现,接收一个参数并赋值给对象。实现代码如下:

                   InvocationHandler handler;

                   Public $Proxy0(InvocationHandler handler)

                   {

                            this.handler = handler;

}

生成的代理类中的所有方法的运行原理:比如size()方法。(重点难点)

         int size()

         {

                   return handler.invodk(this,this.getClass().getMethod(“size(),null);

}

Client程序调用objProxy.add(“abc”)方法所做的事:

Class Proxy$

{

         Add(Object obj)

         {

                   return handler.invoke(Object proxy,Method method,Object[] args);

                                     //三个参数分别是:objProxy对象,add方法,”abc”参数。

}

}

 

代码示例:

创建代理类,并调用代理类的方法:

 

publicclass ProxyTest {

    publicstaticvoid main(String[] args)throws NoSuchMethodException, Exception {   

       Collection proxy3 = (Collection)Proxy.newProxyInstance(

              Collection.class.getClassLoader(),//参数为实现接口的加载器。

              new Class[]{Collection.class},//参数产生代理类所实现的接口的class字节码。(数组)

              new InvocationHandler(){//实际参数为InvocationHandler的子类对象。

                  @Override

                  public Object invoke(Object proxy, Method method,

                         Object[] args)throws Throwable {//形式参数类型为:proxyMethod,Method方法的参数。

                     ArrayList target =newArrayList();

                     return method.invoke(target,args);//返回add方法对象调用的invoke()方法。

                  }

                 

              }

              );

       proxy3.add("zxx");//内部会调用InvocationHandler对象的invoke方法。

       proxy3.add("lhm");

       proxy3.add("bxd");

       System.out.println(proxy3.size());

       System.out.println(proxy3.size());

    }

 

}

对于从Object中继承的方法,只有hashCodeequalstoString这三个方法交给InvocationHandler方法来处理。

 

 

http://edu.csdn.net/heima android培训 http://edu.csdn.net/heima ; java培训期待与您交流!详细请查看http://edu.csdn.net/heima

原创粉丝点击