1、JavaBean概述
JavaBean是一种特殊的java类,主要用于传递数据信息。这种java类的方法主要用于访问私有的字段,且方法名符合某种命名规则。 如果两个模块之间传递多种信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object),这些信息在类中用私有字段来存储。如果读取或者设置这些字段的值,则需要通过一些相应的方法来访问。
JavaBean的属性是根据其中的setter和getter方法来确定的。而不是根据其中的成员变量。例如方法名为setAge,则它的意思是设置Age,如果方法名为getAge,则其意思是获取Age。去电set或者get前缀,剩余部分就是属性名。如果剩余部分单词的第二个字母是小写的,则把剩余部分的首字母该成小写。 例如:setLast的属性名:last;setAge属性名:age;SetCPU的属性名:CPU。
总之一个类被当做JavaBean使用时,JavaBean的属性名是根据方法名来推断的,它根本看不到JavaBean内部的成员变量。
一个符合JavaBean特点的类可以当做普通类来使用。使用JavaBean的好处:在JavaEE开发中,经常要使用到JavaBean。很多环境都要求按JavaBean方式进行操作;JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。用内省这套API操作JavaBean比普通类的方式更方便。
2、JavaBean实例操作
演示示例:读取JavaBean的属性以及设置JavaBean的属性。
ReflectPoint2类
package com.itheima.day01;
import java.util.Date;
public class ReflectPoint2 {
private Date birthDay = new Date();
private int x;
private int y;
public ReflectPoint2(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Date getBirthDay() {
return birthDay;
}
public void setBirthDay(Date birthDay) {
this.birthDay = birthDay;
}
}
正文代码:
package com.itheima.day01;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ReflectPoint2 pt = new ReflectPoint2(4, 5);
//获取x的值;普通方式:"x"-->"X"-->"getX"-->MethodgetX;
String propertyName = "x";
Object retVal = getProperty(pt, propertyName);
System.out.println(retVal); //4;
Object value = 8;
setProperty(pt, propertyName, value);
System.out.println(pt.getX()); //8
}
//重构方法;
private static void setProperty(Object pt, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
PropertyDescriptor pd1 = new PropertyDescriptor(propertyName, pt.getClass());
Method methodSetx = pd1.getWriteMethod();
methodSetx.invoke(pt, value);
}
private static Object getProperty(Object pt, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
//简单操作;
/*PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt);*/
//复杂点的操作;
BeanInfo beanInfo = Introspector.getBeanInfo(pt.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd: pds){
if(pd.getName().equals(propertyName)){
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt);
break;
}
}
return retVal;
}
}
以上示例还可以使用BeanUtils工具包来帮我们完成。但使用的时候需要导入BeanUtils包!!! 导包示例:将下载好的Util包解压,在工程下新建一个Folder文件夹,将解压出来的的jar包复制到其中,让后单击jar包,单击鼠标右键选择Build Path将jar包加入到classpath下即可。
package com.itheima.day01;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
public class IntroSpectorTest1 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ReflectPoint2 pt1 = new ReflectPoint2(4, 5);
BeanUtils.setProperty(pt1, "x", "7"); //BeanUtils包中,这里的7可以是字符串形式;
System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName()); //java.lang.String
System.out.println(BeanUtils.getProperty(pt1, "x")); //7
PropertyUtils.setProperty(pt1, "y", 8); //这里的8如果是字符串形式则会出现参数类型不匹配错误;这也是PropertyUtils与BeanUtils
//的区别,BeanUtils可以将字符串、整数自动转换,而PropertyUtils不行。
System.out.println(PropertyUtils.getProperty(pt1, "y").getClass().getName()); //java.lang.Integer
System.out.println(pt1.getY()); //8
BeanUtils.setProperty(pt1, "birthDay.time", 12);
System.out.println(BeanUtils.getProperty(pt1, "birthDay.time")); //12
}
}
3、Java注解(JDK1.5新特性)
1)、SuppressWarnings:指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。注意,在给定元素中取消显示的警告集是所有包含元素中取消显示的警告的超集。例如,如果注释一个类来取消显示某个警告,同时注释一个方法来取消显示另一个警告,那么将在此方法中同时取消显示这两个警告。
Deprecated:用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。
Override:表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。 前面的ReflectPoint类中的复写equals方法和hashCode方法是前面有@Override提示该方法要复写父类方法,不然就会报错。
总结:注解相当于一种标记,在程序中加了注解就等于为程序加上了某种标记。没加,就等于没有标记。以后javac编译器、开发工具 和其他程序可以用反射来了解你的类及各种元素上有无何种标记,有什么标记就去干相应的事情。标记可以加在包、类、字段、方法、方法的参数以及局部变量上。 具体参考API文档中的注释类型。
2)、自定义注解
Retention类:指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为RetentionPolicy.CLASS。只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效。
Retention注解的三种取值:RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME。分别对应:java源文件-->class文件-->内存中的字节码。
Target类:指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。
Target的默认值为任何元素。设置Target等于ElementType.METHOD,那么加载在类上的注解就会报错。如果改用成数组方式设置{ElementType.METHOD,ElementType.TYPE},那么注解就可以加载在类上和方法上了。
自定义的注解:
package com.itheima.day02;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItcastAnnotation {
String color() default "blue";
String value();
int[] arrayAttr() default {4,5,6,7};
}
自定义的类:
package com.itheima.day02;
@ItcastAnnotation(color = "red",value = "abc",arrayAttr={1,2,3})
public class AnnotationTest {
/**
* @param args
*/
@SuppressWarnings("deprecation") //压缩警告,提示不要再提示以下过时的方法已过时;
@ItcastAnnotation("xyz")
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
System.runFinalizersOnExit(true);
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation = (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color()); //red;
System.out.println(annotation.value()); //abc
System.out.println(annotation.arrayAttr().length); //3
}
}
@Deprecated //此注解表示该方法已过时;
public static void sayHello(){
System.out.println("Hello World!!!");
}
}
4、泛型(JDK1.5新特性)
泛型是提供给编译器javac使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入。编译器编译带类型说明的集合时会去掉“类型”信息,是程序运行效率不受影响。对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要跳过编译器就可以往某个泛型集合中加入其它类型的数据。例如,利用反射得到集合,在调用其add方法即可。
例:ArrayList<E>和ArrayList<Integer>涉及的属于
整个ArrayList<E>称为泛型类;
ArrayList<E>中的E称为类型变量或者类型参数;
整个ArrayList<Integer>称为参数化的类型;
ArrayList<Integer>中的Integer称为类型参数的实例或者实际类型参数;
ArrayList<E>中的<>念Typeof;
ArrayList称为原始类型。
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告:如:Collection<String> c = new Vector().
原始类型可以引用一个参数化类型的对象,编译报告警告:如:Collection c = new Vector<String>(). 原来的方法接受一个集合参数,新的类型也能穿进去。
参数化类型不考虑类型参数的继承关系:
如:Vector<String> v = new Vector<Object>(); 错误,如果不写<Object>就是对的。
Vector<Object> v = new Vector<String>(); 错误。
在创建数组实例时,数组的元素不可以使用参数化的类型。例如:Vector<Integer> vectorList = new Vector<Integer>[10];错误。
?通配符: 使用?号通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
package com.itheima.day02;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class GenericTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ArrayList<String> collections1 = new ArrayList<String>();
collections1.add("abc");
collections1.add("def");
collections1.add("xyz");
System.out.println(collections1.get(0));
ArrayList<Integer> collections2 = new ArrayList<Integer>();
collections2.add(1);
collections2.add(2);
collections2.add(3);
System.out.println(collections2.get(0));
System.out.println(collections1.getClass() == collections2.getClass());//true
collections2.getClass().getMethod("add", Object.class).invoke(collections2, "abc");
System.out.println(collections2.get(3)); //abc;
printCollections(collections2);
HashMap<String,Integer> hm = new HashMap<String,Integer>();
hm.put("java01", 12);
hm.put("java02", 23);
hm.put("java03", 52);
Set<Map.Entry<String, Integer>> entrySet = hm.entrySet();
for(Map.Entry<String, Integer> entry: entrySet){
System.out.println(entry.getKey()+"::"+entry.getValue());
}
}
public static void printCollections(Collection<?> collection) {
//collection.add("abc"); //与参数化有关的方法不能调用;
System.out.println(collection.size());
for(Object obj:collection){
System.out.println(obj);
}
}
}
5、类加载器
java虚拟机可以安装多个类加载器,系统默认三个类加载器。每个类加载器负责加载特定位置的类:BootStrap、ExtClassLoader、AppClassLoader。
类加载器也是java类,因为其他类的类加载器也要被类加载器加载,显然必须有一个类加载器不是java类,这就是BootStrap。
java虚拟机中的所有类加载器采用了具有父子关系的树形结构进行组织。在实例化每个类加载器对象时,需要为其指定一个父类 加载器对象或者默认采用系统类加载器为其父级类加载。
java类之间的父子关系及管辖范围:BootStrap--->JRE/lib/rt.jar ExtClassLoader--->JRE/lib/ext/*.jar AppClassLoader--->CLASSPATH指定的所有jar或目录。
java虚拟机要加载一个类时,是如何选择类加载器去加载的? 首先当前线程的类加载器去加载线程中的第一个类; 如果类A中引用了类B,java虚拟机将使用加载类A的加载器去加载类B。还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载时,有先委托其上级类加载器。 当所有的父类加载器都没有加载到类,又回到发起者类加载器,如果还加载不到就会抛出ClassNotFoundException。而不会再去找发起者类加载器的子类加载器去加载了。
package com.itheima.day02;
public class ClassLoaderTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String str = ClassLoaderTest.class.getClassLoader().getClass().getName();
System.out.println(str); //sun.misc.Launcher$AppClassLoader
System.out.println(System.class.getClassLoader()); //null System是由BootStrap类加载器加载的
}
}
6、动态代理
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。
代理实现图:
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理。所以要为一个没有实现接口的类生成动态代理类,就可以使用CGBLIB库。
代理的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置上加上系统功能代码:
1)、在调用目标方法之前;
2)、在调用目标方法之后;
3)、在调用目标方法前后;
4)、在调用目标方法异常的catch块中;
创建动态类的示例对象步骤:
A、用反射获得构造方法;
B、编写一个简单地实例类InvocationHander类;
C、调用构造方法创建动态类的实例对象,并将编写的InvocationHander类的实例对象传进去;
D、将创建动态类的实例对象的代理改成内部类的形式编写;
代码如下:
Advice接口:
package com.itheima.day03;
import java.lang.reflect.Method;
public interface Advice {
void beforMethod(Method method);
void afterMehtod(Method method);
}
MyAdvice类:
package com.itheima.day03;
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long startTime;
@Override
public void beforMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("程序开始了!");
startTime = System.currentTimeMillis();
}
@Override
public void afterMehtod(Method method) {
// TODO Auto-generated method stub
System.out.println("程序结束了!");
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time "+(startTime - endTime));
}
}
主体代码:
package com.itheima.day03;
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) throws Exception{
// TODO Auto-generated method stub
Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy.getName()); //$Proxy0
System.out.println("----------------------------------------------");
Constructor[] constructors = clazzProxy.getConstructors();
for(Constructor constructor:constructors){
String name = constructor.getName();
StringBuilder sBuild = new StringBuilder(name);
sBuild.append("(");
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam: clazzParams){
sBuild.append(clazzParam.getName()).append(",");
}
if(clazzParams != null && clazzParams.length != 0)
sBuild.deleteCharAt(sBuild.length()-1);
sBuild.append(")");
System.out.println(sBuild.toString());
}
System.out.println("----------------------------------------------");
Method[] methods = clazzProxy.getMethods();
for(Method method:methods){
String name1 = method.getName();
StringBuilder sBuild1 = new StringBuilder(name1);
sBuild1.append("(");
Class[] clazzParams1 = method.getParameterTypes();
for(Class clazzParam: clazzParams1){
sBuild1.append(clazzParam.getName()).append(",");
}
if(clazzParams1 != null && clazzParams1.length != 0)
sBuild1.deleteCharAt(sBuild1.length()-1);
sBuild1.append(")");
System.out.println(sBuild1.toString());
}
System.out.println("----------------------------------------------");
Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
class MyInvacationHander1 implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection) constructor.newInstance(new MyInvacationHander1());
System.out.println(proxy1); //null
Collection proxy2 = (Collection) constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
//proxy1.size(); //出现NullPointerException异常,因为上面的invoke方法中返回null,
//而此处接受的是一个int型的数据,所以就会出现错误;
System.out.println(proxy2);
final ArrayList target = new ArrayList();
Collection proxy3 = (Collection) getProxy(target,new MyAdvice());
proxy3.add("java01");
proxy3.add("java02");
proxy3.add("java03");
System.out.println(proxy3.size());
}
private static Object getProxy(final Object target,final Advice advice) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
//new Class[]{Collection.class},
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time "+(startTime - endTime));
return retVal;*/
advice.beforMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMehtod(method);
return retVal;
}
});
}
}
实现AOP功能的封装与配置
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据其参数字符串返回一个相应的实例对象。如果参数字符串在配置中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象。否则,返回该类实例对象的getProxy方法返回的对象。
BeanFactory的构造方法接受代表配置文件的输入流对象,配置文件格式如下:
#xxx=java.util.ArrayList
xxx=cn.itheima.day03.aopframework.ProxyFactoryBean
xxx.advice=cn.itheima.day03.MyAdvice
xxx.target=java.util.ArrayList
ProxyFactoryBean充当封装生成动态代理的工厂,需要为工厂提供目标和通知。
编写客户端应用:
编写Advice接口的类和在配置文件中进行配置;
调用BeanFactory获取对象。
ProxyFactoryBean:
package com.itheima.day03.aopframework;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.itheima.day03.Advice;
public class ProxyFactoryBean {
private Advice advice;
private Object target;
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
//new Class[]{Collection.class},
target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time "+(startTime - endTime));
return retVal;*/
advice.beforMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMehtod(method);
return retVal;
}
});
}
}
BeanFactory类:
package com.itheima.day03.aopframework;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import cn.itheima.day03.Advice;
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream in){
try {
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
public Object getBean(String name){
String className = props.getProperty(name);
Object bean = null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){
Object proxy = null;
try {
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
Advice advice = (Advice)Class.forName(props.getProperty(name+".advice")).newInstance();
Object target = 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;
}
}
测试主体代码:
package com.itheima.day03.aopframework;
import java.io.InputStream;
public class AopFrameWorkTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
InputStream ips = AopFrameWorkTest.class.getResourceAsStream("config.properties");
Object bean = new BeanFactory(ips).getBean("xxx");
System.out.println(bean.getClass().getName());
}
}