04.内省(Introspector)
javaBean——一个特殊的java类{包括属性;get();set()方法}
符合JavaBean特点的类可以当做普通类使用,但把它当做JavaBean有额外好处,JavaBean好处:
javaEE开发中要求
jdk中有对JavaBean进行操作的一些API(成为内省),比当普通类更方便(如:获取通过getX方法访问私有x)
对JavaBean的简单内省操作【实际开发中应该把适当操作包装在一个方法中,是代码清晰,方便易用】
ReflectPoint pt1 = new ReflectPoint(3, 5);
String propertyName = "x";//属性名propertyName
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
//创建属性描述类PropertyDescriptor对象,构造方法参数为: 属性名、当做JavaBean来看那个类,得到JavaBean属性
Method methodGetX = pd.getReadMethod();//获得JavaBean中的读方法,(pd.getWriteMethod获得写方法)
Object retVal = methodGetX.invoke(pt1);// invoke——调用
System.out.print(retVal);//得到了输出结果 3
对JavaBean的复杂内省操作:
//把一个类当做JavaBean看,就是调用Introspector.getBeanInfo方法,得到的BeanInfo封装了把这个类当做JavaBean来看的结果信息
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();//得到一个属性描述类数组,然后遍历找到想要的方法
05.用BeanUtils工具包操作JavaBean:【这是apache公司的做的,所以需要引入beanutils包、logging包】
BeanUtils.getProperty(pt1, "x");
BeanUtils.setProperty(pt1, "x", "9");
BeanUtils.setProperty(pt1, "birthday.time", "111");//联级操作birthday下time属性
【引入】java7的新特性:java7中将可以这样做
Map map = {name:"zxx",age:18};
BeanUtils.setProperty(map, "name", "lhm");
06.JDK1.5新特性:注解(Annotation)
注解相当于一个标记,加了注解就等于为程序打上了某种标记,编译器会通过反射来了解你的类及各种元素上是否有标记!
@SuppressWarnings("deprecation") //消除警告
@Deprecated //定义已过时,再编译是会弹出警告
@Override //标记覆盖,覆盖不对是不会通过编译
元注解:注解的注解 (同理:元数据、元信息)
@Retention(RetentionPolicy.RUNTIME)
//定义注解生命周期:RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME) !
@Target({ElementType.METHOD,ElementType.TYPE})//创建的注解可以在什么位置
为注解增加高级属性
public @interface ItcastAnnotation {
String color() default "blue"; //缺省属性,即不填时的默认值
String value(); //只有这一个属性要填是可以直接写不用value=
int[] arrayAttr() default {3,4,4};
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;
MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");
}
07.JDK1.5新特性:泛型(Generic)
泛型可以指定输入类型一致,提高了安全性
泛型【去类型化】是供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说 明的集合时会去掉“类型”信息,使程序运行效率不受影响。
例如:用反射得到集合,再调用其add方法即可加入其他类型数据了。
ArrayList<Integer> collection3 = new ArrayList<Integer>();//指定只能输入Integer类型:给编译器看的
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
System.out.println(collection3.get(0));//输出abc,反射后去类型化了
泛型术语:
整个称为ArrayList<E>泛型类型
ArrayList<E>的E称为类型变量或类型参数
而整个ArrayList<Integer>称为参数化的类型
而ArrayList<Integer>的integer称为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念typeof
ArrayList称为原始类型
参数化类型与原始类型的兼容性 //可不可以还不是编译器的一句话的事
参数化类型不考虑类型参数的继承关系
Vector<String> = new Vector<Object>();//错,反之也错
泛型中的?通配符
<? > 使用?通配符可以引用其他各种参数化类型。【不能调用参数化有关的方法,那就限定了参数类型,矛盾】
collection.size()
Vector<? extends Number>x = new <extends Integer> //限定通配符的上边界
Vector<? super Integer>x = new <extends Number> //限定通配符的下边界
限定通配符范围总包括自己
泛型集合的综合应用案例
HashMap<String,Integer> maps = new HashMap<String, Integer>();
maps.put("zxx", 28); maps.put("lhm", 35); maps.put("flx", 33);
Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
//Map中一对key和value的组合体也是一个类——>Map.Entry
//得到Map中的组合体放入Set中, 进行迭代
for(Map.Entry<String, Integer> entry : entrySet){
System.out.println(entry.getKey() + ":" + entry.getValue());
}
自定义泛型的方法和应用
private static<T> T add(T x,T y)
add(3,5);
Number x1 = add(3.5,3); //得到的是Number类型,不是float也不是int
Object x2 = add(3,"abc");//同上,实际取的是两个参数的公倍数
private static <T> void swap(T[] a,int i,int j){
T tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
swap(new String[]{"abc","xyz","itcast"},1,2);
//swap(new int[]{1,3,5,4,5},3,4); //编译器会报错
【T的引用不能是基本数据类型,只有引用类型才能作为泛型方法的实际参数】
定义泛型是也可以用estends限定。普通方法,静态方法,构造方法都可以用泛型
定义泛型是可以指定多个类型参数在定义它们的尖括号中用逗号分
public static<K,V> V getValue(K key) {return map.get(key);}
自定义泛型方法的练习与类型推断总结
实现自动将Object类型的对象转换成其他类型:
private static <T> T autoConvert(Object obj){
return (T)obj;
}
Object obj = "abc";
String x3 = autoConvert(obj);
定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象:
private static <T> void fillArray(T[] a,T obj){
for(int i=0;i<a.length;i++){
a[i] = obj;
}
}
采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容:
public static <T> void printCollection2(Collection<T> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
定义一个方法,把任意参数类型的集合中的数据安全的复制到相应类型的数组中:
public static <T> void copy1(Collection<T> dest,T[] src) { }
public static <T> void copy2(T[] dest,T[] src) { }
copy1(new Vector<String>(),new String[10]);
copy2(new Date[10],new String[10]);//取交集应为Object
//copy1(new Vector<Date>(),new String[10]);//报错【泛型具有传播性,既然<Date>已经确定,<T>也就确定为<Date>】
自定义泛型类的应用
实例对象多处用到统一泛型参数,为保持同一类型,泛型要加在类级别上,语法如下:
public class GenericDao<T> {
private T filed1;
public void save(T obj) {}
public T getById(int id) {}
}
用法:引用该类名是指定类型信息来参数化类型变量
GenericDao<String> dao = null; new GeneriDao<String>();
通过反射获得泛型的实际类型参数(Hebernate源码)