泛型

 

  泛型是java1.5之后才引入的,为什么要引入泛型:

  1 为了使类型参数化

  2 提高类型的安全性并简化类型转换的过程,在泛型处理过程中,类型的转换都是自动和隐士的,泛型让类型检查从运行期提前到编译器,出错能预先提示。

在没有泛型的情况:

class TestObj{
    private Object obj = null;
    public TestObj(Object obj) {
        this.obj = obj;
    }
    public void speak() {
        System.out.println(this.obj.getClass());
    }
    public Object getObj() {
        return obj;
    }
}


        Integer i1 = new Integer(10);
        TestObj to = new TestObj(i1);
        
        to.speak();
        Integer i2 =(Integer)to.getObj();
        System.out.println(i2);
    

在这里Integer i2 =(Integer)to.getObj(); 类型转换是不安全的。如果不能确认object类型是integer 那么就会出错。

在看看泛型:

class GenObj <T>{
    private T obj;
    public GenObj(T obj){
        this.obj = obj;
    }
    public void speak() {
        System.out.println(obj.getClass());
    }
    public T getObj() {
        return (T)obj;
    }
}

        Integer i1 = new Integer(10);
        //GenObj go = new GenObj(i1);
        GenObj<String> go = new GenObj<String>("123");
        go.speak();
        
    

如果用GenObj go = new GenObj(i1); 来实例化引入泛型的对象会出现警告:

提示说要对通用类型的引用参数化,这里参数化就是<>里的,这句话就是开头说的为了使类型参数化;

引入的泛型之后就不用使用显示的强制类型转换了。

        Integer i1 = new Integer(10);
        //GenObj go = new GenObj(i1);
        GenObj<String> go = new GenObj<String>("123");
        go.speak();
        String st1 = go.getObj();
        System.out.println(st1);
    

如果类型错误,编译器会报错。
泛型参数T 必须是引用类型,不能基本数据类型(int long char等等);

多个参数的泛型:

class MutilGen<K,V>{
    private K k1;
    private V v1;
    public MutilGen(K k1,V v1) {
        this.k1 = k1;
        this.v1 = v1;
    }
    public K getK1() {
        return k1;
    }
    public V getV1() {
        return v1;
    }
    public void speak() {
        System.out.println(this.k1.getClass()+":"+this.k1.toString());
        System.out.println(this.v1.getClass()+":"+this.v1.toString());
    }
}
        MutilGen<String, Integer> mg = new MutilGen<String, Integer>("你好", 1);
        mg.speak();

执行结果是:
class java.lang.String:你好
class java.lang.Integer:1

多参数用逗号隔开。

泛型的类型边界

为什么要有类型边界呢,看下面这个程序。

public class SumTest<M> {

    M[] tsMs;
    double sum=0;
    public SumTest(M[] tsMs) {
        this.tsMs = tsMs;
    }
    public double Sum() {
        for(int i=0;i<tsMs.length;i++) {
            sum +=tsMs[i].doubleValue();        }
        return sum;
   }
}

这里tsMs[i].doubleValue();会报错,为什么呢,因为定义的泛型参数M 编译器并不知道是什么类型,所以这里用doubleValue()肯定是不行的。如果我们确认传入的参数一些数据类型,也就是说这些参数是在一个范围的,有点像c语言的枚举类型,将泛型参数的边界确定下来,看修改之后的程序:

public class SumTest<M extends Number> {

    M[] tsMs;
    double sum=0;
    public SumTest(M[] tsMs) {
        this.tsMs = tsMs;
    }
    public double Sum() {
        for(int i=0;i<tsMs.length;i++) {
            sum +=tsMs[i].doubleValue();
        }
        return sum;
    }
    
    public static void main(String[] args) {
        Integer[] intArr = new Integer[3];
        ArrayList<Integer> intList = new ArrayList<Integer>();
        intList.add(100);
        intList.add(10);
        intList.add(200);
        intArr = intList.toArray(new Integer[0]);
        SumTest<Integer> st = new SumTest<Integer>(intArr);
        System.out.println(st.Sum());
    }
}

结果是310.0
因为数据类型 Byge Double Long Integer Short的父类是Number,所以用externds 来确定泛型M的边界,我感觉非常类似与c语言里的枚举类型,举个例子:

typedef enum{
    Monday = 0,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}Week;

void ShowDay(Week day){
    switch(day){
        case 0:printf("Monday\r\n");break;            
        case 1:printf("Monday\r\n");break;
        case 2:printf("Tuesday\r\n");break;
        case 3:printf("Wednesday\r\n");break;
        case 4:printf("Thursday\r\n");break;
        case 5:printf("Saturday\r\n");break;
        case 6:printf("Sunday\r\n");break;
        default:break;
    }
}
ShowDay(Monday);


通配符:

    M[] tsMs;
    double sum=0;
    public SumTest(M[] tsMs) {
        this.tsMs = tsMs;
    }
    public double Sum() {
        for(int i=0;i<tsMs.length;i++) {
            sum +=tsMs[i].doubleValue();
        }
        return sum;
    }
    public boolean SumEqual(SumTest<M> st) {
        if(this.Sum() == st.Sum()) {
            return true;
        }else {
            return false;
        }    
    }
    public static void main(String[] args) {
        Integer[] intArr = {1,2,3};
        Integer[] intArr1 = {1,2,3};
        Double[] dblArr = {1.0,2.0,3.0};
        SumTest<Integer> st = new SumTest<Integer>(intArr);
        SumTest<Integer> st1 = new SumTest<Integer>(intArr1);
        SumTest<Double> st2 = new SumTest<Double>(dblArr);
        System.out.println(st.SumEqual(st1));
        System.out.println(st.SumEqual(st2));//这里会报错  
}

这里加入一个public boolean SumEqual(SumTest<M> st) 方法,传入的是参数是SumTest,如果按照这样定义会出现参数不匹配,这里很好理解,因为st1传入的是Integer,而st2是Double类型,那么怎么解决这个问题呢。将泛型参数<M>改成通配符<?>即可。

    public boolean SumEqual(SumTest<?> st) {
        if(this.Sum() == st.Sum()) {
            return true;
        }else {
            return false;
        }    
    }

结果是:
true
false

 

posted @ 2016-03-13 22:12  麦哈顿博士  阅读(212)  评论(0编辑  收藏  举报