Java泛型和通配符解决了类型参数化的问题,使用主要有如下几种组合:
泛型 | 通配符 | 同时使用泛型加+通配符 | |
定义类 | 不可使用 | 不可用 | |
定义方法 |
1.在定义类时使用泛型:
泛型占位符<T>位于类名之后,左花括号之前,表明这是一个泛型类,格式如下:
类修饰符 类名 <T> {
}
例如:
class Demo1<T>{
T field;
public T getField(){
return this.field;
}
public void setField(T t){
this.field = t;
}
}
public class Main {
public static void main(String[] args){
Demo1<String> demo = new Demo1<String>();
demo.setField("定义泛型类");
System.out.println(demo.getField());
}
}
2.在定义方法是使用泛型:
在普通类和泛型类中都可以定义泛型方法,格式是(<T>为泛型占位符):
分为如下几种:
(1)无返回值,无形参方法:
方法修饰符 <T> 方法返回值 方法名(){}
(2)无返回值,有形参方法:
方法修饰符 <T> 方法返回值 方法名(T t){}
(3)有返回值,有形参方法:
方法修饰符 <T> Class<T> 方法名(){}
(4)有返回值,有形参方法:
方法修饰符 <T> Class<T> 方法名(T t){}
举例说明:
class Demo1<T>{
T field;
public T getField(){
return this.field;
}
public void setField(T t){
this.field = t;
}
//无返回值无参数泛型方法
public <E> void printClass(){
ArrayList<E> al = new ArrayList<E>();
System.out.print("执行无返回值无参数泛型方法");
System.out.println(al.getClass());
}
//无返回值有参数泛型方法
public <E> void printClass2(E e){
System.out.print("执行无返回值有参数泛型方法");
System.out.println(e.getClass());
}
//有返回值无参数泛型方法
public <E> ArrayList<E> newArray(){
System.out.println("执行有返回值无参数泛型方法");
return new ArrayList<E>();
}
//有返回值有参数泛型方法
public <E> ArrayList<E> newArray2(E e){
System.out.println("执行有返回值有参数泛型方法");
return new ArrayList<E>();
}
}
public class Main {
public static void main(String[] args){
Demo1<String> demo = new Demo1<String>();
demo.printClass();
demo.printClass2("执行有泛型形参无返回值");
demo.newArray();
demo.newArray2("执行有泛型形参有返回值");
}
}
执行结果:
执行无返回值无参数泛型方法class java.util.ArrayList
执行无返回值有参数泛型方法class java.lang.String
执行有返回值无参数泛型方法
执行有返回值有参数泛型方法
在定义方法时使用泛型可以使用extends关键字指定泛型的上界,例如:
class Demo {
public <T extends Number> void showClass(T t) {
System.out.println(t.getClass());
}
}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Demo demo = new Demo();
demo.showClass(123);
demo.showClass(123f);
demo.showClass(123L);
// demo.showClass("123"); 有错误 参数的类型,只能是 Number类型或者其子类
}
}
3.在定义方法时使用通配符?:
class Demo {
public void show(List<?> list) {
//只能往list里面添加null
list.add(null);
//list.add(123); 编译错误
//list.add(new Object());编译错误
for (Object object:list) {
System.out.println(object);
}
}
}
public class Main {
public static void main(String[] args){
Demo demo = new Demo();
List<Integer> listInt = new ArrayList<Integer>();
listInt.add(123);
demo.show(listInt);
List<String> listStr = new ArrayList<String>();
listStr.add("字符串");
demo.show(listStr);
}
}
注意:
由于程序无法确认list中的元素类型,所以不能向其中添加对象,连Object类型都不行.除了null(null是所有引用类型的示例)
5.在定义方法时同时使用泛型加通配符:
一般用 extends/super关键字分别指定形参类型的上界/下界(包含上界/下界):
public class Main {
public static <T> void copy0(List<T> src,List<T> dest){
for(T t:src){
dest.add(t);
}
}
public static <T> void copy1(List<T> src,List<? super T> dest){
for(T t:src){
dest.add(t);
}
}
public static <T> void copy2(List<? extends T> src,List<T> dest){
for(T t:src){
dest.add(t);
}
}
public static void main(String[] args){
List<Integer> srcList = new ArrayList<Integer>();
List<Integer> destList0 = new ArrayList<Integer>();
List<Number> destList1 = new ArrayList<Number>();
List<Number> destList2 = new ArrayList<Number>();
srcList.add(1);
srcList.add(23);
srcList.add(456);
copy0(srcList,destList0);
copy1(srcList,destList1);
copy2(srcList,destList2);
System.out.println("destList0[0]" + destList0.get(0));
System.out.println("destList1[1]:" + destList1.get(1));
System.out.println("destList2[2]:" + destList2.get(2));
}
}
最后说一下泛型数组:
数组元素不能包含类型变量或类型形参;
//不允许定义这样的数组
//List<String>[] lsa = new ArrayList<String>[10];
但可以声明元素类型包含类型变量或类型形参的数组:
//允许这样声明数组
List<String>[] lsa = new ArrayList[10];
也可以使用通配符声明数组;
//也可以使用通配符声明数组
List<?>[] lsa = new ArrayList<?>[10];
但在使用中要注意使用instanceof运算符来保证数据类型.
待续.
本文部分参考于:
https://www.bo56.com/java%E6%B3%9B%E5%9E%8B%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B%E6%95%B4%E7%90%86/