Java之路(六):集合框架

泛型

为什么需要使用泛型:

1.存储在任意类型的数据在集合中,取出来都是Object类型的,此时就要强制转换

public static void main(String[] args) {
	List list = new ArrayList();
	list.add(1);
	Object ele = list.get(0);
	Integer num = (Integer) ele;
	System.out.println(num);
}

2.约束储存到集合中的元素必须是相同的数据类型(相同数据类型才能作比较,比如TreeSet类)

TreeSet set = new TreeSet();
	set.add(123);
	set.add("ABC");//报错:ClassCastException

3.设计一个点类(point),来封装坐标位置,要求坐标支持String类型,Integer类型和Double类型

如果不使用泛型,将像下面这样定义:

class Point1{
	private String x;
	private String y;
}
class Point2{
	private Integer x;
	private Integer y;
}
class Point3{
	private Double x;
	private Double y;
}

这样重复了代码,使得代码非常不优雅。

泛型(GenericType):Java5开始支持的新的语法

1.广泛通用的类型;
2.代码模板中类型不确定,谁调用这段代码,就是什么类型;

Point.java

//Type(T);Element(E);Key(K);Value(V)
public class Point <T> {
	private T x;
	private T y;
	
	public T getX() {
		return x;
	}
	public void setX(T x) {
		this.x = x;
	}
	public T getY() {
		return y;
	}
	public void setY(T y) {
		this.y = y;
	}
}

PointDemo.java

public class PointDemo {
	public static void main(String[] args) {
		//使用String类型
		Point<String> p1 = new Point<String>();
		String x1 = p1.getX();
		//使用Integer类型
		Point<Integer> p2 = new Point<Integer>();
		Integer x2 = p2.getX();
		//使用Double类型
		Point<Double> p3 = new Point<Double>();
		Double x3 = p3.getX();
	}
}

我们使用<>来传入泛型的类型,如:List<String> list = new List<String>();前后<>中的内容必须一样,因此不存在泛型继承的概念。
但是后面的<>内容可以省略,如List<String> list = new List<>();
我们从反编译代码中可以看出:
反编译泛型
其实泛型也是一种语法糖!

泛型方法

情况一:泛型类中的泛型只能适用于非静态方法,如果需要给静态方法设置泛型,此时应该使用泛型方法;
情况二:泛型类中的泛型应该适用与整个类中多个方法,有时只对某一个方法设置泛型即可。

一般的,把自定义的泛型作为该方法的返回类型才有意义,而且此时的泛型必须是由参数设置进来的。如果没有参数来设置泛型的具体类型,此时的方法一般设置为Object类型。

泛型方法具体展示:

public static <T> T doWrok(T val) {
	return val;
}
泛型的通配符以及上限和下限

泛型的通配符:
不知道使用什么类型来接收的时候,此时可以使用,表示未知。
此时只能接收数据,不能声明和存储数据。

public static void main(String[] args) {
	List<Integer> list1 = new ArrayList<>();//这里不能用<?>来声明
	doWork(list1);
	List<String> list2 = new ArrayList<>();
	doWork(list2);
}
	
public static void doWork(List<?> list){
		
}

泛型的上限和下限: 用来限定元素的类型必须是X的子类或相同,X的父类或相同。

public class GenericTypeDemo {

	public static void main(String[] args) {
		List<Integer> list1 = new ArrayList<>();
		List<String> list2 = new ArrayList<>();
		List<Number> list3 = new ArrayList<>();
		List<Object> list4 = new ArrayList<>();
		
		doWork1(list1);//true
		doWork1(list2);//false
		doWork1(list3);//true
		doWork1(list4);//false
		
		doWork2(list1);//false
		doWork2(list2);//false
		doWork2(list3);//true
		doWork2(list4);//true
	}
	//泛型的上限:此时的泛型?必须是Number类或者是Number类的子类
	public static void doWork1(List<? extends Number> list){
		
	}
	//泛型的下限:此时的泛型?必须是Number类或者是Number类的父类
	public static void doWork2(List<? super Number> list){
		
	}
}
泛型的擦除和转换

泛型的擦除:

1)泛型编译后就消失了;
2)当把带有泛型的集合赋给不带泛型的集合时,此时泛型被擦除(手动擦除);

public static void main(String[] args) {
	List<Integer> list1 = new ArrayList<>();
	list1.add(123);

	List list2 = null;
	list2 = list1;// 此时泛型擦除
	list2.add("ABC");

	// 带有String类型的泛型
	List<String> list3 = null;
	list3 = list2;
	System.out.println(list3);
		
	//等价于String num2 = 123 报错
	String num = list3.get(0);
}

堆污染:
当一个方法既使用泛型,又使用可变参数的时候,此时容易导致堆污染问题。

//Type safety: Potential heap pollution via varargs parameter arr
	@SafeVarargs //抑制警告
	public static <T>List<T> asList(T... arr){
		return null;
	}

泛型详解,参考https://www.cnblogs.com/coprince/p/8603492.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值