在之前学过的集合框架中,List和Map都使用了泛型技术来确认其内容的数据类型。
如果不使用泛型,在程序运行阶段,会带来数据类型转型的错误风险。

  1. List<String> list = new ArrayList<String>();
  2. list.add("tom");
  3. for (int i = 0; i < list.size(); i++) {
  4. String obj = list.get(i);
  5. System.out.println(obj);
  6. }
  7. List list2 = new ArrayList();
  8. list2.add("helen");
  9. list2.add(2); // 自动装箱成Integer
  10. list2.add(true); // 自动装箱成Boolean
  11. for (int i = 0; i < list2.size(); i++) {
  12. String obj = (String)list2.get(i); // 此处是有风险的
  13. }

在Java中,使用变量之前,必须要先定义变量的数据类型,存在一种特殊的现象,就是多态(数据类型是父类,实现对象是子类),变量赋值不一定要完全和数据类型一致,可以赋予子类对象给它。

  1. public class Client2 {
  2. public static void main(String[] args) {
  3. Point point = new Point();
  4. point.x = "东经102°";
  5. point.y = "北纬32°";
  6. point.x = 102;
  7. point.y = 32;
  8. String s = (String) point.x;
  9. point.print();
  10. }
  11. }
  12. class Point {
  13. Object x;
  14. Object y;
  15. public void print() {
  16. System.out.println(x + "" + y);
  17. }
  18. }

向下转型会带来数据风险的(ClassCastException)

不使用泛型的缺点:需要强制转换;可向集合中添加任意类型的对象,存在风险
泛型的使用:在接口/类名后的尖括号内加上类型,如 List list=new ArrayList();同时,变量声明时的泛型类和其实现类时的泛型类必须相同,即“=”前后的尖括号中的类型需要一致

  1. class Animal{}
  2. class Cat extends Animal {}
  3. List<Animal> list = new ArrayList<Cat>();
  4. 这样是不允许的。变量声明的类型必须匹配传递给实际对象的类型

泛型作为方法参数

泛型作为方法参数

案例: 定义一个抽象类Goods,包含抽象方法sell(); 分别定义各类商品Book,Clothes和Shoes继承Goods,并实现sell()方法,输出一句话,如sell books 定义一个商品销售类GoodsSeller,模拟销售,包括方法:public void sellGoods(List goods),循环调用list对象的sell() 方法

  1. public abstract class Goods {
  2. public abstract void sells();
  3. }
  4. public class Books extends Goods{
  5. @Override
  6. public void sells() {
  7. System.out.println("sell books");
  8. }
  9. }
  10. public class Clothes extends Goods {
  11. @Override
  12. public void sells() {
  13. System.out.println("sell clothes");
  14. }
  15. }
  16. public class Shoes extends Goods {
  17. @Override
  18. public void sells() {
  19. System.out.println("sell shoes");
  20. }
  21. }
  22. public class GoodsSeller {
  23. //代表只要goods参数保存的元素是Goods或者Goods的子类,都可以
  24. public void sellGoods(List<? extends Goods> goods) {
  25. //调用集合中的sell方法
  26. for(int i = 0; i < goods.size(); i++) {
  27. Goods g = goods.get(i);
  28. g.sells();
  29. }
  30. }
  31. }
  32. public class Test {
  33. public static void main(String[] args) {
  34. //定义books相关的list
  35. List<Books> bookLst = new ArrayList<Books>();
  36. bookLst.add(new Books());
  37. bookLst.add(new Books());
  38. //定义Shoes相关的list
  39. List<Shoes> shoesLst = new ArrayList<Shoes>();
  40. shoesLst.add(new Shoes());
  41. shoesLst.add(new Shoes());
  42. //定义Clothes相关的list
  43. List<Clothes> clothesLst = new ArrayList<Clothes>();
  44. clothesLst.add(new Clothes());
  45. clothesLst.add(new Clothes());
  46. GoodsSeller gdSeller = new GoodsSeller();
  47. gdSeller.sellGoods(bookLst);
  48. }
  49. }

自定义泛型类

  1. public class Demo {
  2. public static void main(String[] args) {
  3. Point<Integer, Integer> p = new Point<Integer, Integer>();
  4. p3.x = 1;
  5. p3.x = 2;
  6. }
  7. }
  8. public class Point<T1, T2> {
  9. T1 x;
  10. T2 y;
  11. }

类的泛型在className之后定义,只有定义的泛型类型才能在类中使用。

即我们定义只有先定义类名后的泛型标志符的时候,才能使该泛型类使用泛型定义方法和成员变量。

自定义泛型方法

泛型方法不一定要写在泛型类中

  1. /**
  2. * 定义泛型方法
  3. **/
  4. public class GenericMethod {
  5. //定义泛型方法的时候需要将泛型放在访问修饰符和返回值中间
  6. public <T extends Number> void print(T t) {
  7. System.out.println(t.toString());
  8. }
  9. public static void main(String[] args) {
  10. GenericMethod gm = new GenericMethod();
  11. //可以通过泛型方法实现一个方法传递不同的参数
  12. //gm.print("123");规定泛型的继承限定之后,该行语句就是错误的了
  13. gm.print(123);
  14. gm.print(123f);
  15. }
  16. }

泛型一般使用于框架设计,在实际的应用开发中较少运行

Java泛型中的标记符含义:

E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
<K,V>就是代表键值对的泛型