java 泛型

Jdk 1.5以前的集合类中存在什么问题

ArrayList collection = new ArrayList();

collection.add(1);

collection.add(1L);

collection.add("abc");

int i = (Integer) collection.get(1);//编译要强制类型转换且运行时出错!

Jdk 1.5的集合类希望你在定义集合时,明确表示你要向集合中装哪种类型的数据,无法加入指定类型以外的数据

ArrayList<Integer> collection2 = new ArrayList<Integer>();

collection2.add(1);

/*collection2.add(1L);

collection2.add(“abc”);*///这两行代码编译时就报告了语法错误

int i2 = collection2.get(0);//不需要再进行类型转换

泛型是提供给javac编译器使用的,

利用反射穿透泛型限制 (暴力反射)

泛型能绝对保证集合中存入数据都是它限定的类型吗?先看下边的代码

package july78javaEnhance;

import java.util.ArrayList;

public class Demo23 {

    public static void main(String[] args) {

        ArrayList<Integer> collection2 = new ArrayList<Integer>();  

        System.out.println(collection1.getClass()==collection2.getClass());  

        collection2.add(“真暴力”);//这句会报错   

        collection2.getClass().getMethod("add", Object.class).invoke(collection2, "真暴力");  

        System.out.println(collection2.get(0)); //结果却为真暴力 

        //已经限制集合中元素的类型为Integer,可用反射却能将String存入,为什么? 这是因为泛型是给编译器用的,运行时就没有这些泛型信息了,这叫做“去泛型化”,所以可以通过反射,获取集合字节码加入非指定的类型。

    }

}

泛型中的?通配符的扩展

  限定通配符的上边界:

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

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

  限定通配符的下边界:

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

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

提示:

限定通配符总是包括自己。

?只能用作引用,不能用它去给其他变量赋值

Vector<? extends Number> y = new Vector<Integer>();

Vector<Number> x = y;

上面的代码错误,原理与Vector<Object > x11 = new Vector<String>();相似,

只能通过强制类型转换方式来赋值。

Eg:

泛型集合类的综合案例 

能写出下面的代码即代表掌握了Java的泛型集合类: 

 HashMap<String,Integer> hm = new HashMap<String,Integer>(); 

  hm.put("zxx",19); 

  hm.put("lis",18); 

   

  Set<Map.Entry<String,Integer>> mes= hm.entrySet(); 

  for(Map.Entry<String,Integer> me : mes) { 

   System.out.println(me.getKey() + ":" + me.getValue()); 

  } 

由C++的模板函数引入自定义泛型 

如下函数的结构很相似,仅类型不同: 

int add(int x,int y) { 

            return x+y; 

     }   

float add(float x,float y) { 

            return x+y;      

    }    

double add(double x,double y) { 

            return x+y;      

    }    

C++用模板函数解决,只写一个通用的方法,它可以适应各种类型,示意代码如下: 

    template<class T>  

    T add(T x,T y) { 

            return (T) (x+y); 

    } 

类型参数的类型推断(花了张老师两天的时间总结)

l 编译器判断范型方法的实际类型参数的过程称为类型推断,类型推断是相对于知觉推断的,其实现方法是一种非常复杂的过程。

l 根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:

1.当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:

 swap(new String[3],3,4)   à    static <E> void swap(E[] a, int i, int j)

2.当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:

 add(3,5)   à static <T> T add(T a, T b)

3.当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题:

 fill(new Integer[3],3.5f)   à static <T> void fill(T[] a, T v)

4.当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型, 并且使用返回值,这时候优先考虑返回值的类型,例如,下面语句实际对应的类型就是Integer了,编译将报告错误,将变量x的类型改为float,对比eclipse报告的错误提示,接着再将变量x类型改为Number,则没有了错误:

 int x =(3,3.5f)   à static <T> T add(T a, T b)

5.参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题:

copy(new Integer[5],new String[5]) à static <T> void copy(T[] a,T[]  b);

copy(new Vector<String>(), new Integer[5]) à static <T> void copy(Collection<T> a , T[] b);

定义泛型类型

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

public class GenericDao<T> {

private T field1;

public void save(T obj){}

public T getById(int id){}

}

       类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:

GenericDao<String> dao = null;

new genericDao<String>();

       注意:

在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。

当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数。

       问题:类中只有一个方法需要使用泛型,是使用类级别的泛型,还是使用方法级别的泛型?

(Create)、查询(Retrieve)(重新得到数据)、更新(Update)和删除(Delete)几个单词的首字母简写 

import java.util.Set; 

//dao data access object(数据访问对象)--->crud 

public class GenericDao<E>  { 

    public void add(E x){ 

    } 

    public E findById(int id){ 

        return null; 

    } 

    public void delete(E obj){ 

    } 

    public void delete(int id){ 

    }    

    public void update(E obj){ 

    } 

    public static <E> void update2(E obj){ 

    } 

    public E findByUserName(String name){ 

        return null; 

    } 

    public Set<E> findByConditions(String where){ 

        return null; 

    } 

原文地址:https://www.cnblogs.com/fanweisheng/p/11137845.html