根据使用的地方分为3种,分别是泛型类,泛型方法和泛型接口。
在类名的后面加一对尖括号,括号中填写类型参数,参数可以有多个,多个参数之间使用逗号分隔。
下面是一个例子:
public class GenericTest { private E value; public E getValue(){ return value; } public void setValue(E e){ this.value = e; } } Java 还是建议使用单个大写字母来代表类型参数。常见的如:
- T 代表Type的意思,表示任意的类。
- E 代表 Element 的意思,或者 Exception 异常的意思。
- K 代表 Key 的意思。
- V 代表 Value 的意思,通常与 K 一起配合使用。
- S 代表 Subtype 的意思,文章后面部分会讲解示意。
在创建泛型类对象的时候指定相应的类型,如ArrayList
尖括号那一部分写在返回值之前。
有一点需要注意:不能使用别的方法中使用本方法中定义的泛型,会报错。可以理解为方法中定义的泛型,作用范围只有本方法。
下面是一个例子:
public class GenericTest2 { public void set(E e){ } } 类型推断:编译器会根据调用方法时实参的类型进行推断,所以不用在尖括号中间指定类型。例如,在上述代码中,编译器根据传递的参数"123" 将E指定为String 类型,它发生在编译时。
public class GenericDemo2 { public static void main(String[] args) { GenericTest2 g2 = new GenericTest2(); g2.set("123"); } } 练习1:定义一个工具类ListUtil,其中有一个静态方法,可以向不同的集合中添加多个元素。
public class ListUtil { private ListUtil(){ } public static void addAll (ArrayList list, E e1, E e2){ list.add(e1); list.add(e2); } } 在调用此方法将list传递过去的时候,会将E指定为String类型。
细节:而且这个方法可以传递集合中的元素是任意类型的ArrayList集合过去。
public class GenericDemo3 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); ListUtil.addAll(list, "3", "4"); Iterator iterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.next(); System.out.println(s); } } } 也是在接口的后面加上一对尖括号。
public interface Iterable { } 根据实现的时候是否确定类型有两种方式去实现接口。
方式1:在接口后面的尖括号中给出具体类型。
这里的类GenericDemo6在实现时给出具体的String类型,那么在创建实现类的对象时就不用再给出类型了,并且操作的只能是String类型的数据。
public class GenericDemo6 implements List { @Override public int size() { return 0; } @Override public boolean isEmpty() { return false; } ... } 方式2:实现类依然延续泛型,在类名和接口后面都加上一对尖括号,创建对象时再指定类型。
public class GenericDemo7 implements List { @Override public int size() { return 0; } @Override public boolean isEmpty() { return false; } ... } 细节:
一个.java文件里可以有多个类。
多个类中只能有一个public类,而且文件名只能是public类的名字;
如果多个类中没有public类,则文件名可以是任意一个类的名字。