泛型
1、泛型方法
调用方法时需要指定泛型的具体类型。
定义泛型方法的规则:
- 所有的泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
- 每一个类型参数声明部分包含一个或者多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。
- 泛型的类型参数只能代表引用类型,不能是基本类型
public <T> void test(){ }
public <T> String test1(){ return null; }
public <T> T test2(){ return null; } public <T> T test3(T[] t){ return t[0]; } public <T> void test4(T t){ } public <T> T test5(T t){ return t; } public <T,E> void test6(T t, E e){ } public <T,E> T test7(){ return null; } public <T,E> T test8(T t, E e){ return t; } public <T,E,K> T test9(Map<T,E> map){ return null; }
有界参数类型:
有界是指对泛型的参数类型进行限制。
有界类型参数使用extends关键字后面跟边界类型。注意:虽然用的是extends关键字,却不仅限于继承父类E的子类,也可以代指显现了接口E的子类。
多边界泛型:<T extends A & B & C>。注意:A为父类,B、C是接口。
public <T extends Number> void test10(T t){ byte b = t.byteValue(); } public <T extends Number& Comparable<T>> Integer test11(T t1,T t2,T t3){ T max = t1; if(t2.compareTo(t1) > 0) { max = t2; } if(t3.compareTo(t1) > 0){ max = t3; } return max.intValue(); }
调用泛型方法
public void testGen(){ //int[] abc = new int[2]; //参数类型只能是引用类型,不能是基本类型 Integer[] abc = new Integer[2]; Integer var1 = test3(abc); Integer var2 = test11(1,2,3); }
泛型静态方法
Java中任何方法,包括静态的和非静态的,均可以用泛型来定义,而且和所在类是否是泛型没有关系。注意,泛型类不允许在静态环境中使用。
下面是泛型方法的定义:[public] [static] <T> 返回值类型 方法名(T 参数列表)
public static <T> T getT(){ return null; }
2、泛型类
泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
和泛型方法一样,泛型类的类型参数声明部分也包含一个或者多个类型参数,参数间用逗号隔开。
一个泛型参数,也被称为一个类型变量,是用于指定一个泛型名称的标识符。
public class TestGenerics<T> { private T t; private T a; private T b; public TestGenerics(T a,T b){ this.a = a; this.b = b; } public void add(T t){ this.t = t; } public T getA(){ return a; } public T getB(){ return b; } public static void main(String[] args) { TestGenerics<String> testGenerics = new TestGenerics<>("hello","world"); String strA = testGenerics.getA(); String strB = testGenerics.getB(); TestGenerics<Integer> testGenerics1 = new TestGenerics<>(1,2); Integer intA = testGenerics1.getA(); Integer intB = testGenerics1.getB(); } }
通配符
通配符【?】表示一种未知的类型,常用在方法上。
泛型【T】和通配符【?】的区别:
- 泛型需要在方法返回值前面声明类型参数,通配符不需要
- Java编译器将泛型推断成具体的类型,把通配符推断成未知类型。java编译器只能操作具体的类型,不能操作未知的类型。
- 需要操作参数类型使用泛型,查看参数可以使用通配符
无界通配:指的是不限制通配符的界限
上界通配:定义通配符的上界,用关键字extends声明,形如 List<? extends Number>来定义,表示类型只能结束Number类型及其子类
下界通配:定义通配符的下届,用关键字super声明,形如 List<? super Number>来定义,表示类型只能接受Number及其三层父类类型
import java.util.ArrayList; import java.util.List; public class TestGenerics2{ public static void main(String[] args) { List<Integer> list1 = new ArrayList<>(); list1.add(1); List<String> list2 = new ArrayList<>(); list2.add("hello"); List<Number> list3 = new ArrayList<>(); list3.add(2); getData(list1); getData(list2); getNum(list1); // getNum(list2); //只能是Number类型的及其一下类型 // getNum2(list1); //只能是Number类型及其以上类型 getNum2(list3); } /** * 泛型方法 * @param list * @param <T> */ public static <T> void setData(List<T> list){ list.add((T) new Object()); list.add(null); } /** * 无界通配符 * @param list */ public static void getData(List<?> list){ System.out.println(list.get(0)); // list.add(new Object()); //无法添加 list.add(null); } /** * 上界通配符 * @param list */ public static void getNum(List<? extends Number> list){ System.out.println(list.get(0)); } /** * 下届通配符 * @param list */ public static void getNum2(List<? super Number> list){ System.out.println(list.get(0)); } }
3、泛型接口
泛型接口的声明和非泛型接口的声明类似,除了在接口名后面添加了类型参数声明部分。
通过类去实现泛型接口时,需要指定泛型参数T的类型
public interface IGenerics3<T> { int f = 10; //默认是 static final T next(T t); //默认是 public }
实现类
public class Generics3Impl implements IGenerics3<Integer>{ @Override public Integer next(Integer integer) { return null; } } public class Generics3Impl implements IGenerics3<String>{ @Override public String next(String s) { return null; } }