泛型概述
泛型的意义
在Java中增加泛型之前,泛型程序设计使用继承来实现的。这种方式有以下坏处,而使用泛型不存在这些坏处。
坏处1:需要强制转换
坏处2:可向集合中添加任意类型的对象,存在风险
具体例子参见上一篇文章:Java集合 => 在HashSet中操作自定义对象
泛型的使用
- List
list = new ArrayList (); - Java SE7及以后的版本中,构造方法中可以省略泛型类型。
即:List
多态与泛型
变量声明的类型必须匹配传递给实际对象的类型
class Animal{}
class Cat extends Animal{}
List<Animal> list = new ArrayList<Cat> (); // 错误
List<Object> list = new ArrayList<String> (); // 错误
List<Number> list = new ArrayList<Integer> (); // 错误
泛型作为方法参数
Book.java
package com.generic;
public class Book extends Goods {
@Override
public void sell() {
// TODO Auto-generated method stub
System.out.println("sell books");
}
}
Clothes.java
package com.generic;
public class Clothes extends Goods {
@Override
public void sell() {
// TODO Auto-generated method stub
System.out.println("sell clothes");
}
}
—-Version1.0:———————————————————————————————————————————————————
在这个版本中,我们可以看到GoodsTest.java中的goodsSeller.sellGoods(books);是会报错的。原因就在与,sellGoods方法在定义的时候,接受的泛型是Goods类,但是实际传递过来的缺失Book类,所以类型不匹配导致编译报错。怎么解决这个编译报错呢?请看Version2.0
GoodsSeller.java
package com.generic;
import java.util.List;
public class GoodsSeller {
public void sellGoods(List<Goods> goods) {
// 调用集合中的sell方法
for (Goods good : goods) {
good.sell();
}
}
}
GoodsTest.java
package com.generic;
import java.util.ArrayList;
import java.util.List;
public class GoodsTest {
public static void main(String[] args) {
// 定义book相关的List
List<Book> books = new ArrayList<Book>();
books.add(new Book());
books.add(new Book());
// 定义clothes相关的List
List<Clothes> clothes = new ArrayList<Clothes>();
clothes.add(new Clothes());
clothes.add(new Clothes());
GoodsSeller goodsSeller = new GoodsSeller();
goodsSeller.sellGoods(books); // 报错
}
}
—-Version2.0:———————————————————————————————————————————————————
为了解决Version1.0中的编译报错问题,我们可以用都用Goods类实例化books对象和clothes对象。
但是这样的话,无法区分Book类对象和Clothes类对象,泛型的意义就不大了。有没有办法既可以解决编译报错,有能保留泛型呢?请看Version3.0
GoodsSeller.java
package com.generic;
import java.util.List;
public class GoodsSeller {
public void sellGoods(List<Goods> goods) {
// 调用集合中的sell方法
for (Goods good : goods) {
good.sell();
}
}
}
GoodsTest.java
package com.generic;
import java.util.ArrayList;
import java.util.List;
public class GoodsTest {
public static void main(String[] args) {
// 定义book相关的List
List<Goods> books = new ArrayList<Goods>();
books.add(new Book());
books.add(new Book());
// 定义clothes相关的List
List<Goods> clothes = new ArrayList<Goods>();
clothes.add(new Clothes());
clothes.add(new Clothes());
GoodsSeller goodsSeller = new GoodsSeller();
goodsSeller.sellGoods(books);
goodsSeller.sellGoods(clothes);
}
}
sell books
sell books
sell clothes
sell clothes
—-Version3.0:———————————————————————————————————————————————————
注意sellGoods方法中的参数设置,(List<? extends Goods> goods),这就是泛型作为参数的好处
GoodsSeller.java
package com.generi;
import java.util.List;
public class GoodsSeller {
public void sellGoods(List<? extends Goods> goods) {
// 调用集合中的sell方法
for (Goods good : goods) {
good.sell();
}
}
}
GoodsTest.java
package com.generic;
import java.util.ArrayList;
import java.util.List;
public class GoodsTest {
public static void main(String[] args) {
// 定义book相关的List
List<Book> books = new ArrayList<Book>();
books.add(new Book());
books.add(new Book());
// 定义clothes相关的List
List<Clothes> clothes = new ArrayList<Clothes>();
clothes.add(new Clothes());
clothes.add(new Clothes());
GoodsSeller goodsSeller = new GoodsSeller();
goodsSeller.sellGoods(books);
goodsSeller.sellGoods(clothes);
}
}
sell books
sell books
sell clothes
sell clothes
自定义泛型类
package com.generic;
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(10);
System.out.println("Integer:"+intNum.getNum());
NumGeneric<Float> floatNum = new NumGeneric<>();
floatNum.setNum(5.0f);
System.out.println("Float:"+floatNum.getNum());
}
}
Integer:10
Float:5.0
package com.generic;
public class NumGeneric<T,X> {
private T num1;
private X num2;
public void genNum(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;
}
public static void main(String[] args) {
NumGeneric<Integer,Float> numObj = new NumGeneric<> ();
numObj.genNum(25, 5.0f);
System.out.println("num1="+numObj.getNum1());
System.out.println("num2="+numObj.getNum2());
}
}
num1=25
num2=5.0
自定义泛型方法
泛型方法不一定要写在泛型类里面
package com.generic;
public class GenericMethod {
public <T> void printValue(T t) {
System.out.println(t);
}
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
gm.printValue("hello");
gm.printValue(123);
gm.printValue(5.0f);
}
}
hello
123
5.0
package com.generic;
public class GenericMethod {
public <T extends Number> void printValue(T t) {
System.out.println(t);
}
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
gm.printValue("hello"); // 出错,因为是继承自Number类的泛型
gm.printValue(123);
gm.printValue(5.0f);
}
}