下面的代码是会出现异常的:
List<?> poems = new ArrayList();
poems.add(“life is a song”);
?表示这个List集合中保存的元素是未知类型的,Java不允许把对象放进一个未知类型的集合中,正常的:
package generic;
import java.util.ArrayList;
import java.util.List;
/**
- Created by zhoujie on 1/25/16.
*/
public class First {
/**
-
? 都处理成Object, 处理所有类型
-
可以通过返回一个 List<?>的值, 都被当成Object来处理
-
@param c
*/
public static void display(List<?> c) {
for (int i = 0; i < c.size(); i++) {
// c.get(i) 是Object类型的
System.out.println(c.get(i));
}
}
public static void main(String[] args) {
List poems = new ArrayList<>();
poems.add(“life is a song”);
poems.add(“some one like you”);
poems.add(“you are so beautiful”);
display(poems);
}
}
List<? extends Animal>, 通配符的上限
Animal.java:
public abstract class Animal {
public abstract void sing(Perform p);
}
Cat.java:
public class Cat extends Animal {
@Override
public void sing(Perform p) {
System.out.println(“Hello, audience, I’m a Cat.”);
}
}
Dog.java:
public class Dog extends Animal {
@Override
public void sing(Perform p) {
System.out.println(“Hello, audience, I’m a dog.”);
}
}
Perform.java:
public class Perform {
public void perform(List animals) {
for (Animal a : animals) {
a.sing(this);
}
}
}
下面写一个类测试一下上面的几个类:
public class TestGeric {
public static void main(String[] args) {
List dogs = new ArrayList<>();
Perform p = new Perform();
dogs.add(new Dog());
p.perform(dogs); // 此处代码编译出现异常
}
}
List不能和perform中的参数 List animals对应起来,说明List并不是List的子类型,可以将Perform类的代码改成:
public class Perform {
public void perform(List<?> animals) {
for (Object o : animals) {
Animal a = (Animal)o;
a.sing(this);
}
}
}
这样的改进使用了泛型却还需要进行强制类型转换,略显繁琐。
继续改进Perform类:
public class Perform {
public void perform(List<? extends Animal> animals) {
for (Animal a : animals) {
a.sing(this);
}
}
}
终于引出了可爱的List<? extends Animal>,?表示的类型可以是Animal类型和Animal的子类。可以把Animal称为这个通配符(?)的上限(upper bound)。
和一开始讲的List<?>一样,List<? extends Animal> 通常也是当作函数的参数来指定,
public void addMonkey(List<? extends Animal> animals) {
// 下行代码出现编译错误
animals.add(0, new Monkey());
}
带 ?的泛型表达一般都当做方法参数或方法返回值来使用,也就是本笔记中讲述的泛型方法相关。
还有就是,如下代码:
public class Apple {
T col;
public static void main(String[] args) {
//类型只能是Number类型或Number的子类型
Apple ai = new Apple<>();
//编译错误
//Apple as = new Apple<>();
}
}
<? super E>通配符的下限
来看一段代码:
public static T copy(Collection<? super T> dest, Collection src){
T last = null;
for (T ele : src) {
last = ele;
dest.add(ele);
}
return last; //返回一个T类型的变量
}
/*
<? super Type> 通配符 ? 表示它必须是Type本身,或是Type的父类 */ // 栗子 List ln = new ArrayList<>(); List li = new ArrayList<>(); li.add(2016); // 此处可准确地知道最后一个被复制的元素是Integer类型 // 与src集合的元素类型相同 Integer ele = copy(ln, li); 在集合框架中的 TreeSet有一个构造器也用到了这种设定通配符下限的语法, TreeSet(Comparator<? super E> c) ## 总结 互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。 **另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 ** **下面有部分截图希望能对大家有所帮助。** ![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/235b6482f5997b78590fda86ebc24557.webp?x-oss-process=image/format,png) 设定通配符下限的语法, TreeSet(Comparator<? super E> c) ## 总结 互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。 **另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 ** **下面有部分截图希望能对大家有所帮助。** [外链图片转存中...(img-2KrINfy6-1714738164063)] > **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/topics/618154847)收录**