黑马程序员_java基础加强2

本文详细解析了JavaBean的属性获取和内省操作,包括如何通过PropertyDescriptor类进行简单和复杂操作,以及注解、动态代理和Spring AOP框架的应用。重点介绍了JavaBean的属性访问规则、内省方法的使用,以及如何利用注解和动态代理实现增强功能。通过实例代码展示了如何在Java程序中灵活运用这些概念,以提升开发效率和代码质量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------- android培训java培训、期待与您交流! ---------- 

 

内省(javaBean)

javaBean是一种特殊的类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

javaBean的属性是根据方法名称来的。

JavaBean的属性名:去掉get set前缀。

EggetAge-->如果第二个字母是小写的,则把第一个字母变成小写的--->age;

getCPU--->如果第二个字母大写,第一个也大写

 对javaBean的简单的内省操作

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

             MethodmothodGetX=pd.getReadMethod();

             ObjectretVal=mothodGetX.invoke(pt1);

javaBean的复杂的内省操作

             BeanInfobeanInfo=Introspector.getBeanInfo(pt1.getClass());

             PropertyDescriptor[]pds=beanInfo.getPropertyDescriptors();

             ObjectretVal=null;

             for(PropertyDescriptorpd : pds){

                    if(pd.getName().equals(propertyName))

                           MethodmothodGetX=pd.getReadMethod();

                           retVal=mothodGetX.invoke(pt1);

                           break;

             }

             returnretVal;      

BeanUtils工具包

1)用BeanUtils类先get原来设置好的属性,再将其set为一个新值。

get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,通常使用字符串

2)用PropertyUtils类先get原来设置好的属性,再将其set为一个新值

get属性时返回的结果为该属性本来的类型,set属性时只接受该属性本来的类型

注解

Jdk1.5版本的新特性

一个注解就是一个类,相当于创建了类的实例对象

有三个主要的注解:

@Suppersswarnings()压缩警告

@Deprecated过时

@override覆盖

注解的作用:向工具软件传达一种信息

总结:

注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,标记可以加载包,类,字段,方法,方法的参数以及局部变量上。

1.元注解:注解的注解

2.注解的应用结构图

注解类

@interface{}

应用了“注解类”的类

@A

Class B{}

对“应用了注解类的类”进行反射操作的类

Class c

B.class.isAnnotionpresent(A.class)

Aa=B.class.getAnnotion(A.class)

总结:

根据反射测试的问题,引用@Retention元注解的讲解,其三种取值:RetentionPolicy.SOURCE

RetentionPolicy.CLASS

RetentionPolicy.RUNTIME

分别对应:java源文件---class文件---〉内存中的字节码

@Suppersswarnings() RetentionPolicy.SOURCE  java源文件

@Deprecated RetentionPolicy.RUNTIME内存中的字节码

@overrideRetentionPolicy.SOURCE java源文件

补充知识点:

@Target元注解:Target为默认元素,设置Target=ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设置

{ElementType.METHODElementType.Type}就可以了。

    |         |                  |

枚举     在方法上     在类上

关于注解的小练习:

package cn.itcast.day2;

@ ITcaseAnnotation(annotationAttr=@MetaAnnotation("ssd"),color="red",value="abc",arrayAttr={4,52,3})

public class AnnotationTest {

      /*

       * @param args

       * @ ITcaseAnnotation

       */@SuppressWarnings("deprecation")

       @ITcaseAnnotation(value="xxx",arrayAttr={5,7,3})

      publicstatic void main(String[] args) throws Exception{

             //TODO Auto-generated method stub

             System.runFinalizersOnExit(true);

             if(AnnotationTest.class.isAnnotationPresent(ITcaseAnnotation.class)){

 ITcaseAnnotationannotation=(ITcaseAnnotation)AnnotationTest.class.getAnnotation(ITcaseAnnotation.class);

                    System.out.println(annotation.color());

                    System.out.println(annotation.value());

                    System.out.println(annotation.arrayAttr().length);

                    System.out.println(annotation.lamp().nextLamp().name());

           System.out.println(annotation.annotationAttr().value());

             }

      }

      @Deprecated

      publicstatic void say(){

             System.out.println("您好,欢迎来到传智播客!!");

      }

}

代理

 

1、代理类的作用

可以给具有相同接口的类增加一些这些类都需要用到的功能

程序中的代理:

1)要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能。

2)编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。

 

2AOP

AOP:Aspect oriented program面向方面编程,或面向切口编程,Aop的目标就是要使用交叉业务模块化

比如,事物,log

所谓交叉业务就是一个功能贯穿到多个模块中。

 

3、动态代理

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

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

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

package cn.itcast.day3;

 

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.ArrayList;

import java.util.Collection;

public class ProxyTest {

public static void main(String[] args)throwsException {

             //Proxy.getProxyClass(类加载器,接口)

Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);

             System.out.println(clazzProxy1.getName());//打印类的名字

             System.out.println("----------beginconstructors list------想要以列表的方式打印----");

             /*列表格式:

              * $Proxy0()

               $Proxy0(InvocationHandler,int)*/

             //得到类中所有的构造方法

             Constructor[] constructors=clazzProxy1.getConstructors();

             for(Constructorconstructor:constructors){

                    Stringname=constructor.getName();//得到构造方法之一的名字

                    StringBuildersBuilder=new StringBuilder(name);

                    sBuilder.append("(");

                   Class[]clazzParams=constructor.getParameterTypes();//取出参数类型

                  for(ClassclazzParam:clazzParams){//将参数类型遍历,放入到缓冲区中

                           sBuilder.append(clazzParam.getName()).append(",");

                    }

                    if(clazzParams!=null&&clazzParams.length!=0){

                   sBuilder.deleteCharAt(sBuilder.length()-1);//去掉最后一个逗号

                    }

                    sBuilder.append(")");

                    System.out.println(sBuilder.toString());

             }

             System.out.println("----------beginmethods list----------");

             /*$Proxy0()

               $Proxy0(InvocationHandler,int)*/

             Method[] methods=clazzProxy1.getMethods();

             for(Methodmethod:methods){

                    Stringname=method.getName();

                    StringBuildersBuilder=new StringBuilder(name);

                    sBuilder.append("(");

                    Class[]clazzParams=method.getParameterTypes();

                    for(ClassclazzParam:clazzParams){

                           sBuilder.append(clazzParam.getName()).append(",");

                    }

                    if(clazzParams!=null&&clazzParams.length!=0){

                           sBuilder.deleteCharAt(sBuilder.length()-1);

                    }

                    sBuilder.append(")");

                    System.out.println(sBuilder.toString());

             }

      }

}

4.创建动态类实例对象调用其方法

mian:

//创建动态类的实例对象.

System.out.println("----------begin createinstance object----------");

//Object obj = clazzProxy1.newInstance();//此处为不带参数的构造参数,而且没有,所以不行

//所以这里要搞到有参数的构造函数

Constructor constructor =clazzProxy1.getConstructor(InvocationHandler.class);

//做一个实现InvocationHandler的类

class MyInvocationHander1 implementsInvocationHandler{

 

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

throws Throwable {

return null;

}

}

Collection proxy1 =(Collection)constructor.newInstance(newMyInvocationHander1());

System.out.println(proxy1);

proxy1.clear();

//proxy1.size();

5.完成InvocationHandler对象的内部功能

 

补充:---

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

创建某一接口FOO的代理。

InvocationHandler handler = newMyInvocationHandler(...);

Class proxyClass = Proxy.getProxyClass(

Foo.class.getClassLoader(), new Class[] { Foo.class});

Foo f = (Foo) proxyClass.

getConstructor(new Class[] {InvocationHandler.class }).

newInstance(new Object[] { handler });

或使用以下更简单的方法:

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),

new Class[] { Foo.class },

handler);

 

完成InvocationHandler对象的内部功能.

总结:jvm创建动态类及实例对象,需要给它提供那些信息?

三个方面:

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

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

3,生成的类中的方法的代码是怎么样的,也由得我们提供.把我们的代码卸载一个约号了的接口对象的方法中,

把对象传给他,它调用的我的方法,即相当于插入了我的代码.提供执行代码的对象,就是那个InvocationHandler对象.

它是在创建动态类的实例对象的构造方法时传递进去的.在上面的InvocationHandler对象的invoke方法中

 

加一点代码,就可以看到这些代码被调用运行了.

main:

Collection proxy3 =(Collection)Proxy.newProxyInstance(

Collection.class.getClassLoader(),

new Class[]{Collection.class},

new InvocationHandler()

{

//指定一个目标

ArrayList target = new ArrayList();

public Object invoke(Object proxy, Method method, Object[] args)throws Throwable

{

//测试时间

long beginTime= System.currentTimeMillis();

Object retVal =method.invoke(target, args);

long endTime =System.currentTimeMillis();

System.out.println(method.getName()+"runningtime of"+(endTime-beginTime));

return retVal;

}

});

proxy3.add("zxx");

proxy3.add("lhm");

proxy3.add("bxd");

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

}

6.分析InvocationHandler对象的运行原理

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

7.实现类似spring的可配置的AOP框架.

工厂类BeanFactor负责创建目标类或代理类的实例对象,并通过配置文件实现切换.

getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应

的不是ProxyFactoryBean,则直接返回该类的实例对象,否则返回该类实例对象的getProxy方法返回的对象

BeanFactory的构造方法接受代表配置文件的输入对象,配置文件格式如下:

#xxx=java.util.ArrayList

xxx=cn.itcast.day3.aopframework.ProxyFactoryBean

xxx.advice=cn.itcast.day3.MyAdvice

xxx.target=java.util.ArrayList

ProxyFacotryBean充当封装生成动态代理的工厂,需要为工厂类提供的配置参数信息:

 <BeanFactory>

packagecn.itcast.day3.aopframework;

import java.io.IOException;

import java.io.InputStream;

importjava.util.Properties;

importcn.itcast.day3.Advice;

public class BeanFactory

{

Properties props = newProperties();

publicBeanFactory(InputStream ips)//构造方法要接受一个配置文件.

{

try

    {

         props.load(ips);

    }

catch(IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

    }

}

public ObjectgetBean(String name)

{

     StringclassName = props.getProperty(name);

     Objectbean = null;

     try {

          Class clazz = Class.forName(className);

          bean = clazz.newInstance();

      } catch (Exception e)

     {

      // TODO Auto-generated catch block

      e.printStackTrace();

}

if(beaninstanceof ProxyFactoryBean)//如果是特殊的类,就创建一个代理

{

     Object proxy = null;

      ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;

try

{

     Adviceadvice = (Advice)Class.forName(props.getProperty(name +".advice")).newInstance();

     Objecttarget = Class.forName(props.getProperty(name +".target")).newInstance();

     proxyFactoryBean.setAdvice(advice);

     proxyFactoryBean.setTarget(target);

     proxy =proxyFactoryBean.getProxy();

}

catch (Exception e)

{

     e.printStackTrace();

}

    return proxy;

}

    return bean;

   }

}

第二个ProxyFactoryBean

packagecn.itcast.day3.aopframework;

importjava.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

importjava.lang.reflect.Proxy;

importcn.itcast.day3.Advice;

public classProxyFactoryBean {

     privateAdvice advice;

     privateObject target;

     publicAdvice getAdvice() {

         return advice;

}

publicvoid setAdvice(Advice advice) {

     this.advice = advice;

}

publicObject getTarget() {

     return target;

}

publicvoid setTarget(Object target) {

     this.target = target;

}

publicObject getProxy() {

     // TODO Auto-generated method stub

    Object proxy3 = Proxy.newProxyInstance(

    target.getClass().getClassLoader(),

    /*new Class[]{Collection.class},*/

    target.getClass().getInterfaces(),

    new InvocationHandler(){

publicObject invoke(Object proxy, Method method, Object[] args)throws Throwable {

    /*longbeginTime = System.currentTimeMillis();

    ObjectretVal = method.invoke(target, args);

    longendTime = System.currentTimeMillis();

    System.out.println(method.getName()+ " running time of " + (endTime - beginTime));

    returnretVal;*/

    advice.beforeMethod(method);

    ObjectretVal = method.invoke(target, args);

    advice.afterMethod(method);

    return retVal;

  }

 }

);

    returnproxy3;

  }

}

< AopFrameworkTest测试的类 >

packagecn.itcast.day3.aopframework;

import java.io.InputStream;

importjava.util.Collection;

public classAopFrameworkTest {

public static voidmain(String[] args) throws Exception {

     //首先加载文件

     InputStreamips = AopFrameworkTest.class.getResourceAsStream("config.properties");

     //新建一个BeanFactory(配置文件)

     Objectbean = new BeanFactory(ips).getBean("xxx");

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

     ((Collection)bean).clear();

   }

}

另外补充一点:

代理方法的位置的位置:

在调用目标方法之前

在调用目标方法之后

在调用目标方法前后

在处理目标方法异常的catch块中

 

------- android培训java培训、期待与您交流! ---------- 

 

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值