java集合框架--泛型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java集合框架--泛型相关的知识,希望对你有一定的参考价值。

1.泛型概述

  泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行。也被称为参数化类型,可以把类型当做参数一样传递过来,在传递过来之前并不明确,但是在使用的时候就明确了。

  泛型是JDK5以后出现的新特性。


2.泛型出现的原因1

package com;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericDemo {
	public static void main(String[] args) {
		//创建集合对象
		ArrayList list = new ArrayList();
		//添加元素
		list.add("hello");
		list.add("world");
		list.add("java");
		//遍历
		for(Iterator<String> iterator = list.iterator();iterator.hasNext();){
			String str = (String)iterator.next();
			System.out.println(str);
		}
		
	}

}

hello

world

java


上面的代码是将字符串放进集合中,但是集合的add()方法的参数类型时Object,所以我们可以放任意的引用类型,当然如果你存放的是基本类型,那么Jdk5之后会有自动装箱功能,将基本类型转换成引用类型,千万记住,集合存放的是引用类型,而不是基本类型哦。虽然你可以存放基本类型的数据,但是JDK底层依然会转换成引用数据类型的。如果你不明白的话,可以使用反编译工具,将字节码文件反编译一下就知道了。

package com;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericDemo {
	public static void main(String[] args) {
		//创建集合对象
		ArrayList list = new ArrayList();
		//添加元素
		list.add("hello");
		list.add("world");
		list.add("java");
		list.add(new Integer(100));
		list.add(10);//自动装箱
		
		//遍历
		for(Iterator<String> iterator = list.iterator();iterator.hasNext();){
			String str = (String)iterator.next();
			System.out.println(str);
		}
		
	}

}

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at com.GenericDemo.main(GenericDemo.java:18)

报错了,类型转换异常,意思是Integer类型不能转换为String类型。这是运行时异常,意思就是在运行期间才会产生这个异常,这样很不方便。

技术分享

那么此时,我们回顾一下String类型的数组

String[] str = new String[10];
str[0] = "hello";
str[1] = "world";
str[0] = 12;//这边在编译期间就直接报错,为什么?因为是String类型的数组,
//你竟然存放int类型的数据

同理,那么我们能不能在定义集合的时候就采用这种机制呢?

当然啦,集合也采用的是这样机制,在创建集合对象的时候明确元素的数据类型,这样就不会出现这种问题了。这种技术被称为泛型。


那么此时,我们来看泛型的定义吧,泛型就是一种把类型明确的工作推迟到创建对象或调用方法的时候去明确的特殊类型。反而言之,就是在定义集合类的时候,并不给出具体类型,当你创建集合对象的时候给出具体的类型,用来限定集合类型的所有类型,这样是不是很方便。


但是此处的类型只能是引用类型,不能是基本类型哦,要记住虽然有JDK5的自动装箱和拆箱的功能。但是集合本质上存放的还是引用类型的数据,所以你创建集合对象的时候使用泛型就用引用数据类型哦,因为JDK还没有这么强大,哈哈。

package com;

import java.util.ArrayList;
import java.util.Iterator;
//错误代码
public class GenericDemo {
	public static void main(String[] args) {
		//创建集合对象
		ArrayList<String> list = new ArrayList<String>();
		//添加元素
		list.add("hello");
		list.add("world");
		list.add("java");
		list.add(new Integer(100));//这段代码 在编译期间就直接报错 
		//因为我们声明集合中所有元素必须为String类型,而我们存放的却是其他类型的数据
		list.add(10);//自动装箱//和上面一样
		
		//遍历
		for(Iterator<String> iterator = list.iterator();iterator.hasNext();){
			String str = (String)iterator.next();
			System.out.println(str);
		}
		
	}

}


3.泛型的好处

  那么此时,我们想一下,既然泛型能限定集合元素的数据类型,那么意味着集合中的所有类型都是一样的哦,那么我们我们将字符串取出来的时候,能不能省略类型转换呢?想一下,String类型的数组,当你迭代遍历的时候考虑过类型转换吗?NO,因为我知道此时数组里存放的都是String类型的数据,我当然无须考虑,那么泛型的好处也就来了,就是省去了类型转换的麻烦。


原来的代码

package com;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericDemo {
	public static void main(String[] args) {
		//创建集合对象
		ArrayList<String> list = new ArrayList<String>();
		//添加元素
		list.add("hello");
		list.add("world");
		list.add("java");

		
		//遍历
		for(Iterator<String> iterator = list.iterator();iterator.hasNext();){
			String str = (String)iterator.next();//类型转换
			System.out.println(str);
		}
		
	}

}

既然知道,泛型省去了类型转换,那么我们此时将强制类型转换的标记去到如何?

package com;

import java.util.ArrayList;
import java.util.Iterator;

public class GenericDemo {
	public static void main(String[] args) {
		//创建集合对象
		ArrayList<String> list = new ArrayList<String>();
		//添加元素
		list.add("hello");
		list.add("world");
		list.add("java");

		
		//遍历
		for(Iterator<String> iterator = list.iterator();iterator.hasNext();){
			String str = iterator.next();//类型转换
			System.out.println(str);
		}
		
	}

}

当然可以啦,因为我在用迭代器的时候就限定了迭代器中的泛型为String类型了,这样后面再取集合中的元素的时候就不用类型转换了,是不是很方便啊,这样的功能太棒了。真的是难为了JDK4之前的程序员,要进行类型转换。


总结一下泛型的好处:

  1.提高了程序的安全性

  2.将运行期间遇到的问题转移到了编译期间

  3.省去了强制类型转换的麻烦


4.泛型在那些地方使用呢?

  查看API,如果类、接口、抽象类后面跟的是<E>这样的标记,就意味着要使用泛型了。一般来说就是在集合中使用。

package com;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class ArrayListDemo {
	public static void main(String[] args) {
		//创建ArrayList对象
		ArrayList<String> list = new ArrayList<String>();
		
		//添加元素
		list.add("哈哈");
		list.add("呵呵");
		list.add("嘻嘻");
		list.add("笨笨");
		
		//遍历方式一 将ArrayList集合装换为Object[]
		Object[] obj = list.toArray();
		for (int i = 0; i < obj.length; i++) {
			String str = (String) obj[i];
			System.out.println(str);
		}
		
		System.out.println("----------------------");
		
		//遍历方式二 使用Iterator迭代器
		for(Iterator<String> iterator = list.iterator();iterator.hasNext();){
			String str = iterator.next();
			System.out.println(str);
		}
		
		System.out.println("-----------------------");
		
		//遍历方式三 使用ListIterator迭代器
		//顺向遍历
		ListIterator<String> listIterator = list.listIterator();
		while(listIterator.hasNext()){
			String str = listIterator.next();
			System.out.println(str);
		}
		
		System.out.println("------------------------");
		
		//逆向遍历
		while(listIterator.hasPrevious()){
			String str = listIterator.previous();
			System.out.println(str);
		}
		
		System.out.println("------------------------");
		
		//遍历方式四 使用size()和get(int index)方法来实现遍历集合元素
		for (int i = 0; i < list.size(); i++) {
			String str = list.get(i);
			System.out.println(str);
		}
	}
}


5.泛型出现的原因2

  早期的Object类型可以接收任意的对象类型,但是在实际使用中,会存在类型转换问题。即存在安全隐患,所以java提供了泛型来解决这个安全问题。


6.泛型的应用

泛型类:

  把泛型定义在类上。

  格式:public class 类名<泛型类型1,泛型类型2,...>

  注意:泛型类型必须为引用类型

package com;
/**
 * 泛型类
 */
public class ObjectTool<T> {
	private T obj;

	public T getObj() {
		return obj;
	}

	public void setObj(T obj) {
		this.obj = obj;
	}
}
package com;
/**
 * 泛型类的测试
 * @author 许威威
 *
 */
public class ObjectToolTest {
	public static void main(String[] args) {
		ObjectTool<String> ot = new ObjectTool<String>();
		
		ot.setObj("哈哈");
		System.out.println(ot.getObj());
		
		ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
		ot2.setObj(20);//自动装箱
		System.out.println(ot2.getObj());
	}

}


泛型方法:

  把泛型定义在方法上。

  格式:public <泛型类型> 返回值类型 方法名(泛型类型1,泛型类型2,...)

package cn;

public class ObjectTool {
	public void show(String str){
		System.out.println(str);
	}
	public void show(Integer i){
		System.out.println(i);
	}

}
package cn;

public class ObjectToolTest {
	public static void main(String[] args) {
		ObjectTool ot = new ObjectTool();
		ot.show("哈哈");
		ot.show(20);//自动装箱
	}

}

这样是对的,但是我如果传入的是boolean类型,Student类型,那么我只能去修改ObjectTool类了,继续增加重载方法,好麻烦。

package cn;

public class ObjectTool<T> {
	public void show(T t){
		System.out.println(t);
	}

}
package cn;

public class ObjectToolTest {
	public static void main(String[] args) {
		ObjectTool<String> ot = new ObjectTool<String>();
		ot.show("哈哈");
		
		ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
		ot2.show(100);
		
		ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>();
		ot3.show(true);
		
	}

}

但是,上面的代码是不是让泛型方法上的参数类型和类的类型一致,但是如果我类上没有泛型,方法就不能接受任意类型的数据了吗?当然不是啦。且看下面分解。

package cn;

public class ObjectTool<T> {
	public void show(T t){
		System.out.println(t);
	}

}
package cn;

public class ObjectTool1Test {
	public static void main(String[] args) {
		ObjectTool1 ot = new ObjectTool1();
		
		ot.show("HelloWorld");
		ot.show(100);
	}

}

泛型接口

  把泛型定义在接口上。

  格式:public interface 接口名<泛型类型1,泛型类型2,...>

package cn;

public interface ObjectTool3<T> {
	
	public  void show(T t);

}
package cn;

public class ObjectTool3Test {
	public static void main(String[] args) {
		ObjectTool3<String> ot = new ObjectTool3<String>(){
			public void show(String str){
				System.out.println(str);
			}
		};
		ot.show("呵呵");
		
	}

}


7.泛型之通配符

<?> 任意类型,如果没有明确,那么就是Object以及任意类型的java类。

<? extends E> 向下限定,E以及其子类

<? super E> 向上限定,E以及其父类

package cn;

import java.util.ArrayList;
import java.util.Collection;

/**
 * 泛型通配符
 * ? 	任意类型,如果没有明确,那么就是Object以及任意的java类了。
 * ? extends E  向下限定,E及其子类
 * ? super E 向上限定,E及其父类
 *
 */
class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
public class GenericDemo {
	public static void main(String[] args) {
		//泛型如果明确些的时候,前后必须一致
		Collection<Object> c = new ArrayList<Object>();
		//下面三种会报错
		//Collection<Object> c = new ArrayList<Animal>();
		//Collection<Animal> c = new ArrayList<Dog>();
		//Collection<Animal> c = new ArrayList<Dog>();
		
		Collection<?> c1 = new ArrayList<Animal>();
		Collection<?> c2 = new ArrayList<Dog>();
		Collection<?> c3 = new ArrayList<Cat>();
		
		//? extends E 向下限定,E及其子类
		Collection<? extends Animal> c4 = new ArrayList<Dog>();
		
		//? super E 向上限定,E及其父类
		Collection<? super Animal> c5 = new ArrayList<Object>();
		
	}
}





本文出自 “11831428” 博客,请务必保留此出处http://11841428.blog.51cto.com/11831428/1862368

以上是关于java集合框架--泛型的主要内容,如果未能解决你的问题,请参考以下文章

java习题-集合框架-泛型

JAVA集合框架之List和Set泛型

java集合框架总结--泛型

第10篇-JAVA 集合框架-JAVA 泛型

Java笔记-泛型与集合框架

Java集合框架--泛型方法 & 泛型集合 & 泛型优点