您的位置:首页 > 编程语言 > Java开发

java 自学日志【二十】---基础加强DAY27上

2013-05-16 22:33 363 查看
-------android培训,java培训,期待与您交流------
内省与beanutils工具包

内省(IntroSpector)主要用于对JavaBean进行操作。

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

用 途:如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对 象通常称之为值对象(Value Object,简称VO)。

这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。

特 点:JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。

去掉set和get前缀,剩余部分就是属性名。如果剩余部分的第二个字母是小写的,则把剩余部分的首字母 改成小的。

JavaBean必须有一个不带参数的构造方法。

好 处:一个符合JavaBean特点的类可以当作普通类一样进行使用,但如果把它当做JavaBean,

那么就可以调用JDK提供的对专门对JavaBean进行操作的API,以实现对一些对普通类来说比较复杂的 功能。

2.内省:JDK提供的对JavaBean进行操作的API,就被称为内省。

3.对JavaBean的简单内省操作 :


public static void setProperty(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
PropertyDescriptor dp1 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = dp1.getWriteMethod();
methodSetX.invoke(pt1,value);
}
--------------------------------------------
public static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor dp = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = dp.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
return retVal;
}
--------------------------------------------
ReflectPoint pt1 = new ReflectPoint(1,1);
String propertyName = "x";
Object retVal = getProperty(pt1, propertyName);
System.out.println("getX:"+retVal);
Object value = 7;

setProperty(pt1, propertyName, value);
System.out.println("setX:"+pt1.getX());
上边即是用java.beans包中的PropertyDescriptor类把ReflectPoint当做JavaBean进行操作。

4.使用BeanInfo类和IntroSpector类查看把ReflectPoint当做一个JavaBean看时,显示的信息,

并获取"x"属性的值(即用另一种方式,实现3中getProperty方法)

public static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] dps = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor dp:dps)
{
if(dp.getName().equals(propertyName)){
retVal = dp.getReadMethod().invoke(pt1);
break;
}
}
return retVal;


5.beanutils工具包

Apache提供的开源的操作JavaBean的工具包,它要和Apache的logging工具包导入到Project中,然后Build Path才可以使用。

里边的BeanUtil和PropertyUtils类使用示例如下:


ReflectPoint pt1 = new ReflectPoint(1,1);
BeanUtils.setProperty(pt1, "x", 25);
System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());
//BeanUtils可以实现属性链操作
BeanUtils.setProperty(pt1, "date.time", "111");//time不一定在类中存在,只是说明date有getTime和setTime方法。
System.out.println(BeanUtils.getProperty(pt1, "date.time"));
<span style="font-size:14px;">      PropertyUtils.setProperty(pt1, "x", 160);
System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName());


BeanUtils:以字符串(String)的形式对JavaBean 的属性进行操作,getProperty方法得到的属性值

是以字符串形式返回的(网络开发时,获取的用户数据类型都是String)。

PropertyUtils:以属性本身的类型最JavaBean的属性进行操作,getProperty()方法得到的属性值是以属性本来的类型返回的。

JDK1.7的新特性之一:Map map = {name:"zhangssan",age:18};

BeanUtils也可以对Map集合进行操作:BeanUtils.setProperty(map, name, "lisi");


注解 Annotation

注解基本应用:演示java.lang包中的三个注释类型。

Deprecated:用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在 更好的选择。在使用不被赞成的程序元素或在不被赞成的 代 码中执行重写时,编译器会发出警 告。

SuppressWarnings:指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的 编 译器警告

Override:表示一个方法声明打算重写超类中的另一个方法声明。


注解相当于一种标记,在程序中加了注解就等于给程序打上了某种标记。以后,javac编译器开发工具盒其他程序可以通过反射来了解你的类及各种元素上有无标记,看你有什么样的标记就去做相应的事。


注解可以加在:类、字段、方法和方法的参数及局部变量上。



import cn.itcast.day1.EnumTest;
@ItcastAnnotation(lamp=EnumTest.TrafficLamp.GREEN,color = "GREEN",value="123",arrayAttri={1,5,8},annoAttr=@MetaAnnotation("flx"))
public class AnnotationTest {

@SuppressWarnings("deprecation")//提示过时了
@ItcastAnnotation("123")
public static void main(String[] args) {
// TODO Auto-generated method stub
System.runFinalizersOnExit(true);
//方法过时了,在dos命令窗口中,如果没有加@SuppressWarnings("deprecation")会提示方法过时,如果有则不提示。

if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation = AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation);
System.out.println(annotation.color());
System.out.println(annotation.value());
System.out.println(annotation.arrayAttri().length);
System.out.println(annotation.lamp().nextLamp());
System.out.println(annotation.annoAttr().value());
}

}
@Deprecated//过时了
public static void sayHello()
{
System.out.println("hi,java!");
}

}
注解的应用结构:

1.注解类型。

2.应用了注解类型的类。

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

元注解:对注解类型进行注解的注解类型。(如元信息,描述信息的信息)

java的元注解都在java.lang.annotation包中,层次如下:

Annotation

|--Documented 指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。

|--Inherited 指示注释类型被自动继承。

|--Retention 指示注释类型的注释要保留多久。 (描述注释存在的周期)

|--Target 指示注释类型所适用的程序元素的种类 (描述注释存在的位置)


为注解增加基本属性。 增加属性的格式: 类型 变量名() default 变量实例 ;

1.添加基本属性:类型为8个基本数据类型,String类,Class类,

2.添加高级属性:枚举,注解类型(注解类型也可以作为基本属性加个注解),

3.以上类型的数组。

注意:如果属性中只有一个value属性,或有多个属性,这些属性都用默认值,那么可以简写为:@Annotation(arg)(arg为value的值)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.itcast.day1.EnumTest;
/*
* .class文件不是字节码文件,class文件通过类加载器,进入内存后,内存中存在的才是字节码文件。
*/
@Retention(RetentionPolicy.RUNTIME)//Retention是元注解:对注解的注解
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItcastAnnotation {
String color() default "red";
String value();
int[] arrayAttri() default {1,2,3};
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;
MetaAnnotation annoAttr()  default @MetaAnnotation("yxf");

}

public @interface MetaAnnotation {
String value() ;
}


泛型 Generic

一.问题的引入:为什么要用泛型?

引入泛型的原因之一:在使用集合时,可以向定义好的某一集合中存入任意类型的数据,而我们希望整个集合中的类型都是一样的,当加入的不期望的类型后,只有到运行期才能发现。 而且取出的类型需要强制转换。


//没有使用泛型:
ArrayList collection = new ArrayList();
collection.add(1);
collection.add(1L);
collection.add("abc");
//      int i = (Integer)collection.get(1);//这句会报错</span>
//使用泛型的代码:

//      在集合中的应用
ArrayList<String> collection1 = new ArrayList<String>();
//      collection1.add(1);
//      collection1.add(1L);
collection1.add("String");
String i = collection1.get(0);//        在反射中的应用
//用反射实现操作:String str = new String(new StringBuffer("abc"));
Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);
String str1 = constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str1.charAt(2));


从上面两段代码的对比中,很容易看出使用泛型的好处:1.限定了集合元素的类型;2.省去了强制转换的过程。

JDK升级一般可分为三个大的方面:1.简化书写;2.提高效率;3.提高安全性。而泛型就属于其中的第三方面安全,它是一种安全机制。


二.利用反射穿透泛型限制

泛型能绝对保证集合中存入数据都是它限定的类型吗?


ArrayList<Integer> collection2 = new ArrayList<Integer>();
System.out.println(collection1.getClass()==collection2.getClass());
collection2.add(“123”);//这句会报错
collection2.getClass().getMethod("add", Object.class).invoke(collection2, "hello");
System.out.println(collection2.get(0)); //结果却为hello
这段代码让你惊讶吧?已经限制集合中元素的类型为Integer,可用反射却能将String存入,为什么?

这是因为泛型是给编译器用的,运行时就没有这些泛型信息了,这叫做“去泛型化”,所以可以通过反射,获取集合字节码加入非指定的类型。


三、ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:

1.ArrayList<E>:这个整体称为“泛型类型”,其中的“E”称为 类型变量 或 类型参数 。

2.ArrayList<Integer>:整体称为“参数化的类型”,“Integer”称为“类型参数的实例”或“实际类型参数”,"<>"读为typeof,ArrayList称为“原始类型”。

3.参数化类型与原始类型的兼容性:可以互相引用,但编译器会报告警告。

4.参数化类型不考虑类型参数的继承关系

5.编译器不允许创建类型变量的数组。在创建数组实例时,数组的元素不能使用参数化的类型。


Collection<String> c = new Vector();
Collection c1 =  new Vector<String>();
//      见第4条
//错误语句  Vector<String> v=new Vector<Object>();
//错误语句  Vector<Object> v1=new Vector<String>();
Vector  v2=new Vector<String>();
Vector<Object> v3 = v2;

//错误语句  Vector <Integer>  [] vectorList = new Vector <Integer>[10];//见第5条。
Vector <Integer[]>   vectorList = new Vector <Integer[]>();


四、扩展应用:泛型中的通配符“?”

1.限定通配符的上边界

Vector<? extends Number> x = new Vector<Integer>();正确的

Vector<? extends Number> x = new Vector<String>():错误的。

2.限定通配符的下边界

Vector<? super Integer> x = new Vector<Number>();正确的。

Vector<? super Integer> x = new Vector<Byte>();错误的。

注意:限定通配符总是包括它自己。

printCollection_2(collection2);
//      Class<Number> x = String.class.asSubclass(Number.class);//错误。
//      Class x1 = String.class.asSubclass(Number.class);
//      Class<String> y = Class.forName("java.lang.String");//错误
Class y = Class.forName("java.lang.String");//要抛出异常。
Class<?> y1;
Class<String> y2 = null;
y1=y2;
//      y2=y1;


五、泛型集合类的综合应用案例


HashMap<String,Integer> hm = new HashMap<String,Integer>();
hm.put("zyq", 18);
hm.put("zsy", 49);
hm.put("zyx", 25);

Set<Map.Entry<String,Integer>> entrySet = hm.entrySet();
for(Map.Entry<String, Integer> entry:entrySet){
System.out.println(entry.getKey() + ":" + entry.getValue());
}


六、定义泛型方法

1.泛型类似C++中的模板,但没有C++中的功能强大。

2.泛型的实际类型参数只能是引用数据类型,例如:对于HashMap<K,V>,K和V不能是八种基本数据类型。

3.异常也可以用泛型

4.类型参数的类型推断


例一:模拟C++中的模板实现求和功能(但没有C++中好用)


add(1,2);
Number x1 = add(1,1.4);//int 和float的最大公共集是Number
Object x2 = add(1,"abc");//String 和int的最大公共集是Object

private static<T> T add(T x,T y){//取得的T是 x 和  y的最大公共集,其实也是java中多态的体现。
return null;
}


例二:实现数组中的元素位置交换

swap(new String[]{"abc","123","hello"},0,1);
//      swap(int[]{1,2,3,4},2,3);//int是基本数据类型,所以不能实现。
[java] view plaincopy
private static<T> void swap(T[] t ,int x,int y){
T temp = t[x];
t[x] = t[y];
t[y] = temp;
}


例三:

ArrayList<Integer> al = new ArrayList<Integer>();
al.add((Integer)autoConvert(345));
System.out.println(al.get(0));

String s = autoConvert("123");
System.out.println(s);
fillArray(new Integer[]{1,3,4},1);

copy1(new Vector<String>(), new String[]{"123","5674"});
copy2(new Date[20], new String[10]);//这个是两个取交集。
//      copy1(new Vector<Date>(), new String[]{"123","5674"});
//类型推断的传播性,Vector中T已经指定为Date,后边的T也应该是Date,否则报错。

public static<T> void fillArray(T[] t,T obj){
for(int x= 0;x<t.length;x++){
t[x]= obj;
}
}
public static <T> T autoConvert(Object obj){
return (T)obj;
}

public static <T>void copy1(Collection<T> des ,T[] src){

}
public static <T>void copy2(T[] des ,T[] src){

}


七、自定义泛型类

import java.util.Set;
//dao data access object:CRUD
public class GenericDao<E> {
//增
public void add(E x){

}
//删
public void delete(int id){

}
public void delete(E obj){

}
//查
public E findByID(int id){
return null;
}
public E findByName(String name){
return null;
}

public Set<E> findByConditions(String where){
return null;
}

//改
public void update(E obj){

}
public static<E> void update1(E obj){//静态方法不能用类上定义的泛型参数,但可以自己定义泛型,这里的E和类上的E是两码事。

}
}
GenericDao<ReflectPoint> dao = new GenericDao<ReflectPoint>();
dao.add(new ReflectPoint(5, 7));
//      String s = dao.findByID(1);//返回的也必须是ReflectPoint


八、通过反射获得泛型的参数化类型

没办法通过泛型的引用,用反射 获取参数化类型的类型参数。

但可以通过反射获得方法的参数列表,从参数列表中获取参数化类型(ParameterizedType)的

原始类型(RawType)和实际类型参数(ActualTypeArguments)


import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Vector;
class GenericTest {
public static void main(String[] args) throws Exception{
Method applyMethod =  GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types =applyMethod.getGenericParameterTypes();
ParameterizedType pType =(ParameterizedType) types[0];

System.out.println(pType.getClass());
System.out.println(pType.getOwnerType());
System.out.println(pType.getRawType());
System.out.println(pType.getActualTypeArguments()[0]);
}

public static void applyVector(Vector<Date> v){

}
/*
public static void applyVector(Vector<Integer> v){ //这个方法和上边的方法是同一个方法。

}*/
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: