public static void main(String[] args) {
ArrayList apples=new ArrayList();
for(int i=0;i<3;i++){
apples.add(new Apple());
}
for(Apple apple:apples){
System.out.println(apple.name());
}
}
}
Output:
apple0
apple1
apple2
当你指定了某个类型作为泛型参数时,你并不仅限于只能将确切类型的对象放置到容器中。向上转型也可以像作用于其他类型一样作用于泛型。
因此,可以将Apple的子类型添加到被指定为保存Apple对象的容器中。
1.1 基本概念
Java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:
-
Collection:
一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素,Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)
-
Map:
一组成对的"键值对(key-value)"对象,允许你使用键来查找值。ArrayList允许你使用数字来查找值,因此在某种意义上将,它将数字与对象关联在了一起。映射表允许我们使用另一个对象来查找对象,它也被称为"关联数组",因为它将某些对象与另外一些对象关联在了一起;或者被称为"字典",因为你可以使用键对象来查找值对象,就像在字典中使用单词来定义一样。Map是强大的编程工具。
理想情况下,编写的代码都是在与这些接口打交道,并且你唯一需要指定所使用精确类型的地方就是在创建的时候。下面创建一个List: List<Apple> apples =new ArrayList<Apple>();
这里,ArrayList被向上转型为List。使用接口的目的在于如果你决定去修改你的实现,所需做的只是在创建处修改它,就像下面这样: List<Apple> apples =new LinkedList<Apple>();
所以一般实际中,我们应该创建一个具体类的对象,将其转型为对应的接口,然后在其余的代码中都使用这个接口。
1.2 添加一组元素:
在java.util的Arrays和Collection类中都有很多实用方法,可以在一个Collection中添加一组元素。
-
Arrays.asList()方法:
接受一个数组或是一个用逗号分隔的元素列表,并将其转换为一个List对象。
-
Collection.addAll()方法:
接受一个Collection对象,以及一个数组或是一个用逗号分割的列表,并将元素添加到Collection中。
public class AsListInference {
public static void main(String[] args) {
Collection collection=new ArrayList(Arrays.asList(1,2,3));
Integer []arr={4,5,6};
collection.addAll(Arrays.asList(arr));
Collections.addAll(collection,7,8,9);
Collections.addAll(collection,arr);
List list= Arrays.asList(1,2,3);
list.set(1,99);
//容器可以在无需任何帮助下打印
System.out.println(collection);
System.out.println(list);
}
}
Output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 5, 6]
[1, 99, 3]
Collection.addAll() 方法运行起来很快,而且构建一个不包含元素的Collection,同时调用Collections.addAll() 这种方式很方便,因此它是首选方式。但是 Collection.addAll() 成员方法只能接受另一个Collection对象作为参数,因此它不如 Arrays.asList() 或 Collections.addAll() 灵活,这两个方法使用的都是可变参数列表。
注意:若使用Arrays.asList()给一个List赋值,需要使用显式类型参数说明,否则会自动寻找它们的共同最浅的基类,这样如果向上转型至根类,则会报错;但是若使用,Collections.addAll()则不存在这个问题。
2.1 List
List承诺可以将元素维护在特定的序列中。List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和移除元素。
有两种类型的List:
1. ArrayList: 它可以随机访问元素,但是在List的中间插入和移除元素时较慢;
/**
-
@Author: Ly
-
@Date: 2020-08-13 08:46
*/
public class ListFeatures {
public static void main(String[] args) {
List li = new ArrayList();
for(int i = 0; i < 10; i++)
li.add(i);
Integer h = 10;
li.add(h); //将指定的元素追加到此列表的末尾
li.add(1,0); //将指定的元素插入此列表中的指定位置
li.remove(0); //删除该列表中指定位置的元素
System.out.println(li);
System.out.println(li+"集合中含有:h "+li.contains(h));
li.set(0,10); //用指定的元素替换此列表中指定位置的元素
Integer p = li.get(0);//返回此列表中指定位置的元素
System.out.println(“数字”+p + “第一次出现位置的索引为:” + li.indexOf§); //打印此列表中指定元素的第一次出现的索引
li.remove§; //删除指定元素的第一次出现
System.out.println(li);
List sub = li.subList(1, 4);//用列表中第1到第4个(不包含第4个)元素创建新的集合
Boolean bl=li.containsAll(sub); //看列表是否包含指定集合的所有元素
System.out.println(“集合li中”+ (bl?“含有”:“不含有”) +“sub中的所有元素”);
List copy = new ArrayList(li);
copy.removeAll(sub); //从此列表中删除包含在指定集合中的所有元素
System.out.println(“copy集合:”+copy);
if(copy.size() > 1) //如果列表中的元素数大于1
copy.addAll(2, sub);//将指定集合中的所有元素插入到此列表中的指定位置
System.out.println(“copy集合:”+copy);
Object[] objects = li.toArray();//以正确的顺序返回一个包含此列表中所有元素的数组
for(Object o:objects){
System.out.print(o+", ");
}
System.out.println(li.isEmpty());//如果此列表不包含元素,则返回 true
li.clear();//从此列表中删除所有元素
System.out.println(li+“:”+ li.isEmpty());
}
}
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]集合中含有: h true
数字10第一次出现位置的索引为:0
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
集合li中含有sub中的所有元素
copy集合:[1, 5, 6, 7, 8, 9, 10]
copy集合:[1, 5, 2, 3, 4, 6, 7, 8, 9, 10]
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, false
[]:true
2. LinkedList: 它通过代价较低的在List中间插入和删除操作,提供了优化的顺序访问。LinkedList在随机访问方面相对比较慢,但是它的特性集较ArrayList更大。
例:
/**
-
@Author: Ly
-
@Date: 2020-08-13 12:24
*/
public class LinkedListFeatures {
public static void main(String[] args) {
LinkedList list = new LinkedList();
for (int i = 1; i < 10; i++) {
list.add(i);
}
System.out.print(list.getFirst()+" "); //返回此列表中的第一个元素,为空时抛出异常
System.out.print(list.element()+" "); //检索但不删除此列表的头,为空时抛出异常
System.out.print(list.peek()+" "); //检索但不删除此列表的头,为空时返回null
System.out.print(list.removeFirst()+" "); //检索并删除此列表的头,为空时抛出异常
System.out.print(list.remove()+" "); //检索并删除此列表的头,为空时抛出异常
System.out.print(list.poll()+" "); //检索并删除此列表的头,为空时返回null
System.out.println();
System.out.println(list);
list.addFirst(0); //在该列表开头插入指定的元素
list.offer(10); //将指定的元素添加为此列表的末尾
list.add(11); //将指定的元素追加到此列表的末尾
list.addLast(12); //将指定的元素追加到此列表的末尾
list.removeLast(); //从此列表中删除并返回最后一个元素。
System.out.println(list);
}
}
Output:
1 1 1 1 2 3
[4, 5, 6, 7, 8, 9]
[0, 4, 5, 6, 7, 8, 9, 10, 11]
LinkedList也像ArrayList一样实现了基本的List接口,但是它执行某些操作时比ArrayList更高效,但是随机访问操作方面要差一些。LinkedList中添加了可以使其用作栈、队列或双端队列的方法。
3. Stack:
“栈”通常是指“后进先出(LIFO)”的容器
,有时也称为叠加栈,LinkedList具有能够直接实现栈的所有功能的方法,因此可以直接将LinkedList作为栈使用。
/*
-
通过使用泛型,引入了在栈的类定义中最简单的可行示例。
-
类名之后的告诉编译器这将是一个参数化类型(在类被使用时将会被实际类型替换的参数)。
-
Stack使用LinkedList实现的,而LinkedList也被告知它将持有T类型对象;
*/
class Stack {
private LinkedList storage=new LinkedList();
public void push(T v){storage.addFirst(v);}
public T peek() {return storage.getFirst();}
public T pop () {return storage.removeFirst();}
public boolean empty () {return storage.isEmpty(); }
public String toString (){return storage.toString();}
}
public class StackTest{
public static void main(String[] args) {
Stack stack = new Stack ();
for (String s : “One Two Three”.split(" "))
stack.push(s);
while (!stack.empty())
System.out.print(stack.pop()+" ");
}
}
Output:
Three Two One
2.2 Set
Set不保存重复的元素;
Set中最常用的是测试归属性,可以很容易地询问某个对象是否在某个Set中。正因如此,查找成了Set中最重要的操作,因此通常会选择一个HashSet的实现,它专门对快速查找进行了优化。(Hash查找最快。)
/**
-
@Author: Ly
-
@Date: 2020-08-14 19:27
*/
public class SetOfInteger {
public static void main(String[] args) {
Random rand=new Random(47);
Set intSet =new HashSet();
//如果想对结果排序,使用TreeSet来替代HashSet,不过在测试HashSet时你会发现打印出来的也是排序好的结果
//SortedSet intSet =new TreeSet();
for (int i = 0; i<10000 ; i++){
intSet.add(rand.nextInt(30));
};
System.out.println(intSet);
//使用contains()测试Set的归属性
System.out.println(intSet.contains(5));
System.out.println(intSet.contains(30));
}
}
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
true
false
TreeSet将元素存储在红-黑数据结构中,而HashSet使用的是散列函数。LinkedHashSet因为查询速度的原因也使用了散列,但是看起来它使用了链表来维护元素的插入顺序。
2.3 Map
将对象映射到其他对象的能力是一种解决编程问题的杀手锏;
考虑一个程序,它将用来检查Java的Random类的随机性。理想情况下,Random可以产生理想的数字分布,但要想测试它,则需要生成大量的随机数,并对落入各种不同范围的数字进行计数。Map可以很容易地解决该问题。在这个问题中,键是由Random产生的数字,值是该数字出现的次数:
/**
-
@Author: Ly
-
@Date: 2020-08-14 20:38
*/
public class Statistics {
public static void main(String[] args) {
Random rand=new Random(47);
Map<Integer,Integer> m=
new HashMap<Integer,Integer>();
for(int i= 0; i <10000 ;i++){
int r=rand.nextInt(20);
Integer freq = m.get®;
m.put(r,freq==null ? 1 : freq+1);
}
System.out.println(m);
//containsKey()和containsValue()来测试Map,以便查看它是否包含某个键或某个值:
System.out.println(m.containsKey(10));
System.out.println(m.containsValue(500));
}
}
Output:
{0=481, 1=502, 2=489, 3=508, 4=481, 5=503, 6=519, 7=471, 8=468, 9=549,
10=513, 11=531, 12=521, 13=506, 14=477, 15=497, 16=533, 17=509, 18=478, 19=464}
true
false
Map与数组和其他的Collection一样,可以很容易地扩展到多维,而我们只需将其值设置为Map(这些Map的值可以是其他容器,甚至是其他Map)。因此,能够很容易地将容器组合起来从而快速地生成强大的数据结构。
class Person{
private String name;
Person(String name){
this.name=name;
}
@Override
public String toString() {
return name;
}
}
public class MapOfList {
public static Map<Person , List>
petPeople = new HashMap<Person,List>();
static{
petPeople.put(new Person(“Dawn”),
Arrays.asList (“Cymric_Molly”,“Mutt_Spot”));
petPeople.put(new Person(“Kate”),
Arrays.asList (“Cat_Shackleton”, “Cat_Elsie”, “Dog_Margret”));
petPeople.put(new Person(“Marilyn”),
Arrays.asList(“Pug_Louie”, “Cat_Negro”, “Cat_Pinkola”));
petPeople.put (new Person(“Luke”),
Arrays.asList(“Rat_Fuzzy”, “Rat_Fizzy”));
petPeople.put(new Person (“Isaac”),
Arrays.asList(“Rat_Freckly”));
}
public static void main(String[] args) {
System.out.println("People: "+ petPeople.keySet());
System.out.println("Pets: "+ petPeople.values());
for(Person person : petPeople.keySet()){
System.out.print(person + " has : ");
for (String str : petPeople.get(person))
System.out.print(" "+str);
System.out.println();
}
}
}
Output:
Luke has : Rat_Fuzzy Rat_Fizzy
Marilyn has : Pug_Louie Cat_Negro Cat_Pinkola
Isaac has : Rat_Freckly
Dawn has : Cymric_Molly Mutt_Spot
Kate has : Cat_Shackleton Cat_Elsie Dog_Margret
Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。
2.4 Queue
队列是一个典型的先进先出(FIFO)的容器。
即从容器的一端放入事物,从另一端取出,并且将事物放入容器的顺序与取出的顺序是相同的。队列常被当作一种可靠的将对象从程序的某个区域传输到另一个区域的途径。队列在并发编程中特别重要。
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。通过将LinkedList向上转型为Queue,下面的示例使用了在Queue接口中与Queue相关的方法:
/**
-
@Author: Ly
-
@Date: 2020-08-14 21:00
*/
public class QueueDemo {
public static void printQ(Queue queue) {
//peek(),element(): 在不移除的情况下返回队头
//peek():在队列为空时返回null
//element():在队列为空时抛出NoSuchElementException异常
while(queue.peek()!= null)
一线互联网大厂Java核心面试题库
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!
加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。通过将LinkedList向上转型为Queue,下面的示例使用了在Queue接口中与Queue相关的方法:
/**
-
@Author: Ly
-
@Date: 2020-08-14 21:00
*/
public class QueueDemo {
public static void printQ(Queue queue) {
//peek(),element(): 在不移除的情况下返回队头
//peek():在队列为空时返回null
//element():在队列为空时抛出NoSuchElementException异常
while(queue.peek()!= null)
一线互联网大厂Java核心面试题库
[外链图片转存中…(img-j8piAhsK-1725654227982)]
正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!
加入社区:https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0