泛型学习总结

泛型概念:

泛型(Generic)一、泛型的作用JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的 java程序后,生成的class文件 

泛型的作用

JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。 

注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的 java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

泛形的基本术语,以ArrayList<E>为例:

<>念着typeof

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

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

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

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

使用泛形时,泛形类型须为引用类型,不能是基本数据类型

自定义泛型:泛型方法

Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛形前,必须对泛形进行声明,语法:<T> ,T可以是任意字母,但通常必须要大写。<T>通常需放在方法的返回值声明之前。例如:public static <T> void doxx(T t); 

1.编写一个泛形方法,实现数组元素的交换

public static <T> void test1(T arr[],int i,int j){

        T temp=arr[i];

        arr[i]=arr[j];

        arr[j]=temp;

public static void main(String[] args) {

        Integer arr[]={1,2,3,4};

        test1(arr,0,2);

        for(int ar:arr){

           System.out.println(ar);

        }

2.编写一个泛形方法,接收一个任意数组,并颠倒数组中的所有元素

public static<T> void test2(T arr[]){

        int startindex=0;

        int endindex=arr.length-1;

        for(;;){

            if(startindex>=endindex){

                break;

            }

            Ttemp=arr[startindex];

            arr[startindex]=arr[endindex];

            arr[endindex]=temp;

            startindex++;

            endindex--;

             }

}

public static void main(String[] args) {

        Integer arr[]={1,2,3,4};

        test2(arr);

        for(int ar:arr){

           System.out.println(ar);

        }

}

 

注意

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

在泛型中可以同时有多个类型,例如: 

public static<K,V> V getValue(K key) {

return map.get(key);

}

 

如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:

public class GenericDao<T> {

        private T field1; 

        public void save(T obj){ 

        }        

        public T getId(int id){ 

        }

}

静态方法不能使用类定义的泛形,而应单独定义泛形 


泛型应用举例:

package com.generictest.learning;


import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;


/**
 * 泛型的使用举例
 * @author Administrator
 *
 */
public class GenericTest {


/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<String, Integer> man=new HashMap<String, Integer>();
man.put("A", 1);
man.put("B", 2);
man.put("C", 3);

/**
* 通过反射向定义为泛型的Map集合添加元素可以绕过泛型的限制
* 因为泛型是在编译时起作用的,在运行时所有定义的泛型都被JVM去掉
*/
try {
man.getClass().getMethod("put", new Class[]{Object.class,Object.class}).invoke(man, new Object[]{"D","maolei"});

}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

/**
* 把Map转换为Set集合
* 此处可以证明泛型是可以嵌套的
*/
Set<Entry<String, Integer>> mn = man.entrySet();
for(Entry<String, Integer> en:mn){
System.out.println(en.getKey()+":"+en.getValue());
}

/**
* 泛型不是协变的
* 关于泛型的混淆,一个常见的来源就是假设它们像数组一样是协变的。
* 其实它们不是协变的。List<Object>不是List<String>的父类型。 
*/
List<Integer> in=new ArrayList<Integer>();
//List<Number> nu=in;  编译不通过

Integer[] intArray = new Integer[10]; 
Number[] numberArray = intArray; 

List<String> st=new ArrayList<String>();
st.add(new String("maolei"));
st.add(new String("maoqingshan"));
//可以将带泛型的对象传递给一个不带泛型的形式变量
printList(st);

List l=st;//是合法的因为:List<String>是一个List

printList2(l);//是合法的因为:List是一个List<Object>

//printList2(st);//编译不通过因为:List<String>不是一个List<Object>

/**
* printList3采用通配符的泛型
* 可以接受任何泛型类型的集合
*/
printList3(st); //合法的
List<Integer> itg=new ArrayList<Integer>();
itg.add(new Integer(1));
itg.add(new Integer(2));
printList3(itg);//合法的

/**
* 下面的代码则工作得很好
* 对于lu,编译器一点都不知道List的类型参数的值。但是编译器比较聪明,它可以做一些类型推理,
* 它推断未知的类型参数 必须扩展Object。这个特定的推理没有太大的跳跃,但是编译器可以作出一些非常令人佩服的类型推理。
* 所以它让您调用List.get()并推断返回类型为Object。
*/
List<Integer> li = new ArrayList<Integer>(); 
li.add(new Integer(42)); 
List<?> lu = li; 
System.out.println(lu.get(0)); 

/**
* 对于lm,编译器不能对List的类型参数作出足够严密的推理,以确定将Integer传递给List.add()是类型安全的。
* 所以编译器将不允许您这么做。
* 对于lm不能操作与泛型有关的方法,add(E e)是与泛型有关的,clear()是与泛型无关的
*/
List<Integer> ll = new ArrayList<Integer>(); 
ll.add(new Integer(42)); 
List<?> lm = ll; 
//lm.add(new Integer(43)); // error 
lm.clear();//可以正常编译

/**
* 泛型方法的使用
*/
Object rtnValue1 = ifThenElse(true,new String("maolei"),new Integer(12));
Object rtnValue2 = ifThenElse(false,new Date(),new HashMap<String, Integer>());
Object rtnValue3 = ifThenElse(true, "pi", new Float(3.14));

String rtnValue4=ifThenElse(false, new String("a"), new String("b"));
Integer rtnValue5=ifThenElse(true, new Integer(12), new Integer(21));
//String rtnValue6=ifThenElse(false, new String("a"), new Integer(2));//编译不通过
System.out.println(rtnValue1);
System.out.println(rtnValue2);
System.out.println(rtnValue3);
System.out.println(rtnValue4);
System.out.println(rtnValue5);



}

/**
* 不采用泛型打印一个集合
* @param l
*/
private static void printList(List l){

Iterator it = l.iterator();
while(it.hasNext()){
System.out.println(it.next());
}

}
/**
* 采用泛型打印一个集合
* @param l
*/
private static void printList2(List<Object> l){

Iterator it = l.iterator();
while(it.hasNext()){
System.out.println(it.next());
}

}

/**
* 采用通配符的泛型打印一个集合
* List<?>是任何泛型List的父类型,所以您完全可以将 List<Object>、List<Integer>或 List<List<List<Flutzpah>>>传递给printList()
* @param l
*/
private static void printList3(List<?> l){

Iterator it = l.iterator();
while(it.hasNext()){
System.out.println(it.next());
}

}

/**
* 泛型方法
* 根据它的第一个参数的布尔值,它将返回第二个或第三个参数
* 为什么要用泛型方法:
* 1:当泛型方法是静态的时,这种情况下不能使用类类型参数。 
* 2:当T上的类型约束对于方法真正是局部的时,
* 这意味着没有在相同类的另一个方法签名中使用相同类型 T 的约束。
* 通过使得泛型方法的类型参数对于方法是局部的,可以简化封闭类型的签名。 
* @param b
* @param first
* @param second
* @return
*/
private static <T> T ifThenElse(boolean b, T first, T second) { 


return b ? first : second;




}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值