学习笔记07—泛型

来源:互联网 发布:阿里云域名解析冲突 编辑:程序博客网 时间:2024/04/28 06:31


泛型的真正内容可以说是博大精深。

据说有复杂的数学证明云云。。。


泛型说到底也是运用抽象思维模式对现实世界进行抽象的产物。 


过去在农村,人们把猪、牛、羊、猫、狗、鸡、鸭都养在一起,虽然这样有利于动物们相互交流感情,但是不利于分类管理,

后来条件好了,人们便把猪放进猪圈,把羊放进羊圈,把猫放进猫......洞。。。一个场所只养一类动物,这样才更有利于它们健康成长。

这就是泛型。


可是话又说回来,要具体情况具体分析。家畜混养其实是一门学问。

把适合混养的两种家畜放在一起有时候可以降低成本,提高产量,增进动物种群间的相互交流。

举一个例子,把羊和兔子放在一起养是经过实践证明了的养殖方式。好处是兔子得病少。。。扯远了。。。。


但是从数学和逻辑上看,泛型要复杂的多。在本篇仅仅介绍基本应用。





泛型


入门

通过反射手段绕过泛型的限制

 

集合上的泛型仅仅在编译前起到约束作用,编译时会去掉泛型信息

ArrayList<String>的字节码和ArrayList<Integer>的字节码是完全一样的

 

例程:

 

package cn.itcast.day2; import java.lang.reflect.InvocationTargetException;import java.util.ArrayList; public classGenericTest {    /**     * @param args     */   publicstaticvoidmain(String[] args) throws Exception {        // TODO Auto-generated method stub        ArrayList collec = new ArrayList();        collec.add(1);        collec.add(1L);        collec.add("abc");         // 不知道添加的元素类型,会发生类转换异常        // int i = (Integer) collec.get(1);        // System.out.println(i);         ArrayList<String> collec2 = newArrayList<String>();        collec2.add("abc");         ArrayList<Integer> collec3 = newArrayList<Integer>();        collec3.add(2);               // 泛型是给编译器看的,编译时会去掉类型信息        // 泛型是Integer和String的ArrayList,其字节码是相同的        boolean flag = collec2.getClass() ==collec3.getClass();        System.out.println(flag);         // 根据上面的原理,可以通过反射,绕过泛型,向集合添加其他类型元素        // 尽管collec3是个带有Integer泛型的ArrayList对象,但是可以用反射方法添加String对象        collec3.getClass().getMethod("add", Object.class).invoke(collec3, "def");        System.out.println(collec3.get(1)); // 输出def,成功添加   } }


 

 

了解泛型其他特点

 

了解泛型

 

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:

 

    整个称为ArrayList<E>泛型类型

    ArrayList<E>中的E称为类型变量或类型参教

    整个ArrayList<Integer>称为参数化的类型

    ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数

    ArrayList<Integer>中的<>念着typeof

    ArrayList称为原始类型

 

参数化类型与原始类型的兼容性:

 

    参数化类型可以引用一个原始类型的对象.编译报告警告.例如

    Colloctlon<String>c = new Vector(); //可不可以,不就是编译器一句话的事吗?

    原始类型可以引用一个参数化类型的对象,编译报告警告,例如

    Colloctlonc = new Vector<String>(); //原来的方法接受一个集合参数,新的类型也要能传进去

 

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

 

    Vector<String>v = new Vector<Object>(); //错误!不写<Object>没错,写了就是明知故犯

    Vector<Object>v = new Vector<String>(); //也错误!

 

在创建数组实例时.数组的元素不能使用参数化的类型,例如,下面语句有错误:

    Vector<Integer>  vectorList[] = new Vector<Integer>[10];

 

思考题:下面的代码会报错误吗?

    Vectorv1 = new Vector<String>();

    Vector<Object>v = v1;

 

解答:

    不会报错。按行解释。

 

 

 

泛型的通配符和扩展

通配符?

extends、super用于限定?的上下边界

extends还可以用到& 表示多个接口的子类

泛型集合的综合应用

 

// 泛型集合的综合应用,HashMap转成Set并输出其元素HashMap<String, Integer> map =newHashMap<String, Integer>();// 添加键值对map.put("a", 24);map.put("b", 25);map.put("c", 26); // 转换为SetSet<Map.Entry<String,Integer>> entrySet = map.entrySet();// 迭代for (Map.Entry<String, Integer> entry : entrySet) {   System.out.println(entry.getKey()+ " : "+ entry.getValue());}


 

 

自定义泛型的语法和类型推断

在返回值前用<T>表示定义一个泛型

 

例如:(仅用于演示语法)

   publicstatic<T> T add (T a, T b) {

        return null;

    }

在使用时返回值要取a和b的并集

        Object obj = add(5, "abc");

       Number f = add(3, 3.56);

 

 

 

一个具有实际意义的例子:

// 一个具有实际意义的运用泛型的方法,交换任意类型数组中两个元素的位置   publicstatic<T> voidswap (T[] t, inta, intb) {        T tmp =t[a];        t[a] = t[b];        t[b] = tmp;    }


 

在main中调用该方法:

        String[] strs = new String[] {"ab", "OK", "hello"};        swap(strs, 1, 2);        for (String str : strs) {            System.out.println(str);       }


 

输出:

ab

hello

OK

 

但是,需要注意的是上面的例子换成int[]就不可以了。

T只能代表引用类型。

只有引用类型才能作为泛型方法的实际参数。

在用于演示语法的例子中之所以能够用int类型是因为“自动装箱”的缘故。

 

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

Vector<Date> v = newVector<Date>();

通过v.getClass()无法获得参数化类型

 

将其传递给一个方法,可实现此功能。

 

public static void applyVector(Vector<Date>v){} Method applyMethod =GenericTest.class.getMethod("applyVector", Vector.class);Type[] types =applyMethod.getGenericParameterTypes();ParameterizedType pType =     (ParameterizedType)types[0];System.out.println(pType.getRawType());//VectorSystem.out.println(pType.getActualTypeArguments()[0]);//Date



附篇:

源文档 <http://blog.csdn.net/wzg199088/article/details/6755711

,堆栈,变量,数组,集合,泛型集合

数组是类型相同,长度固定的存储方式。

集合是类型不同,长度可变的存储方式。

而泛型集合则是类型相同,长度可变的存储方式。

 

泛型:

将类的类型作为参数,制定到其他类或者方法上从而保证类型转换的安全和稳定。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法

定义:将类的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性

好处:是在编译的时候检查类型,并且所有的强制转换都是自动和隐式的,提高代码的重用率。保证编译正确,复用性强,安全性高。

类型参数化:所操作的数据类型被指定为一个参数

类型变量:一种非限定性标识符,用来指定类,接口和方法的类型。规范:.使用大写较短.E表示集合的元素类型 K V -值对T任意类型

擦除:将具有泛型信息的对象赋给一个没有泛型信息的变量,则会发生擦除的现象。

 

泛型接口:实现类必须是泛型类,且类型参数列表一致

注意   Driver<T>   Person为实现类

建立类型参数在实现时,不加修改。在创建时将具体形式传递给接口 

类型参数不为实际类型时,实现类必须是泛型类

public class Person<T> implements Driver<T> 

当实现特定类型的泛型接口时,实现类可以不是泛型

public class Person implements Driver<String>

优势:

针对不同数据类型实现

对接口数据类型进行限制

 

泛型类:

泛型类与非泛型类的层次关系区别在于,泛型类层次的全部子类必须将泛型父类需要的参数类型,逐级想上进行传递,这种传递方式与构造方法的向上调用很类似

注意:①定义对象需要指定数据类型 使用构造也需要指定类型

泛型类派生子类 允许泛型子类为

class B extends A  虽然不抱错但失去了泛型的意义,A中包含的T会转变成Object

class B<T> extends A<T>可以在使用的过程中指定T的类型

class B<T,V> extendsA<T> TA中的类型,也可以指定B所特有的类型V这样就扩展了B

class B extends A<String>也可以直接指定AT的类型,就不需要在B中重复指定了

注意:

1.使用非泛型类继承泛型类或实现接口是,父类和接口中不能再包含类型参数

2.在派生子类时,可使用实际类型代替父类中的参数类型。子类可不再指定类型

3.允许在使用泛型类或接口时,不传入实际参数代替,编译警告。子类重写时会转换父类参数类型为Object

 

泛型方法:非/泛型类,不依赖泛型类或接口

public<T> void test(Tt){} 无须显示传入实际类型参数,根据传入参数

 

类型通配符:

普通通配符:类<?>对象名 = new2<指定类型>

有限制的通配符(有界通配符):

?  extends  A   <=     当前类,父类

?  super     B   >=      当前类,活这当前类的超类

 

总结:

(1)泛型  泛型的类型参数只能是类(自定义类)不能是简单类型

(2)同一种泛型,可对应多个版本,不同版本泛型实例不兼容

(3)泛型类型多个

(4)有界通配符

(5)通配符?



原创粉丝点击