泛型概述

泛型的意义

在Java中增加泛型之前,泛型程序设计使用继承来实现的。这种方式有以下坏处,而使用泛型不存在这些坏处。
坏处1:需要强制转换
坏处2:可向集合中添加任意类型的对象,存在风险

具体例子参见上一篇文章:Java集合 => 在HashSet中操作自定义对象

泛型的使用

  • List list = new ArrayList ();
  • Java SE7及以后的版本中,构造方法中可以省略泛型类型。

即:List list = new ArrayList ();

多态与泛型

变量声明的类型必须匹配传递给实际对象的类型

  1. class Animal{}
  2. class Cat extends Animal{}
  3. List<Animal> list = new ArrayList<Cat> (); // 错误
  4. List<Object> list = new ArrayList<String> (); // 错误
  5. List<Number> list = new ArrayList<Integer> (); // 错误

泛型作为方法参数

Book.java

  1. package com.generic;
  2. public class Book extends Goods {
  3. @Override
  4. public void sell() {
  5. // TODO Auto-generated method stub
  6. System.out.println("sell books");
  7. }
  8. }

Clothes.java

  1. package com.generic;
  2. public class Clothes extends Goods {
  3. @Override
  4. public void sell() {
  5. // TODO Auto-generated method stub
  6. System.out.println("sell clothes");
  7. }
  8. }

—-Version1.0:———————————————————————————————————————————————————
在这个版本中,我们可以看到GoodsTest.java中的goodsSeller.sellGoods(books);是会报错的。原因就在与,sellGoods方法在定义的时候,接受的泛型是Goods类,但是实际传递过来的缺失Book类,所以类型不匹配导致编译报错。怎么解决这个编译报错呢?请看Version2.0

GoodsSeller.java

  1. package com.generic;
  2. import java.util.List;
  3. public class GoodsSeller {
  4. public void sellGoods(List<Goods> goods) {
  5. // 调用集合中的sell方法
  6. for (Goods good : goods) {
  7. good.sell();
  8. }
  9. }
  10. }

GoodsTest.java

  1. package com.generic;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class GoodsTest {
  5. public static void main(String[] args) {
  6. // 定义book相关的List
  7. List<Book> books = new ArrayList<Book>();
  8. books.add(new Book());
  9. books.add(new Book());
  10. // 定义clothes相关的List
  11. List<Clothes> clothes = new ArrayList<Clothes>();
  12. clothes.add(new Clothes());
  13. clothes.add(new Clothes());
  14. GoodsSeller goodsSeller = new GoodsSeller();
  15. goodsSeller.sellGoods(books); // 报错
  16. }
  17. }

—-Version2.0:———————————————————————————————————————————————————
为了解决Version1.0中的编译报错问题,我们可以用都用Goods类实例化books对象和clothes对象。
但是这样的话,无法区分Book类对象和Clothes类对象,泛型的意义就不大了。有没有办法既可以解决编译报错,有能保留泛型呢?请看Version3.0

GoodsSeller.java

  1. package com.generic;
  2. import java.util.List;
  3. public class GoodsSeller {
  4. public void sellGoods(List<Goods> goods) {
  5. // 调用集合中的sell方法
  6. for (Goods good : goods) {
  7. good.sell();
  8. }
  9. }
  10. }

GoodsTest.java

  1. package com.generic;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class GoodsTest {
  5. public static void main(String[] args) {
  6. // 定义book相关的List
  7. List<Goods> books = new ArrayList<Goods>();
  8. books.add(new Book());
  9. books.add(new Book());
  10. // 定义clothes相关的List
  11. List<Goods> clothes = new ArrayList<Goods>();
  12. clothes.add(new Clothes());
  13. clothes.add(new Clothes());
  14. GoodsSeller goodsSeller = new GoodsSeller();
  15. goodsSeller.sellGoods(books);
  16. goodsSeller.sellGoods(clothes);
  17. }
  18. }

sell books
sell books
sell clothes
sell clothes

—-Version3.0:———————————————————————————————————————————————————
注意sellGoods方法中的参数设置,(List<? extends Goods> goods),这就是泛型作为参数的好处

GoodsSeller.java

  1. package com.generi;
  2. import java.util.List;
  3. public class GoodsSeller {
  4. public void sellGoods(List<? extends Goods> goods) {
  5. // 调用集合中的sell方法
  6. for (Goods good : goods) {
  7. good.sell();
  8. }
  9. }
  10. }

GoodsTest.java

  1. package com.generic;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class GoodsTest {
  5. public static void main(String[] args) {
  6. // 定义book相关的List
  7. List<Book> books = new ArrayList<Book>();
  8. books.add(new Book());
  9. books.add(new Book());
  10. // 定义clothes相关的List
  11. List<Clothes> clothes = new ArrayList<Clothes>();
  12. clothes.add(new Clothes());
  13. clothes.add(new Clothes());
  14. GoodsSeller goodsSeller = new GoodsSeller();
  15. goodsSeller.sellGoods(books);
  16. goodsSeller.sellGoods(clothes);
  17. }
  18. }

sell books
sell books
sell clothes
sell clothes

自定义泛型类

  1. package com.generic;
  2. public class NumGeneric<T> {
  3. private T num;
  4. public T getNum() {
  5. return num;
  6. }
  7. public void setNum(T num) {
  8. this.num = num;
  9. }
  10. public static void main(String[] args) {
  11. NumGeneric<Integer> intNum = new NumGeneric<>();
  12. intNum.setNum(10);
  13. System.out.println("Integer:"+intNum.getNum());
  14. NumGeneric<Float> floatNum = new NumGeneric<>();
  15. floatNum.setNum(5.0f);
  16. System.out.println("Float:"+floatNum.getNum());
  17. }
  18. }

Integer:10
Float:5.0

  1. package com.generic;
  2. public class NumGeneric<T,X> {
  3. private T num1;
  4. private X num2;
  5. public void genNum(T num1, X num2) {
  6. this.num1 = num1;
  7. this.num2 = num2;
  8. }
  9. public T getNum1() {
  10. return num1;
  11. }
  12. public void setNum1(T num1) {
  13. this.num1 = num1;
  14. }
  15. public X getNum2() {
  16. return num2;
  17. }
  18. public void setNum2(X num2) {
  19. this.num2 = num2;
  20. }
  21. public static void main(String[] args) {
  22. NumGeneric<Integer,Float> numObj = new NumGeneric<> ();
  23. numObj.genNum(25, 5.0f);
  24. System.out.println("num1="+numObj.getNum1());
  25. System.out.println("num2="+numObj.getNum2());
  26. }
  27. }

num1=25
num2=5.0

自定义泛型方法

泛型方法不一定要写在泛型类里面

  1. package com.generic;
  2. public class GenericMethod {
  3. public <T> void printValue(T t) {
  4. System.out.println(t);
  5. }
  6. public static void main(String[] args) {
  7. GenericMethod gm = new GenericMethod();
  8. gm.printValue("hello");
  9. gm.printValue(123);
  10. gm.printValue(5.0f);
  11. }
  12. }

hello
123
5.0

  1. package com.generic;
  2. public class GenericMethod {
  3. public <T extends Number> void printValue(T t) {
  4. System.out.println(t);
  5. }
  6. public static void main(String[] args) {
  7. GenericMethod gm = new GenericMethod();
  8. gm.printValue("hello"); // 出错,因为是继承自Number类的泛型
  9. gm.printValue(123);
  10. gm.printValue(5.0f);
  11. }
  12. }