1,由内省引出的 javaBean讲解
内省→IntroSpector(检查,视察,了解内部的细节)→对JavaBean操作→是一个特殊的java类,方法的名称符合某种约定的规则的java类。
这种java类中的方法用于访问私有的字段,且方法名符合某种命名规则。
从方法得到属性-->如果第二个字母是小写,则把第一个字符变成小写的
gettime--time setTime---time getCPU--CPU
总之,一个类被当做javaBean使用时,javaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。
一个符合javaBean特点的类可以当做普通类一样使用,但把它当做javaBean用肯定需要带来一些额外的好处,我们才会去了解和应用javaBean
javaEE开发中,经常用到javaBean。很多环境就要求按JavaBean方式进行操作
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称为值对象(Value Object,简称VO)。
jdk中提供了一些api,这套内省就称为内省。
内省的综合案例。package com.itcast.zhang;
public class ReflectPoint {
private int x;// 私有成员变量
public int y;// 共有成员变量
// 共有成员变量str1;str2;str3;
public String str1 = "ball";
public String str2 = "baseketball";
public String str3 = "itcast";
/**
* 得到x
*
* @return
*/
public int getX() {
return x;
}
/**
* 设置x
*
* @param x
*/
public void setX(int x) {
this.x = x;
}
/*
* 得到y
*/
public int getY() {
return y;
}
/**
* 设置y
*
* @param y
*/
public void setY(int y) {
this.y = y;
}
/**
* 构造方法
*
* @param x
* @param y
*/
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
/**
* 重写hashCode方法
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
/**
* 重写equas方法
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
/**
* 重写toString方法
*/
@Override
public String toString() {
return str1 + ":" + str2 + ":" + str3;
}
}
1 package com.itcast.zhang; 3 import java.beans.IntrospectionException; 4 import java.beans.PropertyDescriptor; 5 import java.lang.reflect.InvocationTargetException; 6 import java.lang.reflect.Method; 7 8 public class IntroSpectorTest { 9 10 /** 11 * @param args 12 * @throws IntrospectionException 13 * @throws InvocationTargetException 14 * @throws IllegalAccessException 15 * @throws IllegalArgumentException 16 */ 17 public static void main(String[] args) throws IntrospectionException, 18 IllegalArgumentException, IllegalAccessException, 19 InvocationTargetException { 20 // TODO Auto-generated method stub 21 ReflectPoint pt1 = new ReflectPoint(3, 4);//实例对象 22 String propertyName = "x";//属性名 23 PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1 24 .getClass());//属性描述符,看做javaBean 25 Method methodGetx = pd.getReadMethod();//得到读的方法 26 Object retVal = methodGetx.invoke(pt1);//调用,读方法没有参数 27 System.out.println(retVal); 28 Method methodSetx = pd.getWriteMethod();//得到设置方法 29 methodSetx.invoke(pt1, 7);//对象调用 30 System.out.println(pt1.getX());//原来方式进行输出输出 31 } 32 33 }
采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中把一个类当做JavaBean来看,就是调用IntroSpectro.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当做JavaBean的结果信息。但是这种方法写起来比较麻烦,知道有这种方法就好。
package com.itcast.zhang;
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 {
/**
* @param args
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static void main(String[] args) throws IntrospectionException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3, 4);
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
Object value = 7;
setProperties(pt1, propertyName, value);
System.out.println(pt1.getX());
}
/**
* 设置属性名的值
*
* @param pt1
* @param propertyName
* @param value
* @throws IntrospectionException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private static void setProperties(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
// new 一个PropertyDescription
// (属性描述符)类的对象方法,里面有两个参数,第一个是属性名,第二个是对象的字节码对文件,把某一个类当做javaBean来看可以操作这个类的属性
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1
.getClass());
Method methodSetx = pd2.getWriteMethod();// 得到写的方法。
methodSetx.invoke(pt1, value);// 调用 传入value
}
/**
* 得到属性名
*
* @param pt1
* 对象
* @param propertyName属性名
* @return
* @throws IntrospectionException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1
.getClass());
Method methodGetx = pd.getReadMethod();
Object retVal = methodGetx.invoke(pt1);
// 麻烦的方式 这中方式用的不太多,只是为了提高编码能力而写
// 采用遍历BeanInfo的多有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中,
// 把一个类当做JavaBean开看,就是调用了IntroSpector.getBeanInfo方法,得到BeanInfo对象封装了把这个类当作javaBean看的结果信息
/*
* BeanInfo beaninfo = Introspector.getBeanInfo(pt1.getClass());
* PropertyDescriptor[] pds = beaninfo.getPropertyDescriptors(); Object
* retVal = null; for (PropertyDescriptor pd : pds) { if
* (pd.getName().equals(propertyName)) { Method methodGetx =
* pd.getReadMethod(); retVal = methodGetx.invoke(pt1); break; } }
*/
return retVal;
}
}
package com.itcast.zhang;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws Exception,
NoSuchMethodException {
//定义一个集合
ArrayList<String> collection1 = new ArrayList<String>();
collection1.add("abc");
//collection1.add(1);这里编译错误,只能添加固定的类型
//根据反射 得到构造函数的对象,这里通过泛型也可以避免强制类型转换
Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);
//这里也避免了类型转换的苦恼
String str2 = constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));
}
}
package com.itcast.zhang;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) { // 已经参数化的类型。
//定义两个集合
ArrayList<String> collection1 = new ArrayList<String>();
ArrayList<Integer> collection2 = new ArrayList<Integer>();
//通过比较两个对象的字节码,打印是true;
System.out.println(collection1.getClass() == collection2.getClass());
}
}
泛型是提供给java编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译类型说明的集合时会去掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用add()方法即可。
1 import java.lang.reflect.InvocationTargetException; 2 import java.util.ArrayList; 3 4 5 public class Test2 { 6 public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 7 //已经参数化的类型。 8 ArrayList<String> collection1=new ArrayList<String>(); 9 ArrayList<Integer> collection2=new ArrayList<Integer>(); 10 System.out.println(collection1.getClass()==collection2.getClass()); 11 // 编译错误 collection2.add("abc"); 12 collection2.getClass().getMethod("add",Object.class).invoke(collection2, "abc");//用反射得到集合,再调用add()方法即可跳过编译阶段 13 System.out.println(collection2.get(0));//打印看结果 14 } 15 }
打印 abc --泛型是给编译器看的
泛型的术语:
整个称为ArrayList<E>泛型类型
ArrayList<Integer>称为参数化的类型。
ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念着type of
ArrayList称为原始类型。
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译器报告警告,例如,
Collection<String> c=new Vector();
原始类型可以引用一个参数化类型的对象,编译器报告警告
Collection c=new Vector<String>();
参数化类型不考虑继承关系:
Vector<String> =new Vector<Object>();//错误
在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误:
Vector<Integer> vectorList[]=new Vector<Integeer>[10];
泛型的通配符扩展应用
1 import java.lang.reflect.InvocationTargetException; 2 import java.util.ArrayList; 3 import java.util.Collection; 4 5 public class Test2 { 6 public static void main(String[] args) throws IllegalArgumentException, 7 SecurityException, IllegalAccessException, 8 InvocationTargetException, NoSuchMethodException { 9 // 已经参数化的类型。 10 ArrayList<String> collection1 = new ArrayList<String>(); 11 ArrayList<Integer> collection2 = new ArrayList<Integer>(); 12 System.out.println(collection1.getClass() == collection2.getClass()); 13 // 编译错误 collection2.add("abc"); 14 collection2.getClass().getMethod("add", Object.class).invoke( 15 collection2, "abc"); 16 System.out.println(collection2.get(0)); 17 printCollection(collection2); 18 } 19 20 /** 21 * ?表示任意类型,编译器不会报错 22 * 23 * @param collection 24 */ 25 public static void printCollection(Collection<?> collection) { 26 // 编译错误。 27 // ?可以作为引用变量引用别的类型,但是不能调用与参数有关系的方法 28 // collection.add("abc"); 29 collection.size();// 这个方法可以调用,与参数类型无关。 30 for (Object obj : collection) { 31 System.out.println(obj); 32 } 33 // 总结:使用?通配符可以引用其他各种参数化的类型, 34 // ?通配符定义的变量主要作用是引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。 35 36 } 37 }
通配符的限定
限定通配符的上边界:
正确:Vector<?extends Number> x=new Vector<Integer>();--必须是Number以及是Number的子类
错误:Vector<?extends Number> x=new Vector<String>();
限定通配符的下边界:
正确:Vector<?super Integer> x=new Vector<Number>();必须是Integer的父类,或者Integer
错误:Vector<?super Integer> x=new Vector<Byte>();平级的,所以错误。
泛型集合类的综合案例
1 import java.util.HashMap; 2 import java.util.Map; 3 import java.util.Set; 4 5 public class Test3 { 6 public static void main(String[] args) { 7 HashMap<String, Integer> maps = new HashMap<String, Integer>();//定义一个map集合,键是String类型,值是Integer类型 8 maps.put("xxx", 23);//添加 9 maps.put("yyy", 22); 10 maps.put("zz", 13); 11 Set<Map.Entry<String, Integer>> enrtyset = maps.entrySet();//Map.Entry<String,Integer>是一个对,包括键值 12 for (Map.Entry<String, Integer> entry : enrtyset) {//遍历打印输出 13 System.out.println(entry.getKey() + ":" + entry.getValue()); 14 } 15 } 16 }
定义泛型的类型。
如果类的实例对象中的多处都要用到同意个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如下:
public class Generic<T>{
pirvate T field;
public void save(T obj){};
public T getByid(int id){}
}
通过反射获得泛型的实际类型参数
1 import java.lang.reflect.Method; 2 import java.lang.reflect.ParameterizedType; 3 import java.lang.reflect.Type; 4 import java.util.Date; 5 import java.util.Vector; 6 7 /** 8 * 通过反射获得泛型的实际类型参数 9 * 10 * @author Administrator 11 * 12 */ 13 public class Test4 { 14 public static void main(String[] args) throws Exception, 15 NoSuchMethodException { 16 Method applyMethod = Test4.class.getMethod("applyVector", Vector.class); 17 Type[] type = applyMethod.getGenericParameterTypes();// 得到参数类型的数组 18 ParameterizedType ptype = (ParameterizedType) type[0];// ParameterizedType 19 // 是Type的子类 20 System.out.println(ptype.getRawType());// 得到原始类型 打印Vector 21 System.out.println(ptype.getActualTypeArguments()[0]);// 打印Date 22 } 23 //测试方法 24 public static void applyVector(Vector<Date> v1) { 25 26 } 27 }
类加载器
用到一个类,jvm首先也把这个类的字节码,加载到内存中来进行处理,通常这个字节码的原始信息放在硬盘上ClassPath指定的目录下
java虚拟机中可以安装多个类加载器,系统默认三个类加载器,每个类负责加载特定位置的类:
BootStrap,ExtClassLoader,AppClassLoader
类加载器本身也是Java类,因为其他是Java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap(不需要被加载嵌套在jvm内核中的)
java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
1 public class ClassLoaderTest { 2 public static void main(String[] args) { 3 // 打印 sun.misc.Launcher$AppClassLoader 4 System.out.println(ClassLoaderTest.class.getClassLoader().getClass() 5 .getName()); 6 7 // 报错 空指针异常 8 // System.out.println(System.class.getClassLoader().getClass().getName()); 9 System.out.println(System.class.getClassLoader());// 打印null 由 10 // BootStrap加载 11 ClassLoader loader = ClassLoaderTest.class.getClassLoader();//得到一个类的加载器 12 while (loader != null) { 13 System.out.println(loader.getClass().getName());//输出类加载的名字 14 loader = loader.getParent();//得到父级加载器 15 } 16 System.out.println(loader); 17 } 18 }
类加载器之间的父子关系和管辖范围图
类加载器的委托机制
当java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了类B,java虚拟机将使用加载类A的类装载器来加载类B
每个类加载器加载类时,又先委托给其上级类加载器。
编写自己的类加载器
1,必须继承一个抽象类ClassLoader
2,复写findClass
代理
代理设计 :一个操作的接口有两个子类,其中一个是真实主题实现类,另外一个是代理实现类。代理实现类要完成比真实主题实现类更多的内容,而且
本身还需要处理一些与业务有关的程序代码
要为已存在的多个具有相同的接口的目标类的各个方法增加一些系统功能,例如,异常处理,日志,计算方法的运行时间,事物处理,等等。import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Collection;
/**
* 创建动态类及查看其方法列表
*
* @author Administrator
*
*/
public class Test1 {
public static void main(String[] args) {
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());// 打印 $Proxy0
System.out.println("begin constructo list");
// 有什么样的构造 方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
// System.out.println(constructor.getName());
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);// 单线程StrinbBuilder
sb.append('(');
Class[] classParams = constructor.getParameterTypes();
for (Class clazzParam : classParams) {
sb.append(clazzParam.getName()).append(',');
}
if (classParams != null && classParams.length != 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append(')');
System.out.println(sb.toString());
}
}
}
}
创建动态类的实例对象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
/**
* 创建动态类及查看其方法列表
*
* @author Administrator
*
*/
public class Test1 {
public static void main(String[] args) throws Exception,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());// 打印 $Proxy0
System.out.println("begin constructo list");
// 有什么样的构造 方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
// System.out.println(constructor.getName());
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);// 单线程StrinbBuilder
sb.append('(');
Class[] classParams = constructor.getParameterTypes();
for (Class clazzParam : classParams) {
sb.append(clazzParam.getName()).append(',');
}
if (classParams != null && classParams.length != 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append(')');
System.out.println(sb.toString());
}
}
Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection) constructor1
.newInstance(new MyInvocationHander1());
System.out.println(proxy1);// 打印null;但是对象不是null;
proxy1.clear();
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
/**
* 创建动态类及查看其方法列表
*
* @author Administrator
*
*/
public class Test1 {
public static void main(String[] args) throws Exception,
InstantiationException, IllegalAccessException,
InvocationTargetException {
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());// 打印 $Proxy0
System.out.println("begin constructo list");
// 有什么样的构造 方法
Constructor[] constructors = clazzProxy1.getConstructors();
for (Constructor constructor : constructors) {
// System.out.println(constructor.getName());
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);// 单线程StrinbBuilder
sb.append('(');
Class[] classParams = constructor.getParameterTypes();
for (Class clazzParam : classParams) {
sb.append(clazzParam.getName()).append(',');
}
if (classParams != null && classParams.length != 0) {
sb.deleteCharAt(sb.length() - 1);
sb.append(')');
System.out.println(sb.toString());
}
}
/* Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection) constructor1
.newInstance(new MyInvocationHander1());
System.out.println(proxy1);// 打印null;但是对象不是null;
proxy1.clear();*/
//第二种方式
Constructor constructor1 = clazzProxy1
.getConstructor(InvocationHandler.class);
Collection proxy2=(Collection)constructor1.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
}
}
让jvm创建动态类及其实例对象,需要给他提供哪些信息?
Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Proxy ;
import java.lang.reflect.Method ;
interface Subject{
public String say(String name,int age) ; // 定义抽象方法say
}
class RealSubject implements Subject{ // 实现接口
public String say(String name,int age){
return "姓名:" + name + ",年龄:" + age ;
}
};
class MyInvocationHandler implements InvocationHandler{
private Object obj ;
public Object bind(Object obj){
this.obj = obj ; // 真实主题类 代理的对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object temp = method.invoke(this.obj,args) ; // 调用方法
return temp ;
}
};
public class DynaProxyDemo{
public static void main(String args[]){
Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;
String info = sub.say("周珂珂",30) ;
System.out.println(info) ;
}
};