泛型、JavaBean内省、beanutils工具包


---------------

泛型

-----------------------------------------------------------------------------------------------------------------------------------

JDK1.5版本以后出现新特性。是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器、编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。


由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据。

例如,用反射得到集合,再调用其add方法即可。

 

好处

1.将运行时期出现问题ClassCastException,转移到了编译时期。,

方便于程序员解决问题。让运行时问题减少,安全。,

2,避免了强制转换麻烦。

 

<>:什么时候用呢?

当操作的引用数据类型不确定的时候,就使用<>。将要操作的引用数据类型传入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。

在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。

 

import java.util.*;   
class GenericDemo    
{   
    public static void main(String[] args)    
    {   
        //使用泛型进行限定元素类型   
        ArrayList<String> al = new ArrayList<String>();   
  
        al.add("abc01");//被限定以后,只能添加与限定类型相同类型的元素   
        al.add("abc0991");   
        al.add("abc014");   
  
        //al.add(4);   
        ////al.add(new Integer(4));//如果添加的元素类型不正确会编译失败   
           
  
        Iterator<String> it = al.iterator();   
        while(it.hasNext())   
        {   
            String s = it.next();   
  
            System.out.println(s+":"+s.length());   
        }   
    }   
} 
//在使用接口是时候指定类型   
class LenComparator implements Comparator<String>   
{   
    //在接口上指定以后,内部使用的都是相同的类型   
    public int compare(String o1,String o2)   
    {   
        int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));   
  
        if(num==0)   
            return o2.compareTo(o1);   
        return num;   
    }   
} 

 

泛型类

什么时候定义泛型类?

当类中要操作的引用数据类型不确定的时候,

早期定义Object来完成扩展。

现在定义泛型来完成扩展。

 

//泛型前做法。   
class Tool   
{   
    private Object obj;   
    public void setObject(Object obj)   
    {   
        this.obj = obj;   
    }   
    public Object getObject()   
    {   
        return obj;   
    }   
}   
  
//在有了泛型以后,将泛型定义到类上   
class Utils<QQ>   
{   
    private QQ q;   
    public void setObject(QQ q)//类中的方法可以使用泛型进行定义   
    {   
        this.q = q;   
    }   
    public QQ getObject()   
    {   
        return q;   
    }   
}   
  
  
class  GenericDemo3   
{   
    public static void main(String[] args)    
    {   
        //在创建该类对象的时候指定类型   
        Utils<Worker> u = new Utils<Worker>();   
  
        u.setObject(new Student());   
        Worker w = u.getObject();   
  
        /*按照以前的做法,要处理任意类型的时候,使用到某个类型特有的 方法,需要进行强转。  
        Tool t = new Tool();  
        t.setObject(new Student());  
        Worker w = (Worker)t.getObject();  
        */  
    }   
}  

----------------------------------------------------------------------------------------

泛型的擦除和补偿:

泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全。

泛型的擦除:运行时,会将泛型去掉,生成的class文件中是不带泛型的。

为什么擦除呢?为了兼容运行的类加载器。


泛型的补偿:在运行时,通过获取元素的类型进行转换动作,不用使用者再强制转换了。

注意:泛型内只能定义引用数据类型,不能定义基本数据类型。

 -------------------------------------------------------------------------------------

泛型的通配符和泛型的限定:

? 未知类型。

泛型的限定:

? extends Person 接收Person类型或者Person的子类对象。上限。一般在存储元素的时候使用

? super Person 接收Person类型或者Person的父类对象。下限。通常对集合中的元素进行去除操作时使用。


通配符中需要注意的问题

定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,该方法如何定义呢?

错误方式:

 

public static void printCollection(Collection<Object> cols) {  
    for(Object obj:cols) {  
        System.out.println(obj);  
    }  
    /* cols.add("string");//没错  
     cols = new HashSet<Date>();//错误!*/  
}  


正确方式:

public static void printCollection(Collection<?> cols) {  
    for(Object obj:cols) {  
        System.out.println(obj);  
    }  
    //cols.add("string");//错误,因为它不知自己未来匹配就一定是String  
    cols.size();//没错,此方法与类型参数没有关系  
    cols = new HashSet<Date>();  
}  


总结:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
 

泛型中需要注意的知识点:
参数化类型与原始类型的兼容性:
参数化类型可以引用一个原始类型的对象,编译报告警告,例如,Collection<String> c = new Vector();//为了兼容之前的程序
原始类型可以引用一个参数化类型的对象,编译报告警告,例如,Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去
参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>(); //错误
Vector<Object> v = new Vector<String>(); //错误!
在创建数组实例时,数组的元素不能使用参数化的类型:
例如,下面语句有错误:
 Vector<Integer>[] vectorList = new Vector<Integer>[10];

自定义泛型方法:
交换数组中的两个元素的位置的泛型方法语法定义如下:

static <E> void swap(E[] a, int i, int j) {  
    E t = a[i];  
    a[i] = a[j];  
    a[j] = t;  
}  


注意:只有引用类型才能作为泛型方法的实际参数,E代表的是引用数据类型,E[]a就是引用数据类型的数组。swap(new int[3],3,5);语句会报告编译错误。

自定义泛型类:
如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如下:

public class GenericDao<T> {  
    private T field1;  
    public void save(T obj){}  
    public T getById(int id){}  
}  

 

--------------------------------------------------------------------------------------------------------------------------------------

JavaBean  内省与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,就被称为内省。(参看avaAPI文档中的java.beans包和java.beans.beancontext)

3.对JavaBean的简单内省操作 

 

import java.beans.BeanInfo;  
import java.beans.Introspector;  
import java.beans.PropertyDescriptor;  
import java.lang.reflect.Method;  
  
public class IntroSpector {  
    public static void main(String[] args) throws Exception{  
        ReflectPoint pt1 = new ReflectPoint(3, 5);  
        String propertyName = "x";  
        PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());  
  
        Method methodGetX1 = pd.getReadMethod();  
        Object retVal1 = methodGetX1.invoke(pt1);  
        System.out.println(retVal1);  
          
        Method methodSetX = pd.getWriteMethod();  
        methodSetX.invoke(pt1, 7);  
        System.out.println(pt1.getX());  
//      内省的复杂操作方法  
        BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());  
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();  
          
        Object retVal = null;  
        for(PropertyDescriptor pd1 : pds){  
            if(pd1.getName().equals(propertyName)){  
                Method methodGetX = pd.getReadMethod();  
                retVal = methodGetX.invoke(pt1);  
                break;  
            }  
        }  
        System.out.println(retVal);  
    }  
}  


 ---------------------------------------------------------------------------------------------------------------------------------

.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());  
    </SPAN>  


 

BeanUtils:以字符串(String)的形式对JavaBean 的属性进行操作,getProperty方法得到的属性值是以字符串形式返回的(网络开发时,获取的用户数据类型都是String)。

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

[ 知识积累]

JDK1.7的新特性之一:Map map = {name:"zhangssan",age:18};
BeanUtils也可以对Map集合进行操作:BeanUtils.setProperty(map, name, "lisi");

 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值