1.泛型概述

泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数

一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型

这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口

泛型定义格式:

  • <类型>:指定一种类型的格式。这里的类型可以看成是形参
  • <类型1,类型2..>︰指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
  • 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换

2.泛型类

泛型类的定义格式:

  • 格式: 修饰符class类名< 类型 > { }
  • 范例: public class Generic< T > { }

此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型

  1. package com.study_02;
  2. public class Generic<T> {
  3. private T t;
  4. public T getT() {
  5. return t;
  6. }
  7. public void setT(T t) {
  8. this.t = t;
  9. }
  10. }
  1. package com.study_02;
  2. public class GenericDemo {
  3. public static void main(String[] args) {
  4. Generic<String> g1 = new Generic<>();
  5. g1.setT("林青霞");
  6. System.out.println(g1.getT());
  7. Generic<Integer> g2 = new Generic<>();
  8. g2.setT(30);
  9. System.out.println(g2.getT());
  10. Generic<Boolean> g3 = new Generic<>();
  11. g3.setT(true);
  12. System.out.println(g3.getT());
  13. }
  14. }

3.泛型方法

泛型方法的定义格式:

  • 格式:修饰符<类型>返回值类型方法名(类型变量名){}
  • 范例: public void show(T t){ }
  1. package com.study_03;
  2. //public class Generic {
  3. // public void show(String s) {
  4. // System.out.println(s);
  5. // }
  6. //
  7. // public void show(Integer s) {
  8. // System.out.println(s);
  9. // }
  10. //
  11. // public void show(Boolean s) {
  12. // System.out.println(s);
  13. // }
  14. //}
  15. //// 泛型类改进
  16. //public class Generic<T> {
  17. // public void show(T t) {
  18. // System.out.println(t);
  19. // }
  20. //}
  21. // 泛型方法改进
  22. public class Generic{
  23. public <T> void show(T t) {
  24. System.out.println(t);
  25. }
  26. }
  1. package com.study_03;
  2. public class GenericDemo {
  3. public static void main(String[] args) {
  4. // Generic<String> g1 = new Generic<>();
  5. // g1.show("dd");
  6. //
  7. // Generic<Integer> g2 = new Generic<>();
  8. // g2.show(3);
  9. Generic g = new Generic();
  10. g.show("hah");
  11. g.show(22);
  12. g.show(true);
  13. g.show(12.34);
  14. }
  15. }

4.泛型接口

泛型接口的定义格式:

  • 格式:修饰符interface接口名<类型>{ }
  • 范例: public interface Generic { }
  1. package com.study_04;
  2. public interface IGeneric<T> {
  3. void show(T t);
  4. }
  1. package com.study_04;
  2. public class Generic<T> implements IGeneric<T>{
  3. @Override
  4. public void show(T t) {
  5. System.out.println(t);
  6. }
  7. }
  1. package com.study_04;
  2. public class GenericDemo {
  3. public static void main(String[] args) {
  4. Generic<String> g1 = new Generic<>();
  5. g1.show("haha");
  6. Generic<Integer> g2 = new Generic<>();
  7. g2.show(55);
  8. }
  9. }

5.类型通配符

为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
  • 这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中

如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限

  • 类型通配符上限:<?extends类型>
  • List<? extends Number>:它表示的类型是Number或者其子类型

除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限

  • 类型通配符下限:<?super类型>
  • List<? super Number>:它表示的类型是Number或者其父类型
  1. package com.study_05;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class GenericDemo {
  5. public static void main(String[] args) {
  6. List<?> list1 = new ArrayList<Object>();
  7. List<?> list2 = new ArrayList<Number>();
  8. List<?> list3 = new ArrayList<Integer>();
  9. System.out.println("-------");
  10. // 类型通配符上限: <? extends 类型>
  11. // List<? extends Number> list4 = new ArrayList<Object>();
  12. List<? extends Number> list5 = new ArrayList<Number>();
  13. List<? extends Number> list6 = new ArrayList<Integer>();
  14. System.out.println("--------");
  15. // 类型通配符下线: <? super 类型>
  16. List<? super Number> list7 = new ArrayList<Object>();
  17. List<? super Number> list8 = new ArrayList<Number>();
  18. // List<? super Number> list9 = new ArrayList<Integer>();
  19. }
  20. }

6.可变参数

可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 格式:修饰符返回值类型方法名(数据类型…变量名){ }
  • 范例: public static int sum(int…a){ }

可变参数注意事项

  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
  1. package com.study_06;
  2. public class ArgsDemo01 {
  3. public static void main(String[] args) {
  4. System.out.println(sum(10,20,30,40,50,60));
  5. }
  6. // public static int sum(int b,int... a) {
  7. // return 0;
  8. // }
  9. public static int sum(int... a) {
  10. // System.out.println(a);
  11. int sum = 0;
  12. for (int i : a) {
  13. sum += i;
  14. }
  15. return sum;
  16. }
  17. }

7.可变参数的使用

Arrays.工具类中有-一个静态方法: \

  • publicstatic List asList(T.. a):返回由指定数组支持的固定大小的列表
  • 返回的集合不能做增删操作, 可以做修改操作

List接口中有一个静态方法:

  • public static List of(… elements): 返回包含任意数量元素的不可列表
  • 返回的集合不能做增删改操作

Set接口中有一个静态方法:

  • public static Set of(… elements) :返回一个包含任意数量元素的不可集合
  • 在给元素的时候,不能给重复的元素
  • 返回的集合不能做增删操作,没有修改的方法
  1. package com.study_06;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import java.util.Set;
  5. public class ArgsDemo02 {
  6. public static void main(String[] args) {
  7. // List<String> list = Arrays.asList("hello", "niaho");
  8. //
  9. //// list.add("k"); // UnsupportedOperationException
  10. // list.remove("hello"); // UnsupportedOperationException
  11. // list.set(1,"javase");
  12. //
  13. // System.out.println(list);
  14. // List<String> list = List.of("hello", "world","world");
  15. // list.add("javaee"); // UnsupportedOperationException
  16. // list.remove("hello"); // UnsupportedOperationException
  17. // list.set(1,"javase"); // UnsupportedOperationException
  18. // System.out.println(list);
  19. // Set<String> set = Set.of("hello", "world", "java","hello"); // IllegalArgumentException
  20. Set<String> set = Set.of("hello", "world", "java");
  21. // set.add("hah"); // UnsupportedOperationException
  22. // set.remove("world"); // UnsupportedOperationException
  23. System.out.println(set);
  24. }
  25. }