为什么使用泛型
在Java增加泛型之前,泛型程序设计使用继承来实现的,可其中也有不便,需要强制类型转换
,以及可向集合中添加任意类型的对象,存在一定的风险
。
因此使用泛型就是为了避免需要强制类型转换
,以及运行时异常的安全隐患
,可以控制问题在编译时报错。
使用泛型
List<String> list = new ArrayList<String>();
在Java SE7以后的版本中,构造方法中可以省略泛型类型
List<String> list = new ArrayList<>();
多态与泛型
变量声明的类型
必须匹配
传递给实际对象的类型错误示例:
List<Object> list = new ArrayList<String>(); List<Number> list = new ArrayList<Ingeger>();
泛型作为方法参数
案例:
- 定义一个抽象类Goods ,包含抽象方法sell()分别定义类Book、Clothes和Shoes继承Goods ,并实现sell()方法,输出一-句话,如:
sell books
- 定义一个商品销售类GoodsSeller ,模拟销售,包括方法:
public void sellGoods(List <Goods> goods)
,循环调用List对象的sell()方法。
// 抽象类Goods
public abstract class Goods {
public abstract void sell();
}
// 实现类Book
public class Book extends Goods {
@Override
public void sell() {
System.out.println("sell books");
}
}
// 实现类Clothes
public class Clothes extends Goods {
@Override
public void sell() {
System.out.println("sell clothes");
}
}
// 实现类Shoes
public class Shoes extends Goods {
@Override
public void sell() {
System.out.println("sell shoes");
}
}
商品销售类GoodsSeller:
public class GoodsSeller {
// 此处通过 List<? extends Goods> goods 的方式,规Goods和Goods的子类都可以添加,且限制类型的单一
public void sellGoods(List<? extends Goods> goods) {
// 遍历goods
for(Goods g : goods) {
g.sell(); // 调用sell方法
}
}
}
定义方法参照ArrayList构造方法:
规定E类与E的子类都可以传入,不仅可以
extends
类,也可以extends
接口
同时还可以进行通过实现超类的声明:
// // 此处通过 List<? super Goods> goods 的方式,规定Goods和Goods的超类都可以添加,且限制类型的单一
public void sellGoods(List<? super Goods> goods){
}
测试类:
List<Book> books = new ArrayList<>();
books.add(new Book());
books.add(new Book());
books.add(new Book());
GoodsSeller goodsSeller = new GoodsSeller();
goodsSeller.sellGoods(books);
自定义泛型
定义泛型类1:(一种类型)
// T表示不确定什么类型
public class NumGeneric<T> {
// 同样适用T代替
private T num;
public T getNum() {
return num;
}
public void setNum(T num) {
this.num = num;
}
}
测试类:
NumGeneric<Integer> intNum = new NumGeneric<>();
intNum.setNum(10);
System.out.println("Integer数为:" + intNum.getNum());
NumGeneric<Float> intFloat = new NumGeneric<>();
intFloat.setNum(3.1f);
System.out.println("Float数为:" + intFloat.getNum());
通过自定义泛型,把数据类型参数化
定义泛型类2:(两种类型)
public class TowNumGeneric<T, X> {
private T num1;
private X num2;
public void Num(T num1, X num2) {
this.num1 = num1;
this.num2 = num2;
}
public T getNum1() {
return num1;
}
public void setNum1(T num1) {
this.num1 = num1;
}
public X getNum2() {
return num2;
}
public void setNum2(X num2) {
this.num2 = num2;
}
}
测试类:
TowNumGeneric<Integer, Double> num = new TowNumGeneric<>();
num.Num(20, 3.99);
System.out.println("num1数为:" + num.getNum1());
System.out.println("num2数为:" + num.getNum2());
自定义泛型方法
public class GenericMethond {
// 不确定数据类型
public <T> void printValue(T t) {
System.out.println(t);
}
// 不确定数据类型,但必须是Number的子类
public <T extends Number> void printNum(T t) {
System.out.println(t);
}
}
测试类:
GenericMethond gm = new GenericMethond();
gm.printValue("hello");
gm.printValue(3.9f);
gm.printValue(3);
// printNum()里不可传字符串,必须是数值型
gm.printNum(20);