最近看视频学习Java中的集合,个人觉得老师说的很好的一点就是,先学习LIst和Set共有的方法,也就是他们的父系接口Collection中的方法。
下面是Collection接口常见的实现类。
直奔主题前,我们需要先解释一下下面一行代码
Collection c = new ArrayList();
ArrayList实现了Collection接口,所以我们创建的时候,可以把它赋值给Collection,这是多态的写法,也是面向接口编程的一种方式。
这种写法,只能调用Collection中定义的方法,运行时,对象调用的ArrayList当中的实现方法。
上面这句话是什么意思呢,我写了下面两行代码测试。
Collection list = new ArrayList();
List list2 = new ArrayList();
这里我们尝试调用两个对象的方法,结果如下:
左边的插图是list对象也就是以Collection作为多态父类的对象,右边的插图是list2也就是以List多态父类的对象。
可以看出list可以调用的方法和Collection定义的方法完全一致,也就是说虽然它是new的ArrayList对象,但由于这种多态写法,实际上它只能调用Collection中定义的方法(这些方法在Collection接口中只是定义并没有实现,所以我们借助了ArrayList实现这些方法)。
可以看出list2对象可以调用的方法多于list对象。原因就是它是以List接口作为多态父类,而List接口继承自Collection接口,并多定义了一些方法(下图列出了List接口和Collection接口中的所有方法),所以list2对象可以调用额外的方法。
综上所诉,ArrayList是List的实现类,List是Collection的子接口,所以ArrayList当中必须覆盖Collection当中定义的方法。这种多态写法,运行时,调用的还是ArrayList覆盖实现的方法。
进入主题
下面介绍Collection接口中定义的方法,由于它只是一个接口,所以我们借助于它的实现类ArrayList帮我们验证一些方法。
1. Collection中的add方法(添加元素)
import java.util.ArrayList;
import java.util.Collection;
public class Blog {
public static void main(String[] args) {
Collection c = new ArrayList();
//添加元素
boolean b1 = c.add("dog");
//添加基本数据类型,会自动帮你装箱成包装类
boolean b2 = c.add(10);
//添加重复的元素
boolean b3 = c.add("dog");
//添加自定义的对象
Student sn = new Student();
sn.name = "zs";
sn.age = 10;
boolean b4 = c.add(sn); //对象不加引号,Java中加引号则代表字符串
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
System.out.println(b4);
System.out.println(c);
}
}
class Student{
int age;
String name;
}
上述代码输出结果为:
true
true
true
true
[dog, 10, dog, Student@15db9742]
从输出结果可以看到,ArrayList是可以存放重复元素,并且如果存放对象的话,其存放的是对象的地址。
2. Collection中的remove方法(删除元素)
import java.util.ArrayList;
import java.util.Collection;
public class Remove {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
System.out.println(c);
//从集合当中删除指定的元素
c.remove("a");
System.out.println(c);
}
}
输出结果是
[a, b, c]
[b, c]
3. Collection中的isEmpty方法(判断集合是否为空)
import java.util.ArrayList;
import java.util.Collection;
public class IsEmpty {
public static void main(String[] args) {
Collection c = new ArrayList();
System.out.println(c.isEmpty());
c.add("a");
System.out.println(c.isEmpty());
}
}
输出结果为:
true
false
4. Collection中的size方法(获取集合当中的长度)
import java.util.ArrayList;
import java.util.Collection;
public class Size {
public static void main(String[] args) {
Collection c = new ArrayList();
System.out.println(c.size());
c.add("a");
System.out.println(c.size());
c.add("c");
c.add("c");
c.add("c");
System.out.println(c.size());
}
}
输出结果是:
0
1
4
5. Collection中的clear方法(清空集合中的所有元素)
import java.util.ArrayList;
import java.util.Collection;
public class Clear {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("a");
c.add("a");
c.add("a");
c.add("a");
c.add("a");
System.out.println(c.size());
System.out.println(c);
c.clear();
System.out.println(c.size());
System.out.println(c);
}
}
输出结果如下:
5
[a, a, a, a, a]
0
[]
6. Collection中的addAll方法(把一个集合当中的所有元素合并到另一个集合当中去)
import java.util.ArrayList;
import java.util.Collection;
public class AddAll {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2 = new ArrayList();
c2.add("d");
c2.add("f");
c2.add("g");
System.out.println(c1);
System.out.println(c2);
//将c2中的所有元素合并到c1中
c1.addAll(c2);
System.out.println(c1);
System.out.println(c2);
//如果使用add方法,结果如何呢?
c1.add(c2);
System.out.println(c1);
System.out.println(c1.size());
}
}
输出结果如下:
[a, b, c, d]
[d, f, g]
[a, b, c, d, d, f, g]
[d, f, g]
[a, b, c, d, d, f, g, [d, f, g]]
8
从结果中可以看出ArrayList中实现自Collection中接口定义的addAll方法是将另一个集合中的所有元素逐个加入调用此方法的集合,如果其中有重复的元素,也不影响结果。并且由于List中存放的数据有序,新生成的集合中的元素其实是在原来集合的尾部逐个添加的新元素。
这里需要注意的一点是如果使用add方法,那么是将整个集合当成一个元素添加到原集合中,并非逐个添加的,这一点我们可以从size方法中看出。
7. Collection中的removeAll方法(从一个集合当中删除两个集合的交集)
import java.util.ArrayList;
import java.util.Collection;
public class RemoveAll {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
System.out.println(c1);
Collection c2 = new ArrayList();
c2.add("a");
c2.add("b");
c2.add("e");
System.out.println(c2);
c1.removeAll(c2);
System.out.println(c1);
}
}
输出结果为:
[a, b, c, d]
[a, b, e]
[c, d]
8. Collection中的containsAll方法(判断集合是是否全部包含传入集合中的内容,是则返回true,否则返回false。
import java.util.ArrayList;
import java.util.Collection;
public class ContainsAll {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
Collection c2 = new ArrayList();
c2.add("a");
c2.add("b");
c2.add("e");
boolean ans = c1.containsAll(c2);
System.out.println(ans);
}
}
输出结果:
false //因为c2集合当中有c1集合当中没有的元素
9. Collection中的retainAll方法(取两个集合的交集,并将此交集赋给调用此方法的集合)
retainAll方法也就是把原集合修改为和指定集合的交集。如果原集合变化了(也就是原集合真包含于交集)那么返回true,如果原集合未发生变化(也就就是原集合等于交集)那么返回false。
import java.util.ArrayList;
import java.util.Collection;
public class RetainAll {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("a");
c1.add("b");
c1.add("c");
c1.add("d");
c1.add("e");
Collection c2 = new ArrayList();
c2.add("a");
c2.add("b");
c2.add("c");
System.out.println(c1);
boolean b = c1.retainAll(c2);
System.out.println(c1);
System.out.println(b);
}
}
输出结果
[a, b, c, d, e]
[a, b, c]
true
Collection中的toArray方法(将集合转成数组)
toArray方法将集合转成数组后,它将集合中的元素都自动转成Object类型。这里有个问题是如果当初集合当中存放的是自定义的对象,那么如果要调用对象中的方法和属性,需要再向下转型成对象的类型。
下面是方法的使用
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class ToArray {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(1);
c.add("b");
c.add(true);
c.add('v');
c.add(1.2);
Object[] obj = c.toArray();
//打印数组的三种方式
//1.利用Arrays常用类中的toString方法打印
System.out.println(Arrays.toString(obj));
//2.foreach循环打印
for (Object object : obj) {
System.out.print(object+"\t");
}
System.out.println();
//3.普通的for循环遍历打印
for (int i = 0;i<obj.length; i++) {
System.out.print(obj[i]+"\t");
}
}
}
输出结果为:
[1, b, true, v, 1.2]
1 b true v 1.2
1 b true v 1.2
当集合当中存入的是自定义对象时,需要注意上述的问题(转型问题)
import java.util.ArrayList;
import java.util.Collection;
class Dog{
private String food;
public Dog(String food){
this.food = food;
}
public void eat() {
System.out.println("吃"+food);
}
}
public class ToArray2 {
public static void main(String[] args) {
Collection c = new ArrayList();
Dog d1 = new Dog("shit");
Dog d2 = new Dog("shi");
c.add(d1);
c.add(d2);
Object[] obj = c.toArray();
for (int i = 0; i<obj.length; i++) {
Dog d = (Dog)obj[i];
//obj[i].eat(); //error 因为obj数组中都是Object,并不是Dog对象,所以需要向下转型
d.eat();
}
}
}
输出结果为
吃shit
吃shi
遍历集合
关于遍历集合,Collection接口中有两个方法,第一个是上面的toArray方法,将集合转成数组遍历。第二个是迭代器遍历,在Collection接口定义了一个方法叫iterator() 。(既然是Collection中的,那么所有的实现类都可以用此方法遍历)
ArrayList实现了Collection中的iterator方法(通过new一个内部类对象),在此内部类中主要有三个方法hasNext()、next、remove方法,也就是我们调用iterator方法时,它其实是新建了一个迭代器对象,此对象可以通过三个方法实现我们一些需求。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorTest {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("a");
c.add("b");
c.add("c");
c.add("d");
c.add("e");
Iterator it = c.iterator();
//hasNext判断是否有下一个元素
while (it.hasNext()) {
//next返回第i个元素,也就是遍历集合
System.out.println(it.next());
}
}
}
输出结果为
a
b
c
d
e
总结
关于集合,Collection接口作为List和set接口的父接口,其里面主要有上述几种方法,方法不难,重要的是这些方法都可以在List的实现类(ArrayList|、LinkedList、Vector)以及Set的实现类(hashSet、LinkedHashset、TreeSet)中使用。我们学习集合,就是先学习共性的方法,再了解具体实现类的特有方法。
吾尝终日而思矣,不如须臾之所学也!
希望自己以及大家少做一些无效思考,多学点东西,庸人自扰的状态不攻自破。