Java基础知识之泛型以及自定义泛型

之前的文章讲过了反射内省枚举注解和自定义注解

本篇讲一下泛型

一、什么是泛型和泛型的作用

JDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换

这样不可避免就会引发程序的一些安全性问题。例如:

ArrayList list = new ArrayList();
list.add("abc");
Integer num = (Integer) list.get(0);  //运行时才会报错,在编译时发现不了

再例如:在遍历集合的时候,无法遍历,因为放入集合中的数据类型是不确定的

List list = new ArrayList();
//放入集合一个int型的
list.add(1);
//放入集合一个String类型的
list.add("fuck");

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

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

二、泛型的典型应用

(1)使用增强for循环迭代泛型集合中的元素。

    @Test//泛型遍历List集合
	public void test2(){
		List<String> list = new ArrayList<String>();
		list.add("u");
		list.add("fuck");
		for(String s:list){
			System.out.println(s);
		}
	}

(2)存取HashMap中的元素。

    @Test//泛型遍历Map,方式一
	public void test3(){
		Map<Integer, String> map = new LinkedHashMap<Integer, String>();
		map.put(1, "aaa");
		map.put(2, "bbb");
		map.put(3, "ccc");
		
		Set<Integer> keys = map.keySet();
		for(Integer i:keys){
			String value = map.get(i);
			System.out.println("key:"+i+"\tvalue:"+value);
		}
		
	}
	
	@Test//泛型遍历Map,方式二
	public void test4(){
		Map<String, String> map = new LinkedHashMap<String, String>();
		map.put("a", "aaa");
		map.put("b", "bbb");
		map.put("c", "ccc");
		
		Set<Map.Entry<String, String>> set = map.entrySet();//Set中的元素是Map.Entry类型的
		for(Map.Entry<String, String> me:set){
			String key = me.getKey();
			String value = me.getValue();
			System.out.println("key:"+key+"\tvalue:"+value);
		}
	}

使用泛型时的几个常见问题:

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

b、如果等号左右两边都用到了泛型,则泛型里的类型必须一模一样。如以下的两种就不行

ArrayList<String> list = new ArrayList<Object>();

ArrayList<Object> list = new ArrayList<String>(); 

c、只有一边使用泛型,另一边不使用泛型是允许的。如下边的两种形式是可以的

ArrayList<String> list = new ArrayList ();

ArrayList list = new ArrayList<String>();

这么做的目的是为了兼容

举个例子

    @Test
	public void test5(){
		//JDK1.5以后的新时代程序员调老程序员写的东西
		List<String> list = getList();
		
		//一个老程序员调用新程序员写的东西
		List li = getAnthorList();
	}
	
	//一个老程序员写的方法如下
	public List getList(){
		return null;
	}

	//一个新时代程序员写的方法如下
	public List<String> getAnthorList(){
		return null;
	}

三、自定义泛型的语法

Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。

方法使用泛型前,必须对泛型进行声明,语法:<T> ,T可以是任意字母,但通常必须要大写。一般情况下大写是类型,小写是参数。

<T>需放在方法的返回值声明之前。

public class Demo2 {

	public <T>  void m1(T t){
		
	}

	public <T> T m2(T t){
		return t;
	}

	public static <T> T m3(T t){
		return t;
	}
	
}

除了在方法上声明泛型之外,还可以在类上声明泛型,但是需要注意的是:在类上面声明泛型,仅限于实例方法上直接使用,但是不适合静态方法

例如:

//在类上面声明泛型,在实例方法上直接用即可;但是不适合静态方法
//静态方法上使用的泛型声明必须单独定义
public class Demo2<T> {

	public void m1(T t){
		
	}

	public T m2(T t){
		return t;
	}
	
}

上边就是泛型的基本语法和使用

四、使用泛型练习几个案例

(1)编写一个泛型方法,实现数组元素的交换。

//自定义泛型练习
public class GenericUtil {
	//颠倒任意数组中的指定位置上的两个元素
	//比如[1,2,3]   颠倒0和2位置上的元素   [3,2,1]
	public static <T> void m1(T[] t,int index1,int index2){
		//临时变量
		T temp = t[index1];
		t[index1] = t[index2];
		t[index2] = temp;
	}
}
public class Demo3 {
	@Test
	public void test1(){
		String s1[] = {"a","b","c"};
		GenericUtil.m1(s1, 1, 2);
		List list = Arrays.asList(s1);
		System.out.println(list);
		
	}
}

最后输出结果为 a,c,b

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

//自定义泛型练习
public class GenericUtil {
	//颠倒任意类型数组中的元素顺序
	//[1,2,3]  [3,2,1]
	public static <T> void reverse(T[] t){
		int startIndex = 0;
		int endIndex = t.length -1;
		while(startIndex<endIndex){
			T temp = t[startIndex];
			t[startIndex] = t[endIndex];
			t[endIndex] = temp;
			startIndex++;
			endIndex--;
		}
	}
}
public class Demo3 {
	@Test
	public void test2(){
		String s1[] = {"a","b","c"};
		GenericUtil.reverse(s1);
		List list = Arrays.asList(s1);
		System.out.println(list);//输出结果为c,b,a
		
		Integer ii[] = {1,2,3};
		GenericUtil.reverse(ii);//注意:只有引用类型才能作为泛型方法的实际参数
		list = Arrays.asList(ii);
		System.out.println(list);//输出结果为3,2,1
	}
}

以上就是对泛型的一些学习和总结,如有不正确的地方,可以在评论区进行指正,一起学习一起进步,谢谢

发布了86 篇原创文章 · 获赞 74 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章