ArrayList<Integer> list = new ArrayList<Integer>();
这是Java 7之前的写法,很明显布局器上面的泛型没有必要,现在推举以下写法:
ArrayList<Integer> list = new ArrayList<>();
既然我已经指定了类型,那么添加时只能添加Integer,并且利用时可以直接当做Integer利用
System.out.println(list.get(2)+3);
这种参数化类型便是泛型,泛型便是许可在定义类、接口、方法时利用类型形参,这个参数形参将在申明变量、创建工具、调用方法时动态指定。

回到顶部
三、定义泛型接口、类来看看List接口和Map接口的定义:
public interface List<E> extends Collection<E>public interface Map<K,V>
List接口定义时指定了一个类型形参,Map接口定义了两个类型形参。接口定义了形参之后,在接口中形参就可以当做一种类型来利用,那么个中的方法就可以利用类型形参
boolean add(E e);
这种办法实在也是一种代码复用,我们通过类型形参,高度的将参数抽象,而不须要每种类型都去重新定义类,只要在利用时确定类型即可。我们也可以自定义泛型类
public class WebResult<T> { //利用T类型形参定义实例变量 private T data; public WebResult() { } //利用T类型形参布局工具 public WebResult(T data) { this.data = data; } public void setData(T data) { this.data = data; } public T getData() { return this.data; } public static void main(String[] args) { WebResult<String> webResult = new WebResult<>("返回一个String工具"); System.out.println(webResult.getData()); WebResult<Integer> webResult1 = new WebResult<>(10); System.out.println(webResult1.getData()); }}
四、通配符
先看下面这段代码:
public static void main(String[] str){ ArrayList<String> arrayList=new ArrayList(); test(arrayList);}public static void test(List<Object> test){ for (int i = 0; i <test.size() ; i++) { System.out.println(test.get(i)); }}
这段代码会涌现编译缺点,由于List<String>工具不能作为List<Object>利用,这解释泛型不是协变的,由于之前数组的设计是协变的,导致存在安全性问题,而泛型的设计原则是编译时不涌现警告就不会涌现类型转换缺点,那为了表示各种泛型的父类,就引入了通配符:?这个问号代表可以是匹配任何类型。
将方法修正:
public static void test(List<?> test){ for (int i = 0; i <test.size() ; i++) { System.out.println(test.get(i)); }}
这样便可以顺利编译,我们再加上这段代码:
public static void main(String[] str){ ArrayList<String> arrayList=new ArrayList(); test(arrayList); List<?> strings = arrayList; strings.add("abc");}
这里我们可以将arrayList给strings,按说这个时候是不能赋值的,由于List不知道类型参数的值,这是编译器浸染,可以进行类型推理,但是后面的strings.add("abc")是不能通过编译的,编译器不能对 List 的类型参数作出足够严密的推理,以确定将 String 通报给 List.add() 是类型安全的。以是编译器将不许可这么做。
4.1 设置通配符上限List<?>这种办法,通配的是所有的类型,很多时候我们可以确定是哪一类工具可以添加进去,我们只希望它代表某一类泛型的父类,这个时候我们可以设置通配符的上限。
//动物类public abstract class Animal { public abstract void say();}public class Cat extends Animal { @Override public void say() { System.out.println("喵喵"); }}public class Dog extends Animal { @Override public void say() { System.out.println("旺旺"); }}
这个时候我们就限定了上限
public static void test1(List<? extends Animal> animals) { for (int i = 0; i < animals.size(); i++) { animals.get(i).say(); }}
我们也可以直接在定义类型形参的时候设置上限
public class WebResult<T extends Animal> {
4.2 通配符下限
既然有设置上限,那也有设置下限,那在什么情形下会利用下限呢?看个例子
//将src中的凑集复制到dest,并返回末了一个值public static <T> T copy(Collection<T> dest, Collection<? extends T> src) { T last = null; for (T ele : src) { last = ele; dest.add(ele); } return last;}
功能比较很大略,将src中的凑集复制到dest,并返回src末了一个值
List<Number> ln = new ArrayList<>();List<Integer> li = new ArrayList<>();//编译出错,类型不愿定Integer last = copy(ln, li);
这个时候出错,由于虽然我们知道返回的值一定是Integer,但是由于copy方法的返回值并不是,所有相称于我们在复制的过程中丢失了src的类型,如果我们想定义约束关系使得返回值明确即:dest凑集元素类型与src的关系要么相同要么是其父类,为了表示这种约束关系,引入了<? super T> 这个通配符表示它必须是T本身或者T的父类。
//将src中的凑集复制到dest,并返回末了一个值public static <T> T copy(Collection<? super T> dest, Collection<? extends T> src) { T last = null; for (T ele : src) { last = ele; dest.add(ele); } return last;}
五、泛型方法
除了泛型接口和泛型类,我们还可以定义泛型方法,写法如下:
static <T> void arrayToList(T[] a, List<T> list) { for (T o : a) { list.add(o); }}
调用如下:
Object[] objects = new Object[10];List<Object> list = new ArrayList<>();arrayToList(objects, list);Integer[] integers = new Integer[10];List<Integer> integerList = new ArrayList();arrayToList(integers, integerList);String[] strings = new String[10];List<String> stringList = new ArrayList<>();arrayToList(strings, stringList);//编译缺点,类型禁绝确arrayToList(strings, integerList);
这里可以看出泛型方法跟类型通配符的功能有点类似,其实在大部分情形下我们可以用泛型方法代替类型通配符。
泛型方法许可类型形参被用来表示方法的一个或者多个参数之间的依赖关系,或者说与返回值之间的关系,如果没有这种关系,我们就不该用泛型方法。
六、擦除与转换当把一个具有泛型信息的工具赋给一个没有泛型信息的变量时,所有的类型信息就都丧失落了,比如List<String>类型被转换成List,则对该List的类型检讨也变成了Object。
public class WebResult<T extends Number> { //利用T类型形参定义实例变量 private T data; public WebResult() { } //利用T类型形参布局工具 public WebResult(T data) { this.data = data; } public void setData(T data) { this.data = data; } public T getData() { return this.data; } public static void main(String[] args) { WebResult<Integer> webResult1 = new WebResult<>(10); System.out.println(webResult1.getData()); WebResult<Integer> a = new WebResult<>(20); WebResult b = a; //已经擦除了泛型,只能按最高类型Object //Integer bData = b.getData(); Object object=b.getData(); }}
原来的泛型类上限是Number,而当把a赋给擦除泛型的b工具时,编译器失落去了推断能力,只能把其当做Objec来处理。
而当一个List转成泛型工具是java是许可的
List<Integer> integerList = new ArrayList<>();List stringList = integerList;//许可直接将list工具转换给List<String> strings = stringList;//直接获取数据会涌现缺点,由于转换不堪利System.out.println(stringList.get(0));
为帮助开拓者们提升口试技能、有机会入职BATJ等大厂公司,特殊制作了这个专辑——这一次整体放出。
大致内容包括了: Java 凑集、JVM、多线程、并发编程、设计模式、Spring百口桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大厂口试题等、等技能栈!
欢迎大家关注头条【JAVA后端架构】,回答【666】,获取以上最新Java后端架构VIP学习资料以及视频学习教程,然后一起学习,一文在手,口试我有。
每一个专栏都是大家非常关心,和非常有代价的话题,如果我的文章对你有所帮助,还请帮忙点赞、好评、转发一下,你的支持会勉励我输出更高质量的文章,非常感谢!