为什么要有泛型
在Java增加泛型之前,泛型程序设计使用继承来实现。
坏处:
泛型的使用:如,在尖括号里,限制在list中只能添加String内容
List
Java SE7及以后的版本中,构造方法中可以省略泛型类型。即:List
多态与泛型
变量声明的类型必须匹配传递给实际对象的类型,即前后尖括号内的要一致,如下例是错的:
class Aniaml{}
class Cat extends Animal{}
List<Animal>list=new ArrayList<Cat>();
下例也是错的:
List<Object>list=new ArrayList<String>();
List<Number>numbers=new ArrayList<Integer>();
案例:
Goods
,包含抽象方法sell()
Book
,Clothes
,Shoes
继承Goods
,并实现sell()
,输出一句话GoodsSeller
,模拟销售,包括方法public void sellGoods(Listgoods)
,循环调用List
对象的sell
方法Goods
类:
public abstract class Goods {
public abstract void sell();
}
Book
类:
public class Book extends Goods {
@Override
public void sell() {
System.out.println("Book sell");
}
}
Clothes
类:
public class Clothes extends Goods {
@Override
public void sell() {
System.out.println("Clothes sell");
}
}
Shoes
类:
public class Shoes extends Goods {
@Override
public void sell() {
System.out.println("Shoes sell");
}
}
GoodsSeller
类:
public class GoodsSeller {
// 参数是Goods或其子类都可以
public void sellGoods(List<? extends Goods> goods) {
// 调用集合中的sell方法
for (Goods g : goods) {
g.sell();
}
}
}
测试类:
public class GoodsTest {
public static void main(String[] args) {
// 定义Book相关的List:参数类型一定要一致,不然会报错
List<Book> book = new ArrayList<Book>();
book.add(new Book());
book.add(new Book());
// 定义Clothes相关的List
List<Clothes> clothes = new ArrayList<Clothes>();
clothes.add(new Clothes());
clothes.add(new Clothes());
// 定义Shoes相关的List
List<Shoes> shoes = new ArrayList<Shoes>();
shoes.add(new Shoes());
shoes.add(new Shoes());
GoodsSeller goodsSeller = new GoodsSeller();
goodsSeller.sellGoods(book);
goodsSeller.sellGoods(clothes);
goodsSeller.sellGoods(shoes);
}
}
输出:
Book sell
Book sell
Clothes sell
Clothes sell
Shoes sell
Shoes sell
注意:public void sellGoods(List extends Goods> goods)
表示参数是Goods或其子类都可以。
举个例子:
//自定义泛型类
public class NumGeneric<T> {
private T num;
public T getNum() {
return num;
}
public void setNum(T num) {
this.num = num;
}
// 测试
public static void main(String[] args) {
NumGeneric<Integer> intNum = new NumGeneric<>();
intNum.setNum(100);
System.out.println(intNum.getNum());
NumGeneric<Float> floatNum = new NumGeneric<>();
floatNum.setNum(10.2f);
System.out.println(floatNum.getNum());
}
}
输出:
100
10.2
public class TwoNumGeneric<T, X> {
private T num1;
private X num2;
public void setNum(T num1, X num2) {
this.num1 = num1;
this.num2 = num2;
}
public T getNum1() {
return num1;
}
public X getNum2() {
return num2;
}
public void setNum1(T num1) {
this.num1 = num1;
}
public void setNum2(X num2) {
this.num2 = num2;
}
// 测试
public static void main(String[] args) {
TwoNumGeneric<Integer, Double> num = new TwoNumGeneric<>();
num.setNum(1, 20.0);
System.out.println(num.getNum1() + " " + num.getNum2());
}
}
输出:1 20.0
跟上一个差不多。
泛型方法不一定要写到泛型类中
类似C++的模板:
public class GenericMethod {
public <T> void printValue(T t) {
System.out.println(t);
}
public static void main(String[] agrs) {
GenericMethod gm = new GenericMethod();
gm.printValue("hello,world!");
gm.printValue(123);
gm.printValue(12.34);
}
}
输出:
hello,world!
123
12.34
如果只想要Number和它的子类:
public class GenericMethod {
public <T extends Number> void printValue(T t) {
System.out.println(t);
}
public static void main(String[] agrs) {
GenericMethod gm = new GenericMethod();
gm.printValue(123);
gm.printValue(12.34);
}
}
输出:
123
12.34
为什么使用泛型
注意:变量声明的类型必须匹配传递给实际对象的类型,即前后尖括号的内容要一致
泛型作为方法参数
参数是Goods类及其子类:public void A(List extends Goods>)
PS:extends
后也可以跟接口interface
的名字
参数是Goods及Goods的超类:public void A(List super Goods>)
自定义泛型和自定义泛型方法