week06_day01
其实主要分为两部分:Collection和Map
·······················································································································································································································
正式讲课之前,我们先来搞明白三个小问题:
-
为什么需要集合类?
很多情况下,我们需要对一组对象进行操作。而且很可能事先并不知道到底有多少个对象。为了解决这个问题呢,Java 就提供了集合类供我们使用。 -
集合类的特点
a. 只能存储引用数据类型
b. 可以自动地调整自己的大小 -
数组和集合类都是容器,它们有何不同?
a. 数组可以存储基本数据类型的数据,集合不可以。
b. 数组的长度是固定的,集合可以自动调整自己的大小。
c. 数组的效率高,相对来说集合效率比较低。
d. 数组没有API,集合有丰富的API。
在实际开发中,更经常用的是集合,能用集合做不要用数组。因为不用自己去写API,而且这样你写的代码别人能看懂。
Collection就是一个容器,里面放你的元素。
Collection不存在次序的概念,也就不存在index,也就不存在头删尾删
正确的创建Project、Moudle的方式:
- File-----New-----Project,写入project创建路径,此时一个Project就创建好了,创建好后删除Project下的src目录。
- 在Project中点击:File-----New-----Moudle
·······················································································································································································································
Collection概念
Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
Collection 的含义大家应该清楚了,那么它应该包含哪些 API 呢?
Collection中的equals方法和hashCode方法都应当被重写,因为我们应当比较的是一个Collection中的元素个数以及元素值是否相等甚至元素次序(如LinkedList)是否相等,而不应该比较这两个集合是否是同一个集合(不应比较这两个集合指向的内存地址是否相同)。既然equals方法重写了,hashCode方法也应当被重写。
特点:
a. 可以自动地调整自己的大小
b. 只能存储引用数据类型
API:
- 增:
boolean add(E e)
boolean addAll(Collection c) - 删:
void clear()
boolean remove(Object o)
boolean removeAll(Collection c)
boolean retainAll(Collection c) //retain 保留 - 查:
boolean contains(Object o)
boolean containsAll(Collection c) - 获取集合的属性:
boolean isEmpty()
int size() - 遍历:
Object[] toArray()
Iterator iterator()
public class Demo01 {
public static void main(String[] args) {
Collection c = new ArrayList(10);
for (int i = 0; i < 30; i++) {
c.add(i);
}
//Collection重写了toString方法,打印出来的是数组的值,而不是地址
System.out.println(c);
System.out.println(c.size());
}
}
思考一下,我们说集合没法装基本数据类型的数据,那为什么我们把int类型的数据装进去了呢?
因为自动装箱拆箱。
提供基本数据类型是为了提高性能的,因为数据很简单。但在java中奉行一种原理:一切数据皆对象。所以提供了基本数据类型对应的引用数据类型。
自动装箱:基本数据类型转换成对应的引用数据类型
自动拆箱:引用数据类型转换成对应的基本数据类型
public class Demo02 {
public static void main(String[] args) {
/*int intValue = 10;
Integer integer = Integer.valueOf(intValue);
int i = integer.intValue();*/
//我们只需按照下面这样写就行了
//下面写的这三行代码会在编译时自动编译成上面三行代码
int intValue = 10;
// 自动装箱
Integer integer = intValue;
// 自动拆性
int i = integer;
}
}
·······················································································································································································································
()中的类型和Collection无关的API:
- boolean add(E e)
会发现ArrayList允许重复元素,HashSet不允许重复元素。这就是多态。增加成功返回true,失败返回false。 - boolean remove(Object o)
ArrayList只会删除第一个值为o的元素。删除成功返回true,失败返回false。 - void clear()
- boolean contains(Object o)
包含值为0的元素成功返回true,失败返回false。 - boolean isEmpty()
为空成功返回true,失败返回false。 - int size()
返回Collection对象容纳的元素个数。
public class Demo03 {
public static void main(String[] args) {
// boolean add(E e)
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
System.out.println(c);
System.out.println(c.add("java")); // ?
System.out.println(c);
Collection c2 = new HashSet();
System.out.println(c2.add("hello"));
System.out.println(c2.add("world"));
System.out.println(c2.add("java"));
System.out.println(c2);
System.out.println(c2.add("java"));
System.out.println(c2);
// boolean remove(Object o)
System.out.println(c.remove("java")); // true
System.out.println(c);
System.out.println(c.remove("database")); // false
System.out.println(c);
c.add("javase");
c.add("java");
System.out.println(c.remove("java"));
System.out.println(c);
// int size() , void clear()
System.out.println(c.size());
c.clear();
System.out.println(c.size());
// boolean empty() 判空:判断集合中是否有元素
//在null上看它的属性,调用它的方法,都会报空指针异常
//如何判断一个对象是否为null? if(c == null) 即可
c = null;
System.out.println(c.isEmpty()); // ?
c.clear();
System.out.println(c.isEmpty());
// boolean contains(Object o)
System.out.println(c.contains("java"));
System.out.println(c.contains("database"));
}
}
·······················································································································································································································
()中的类型和Collection有关的API:
- boolean addAll(Collection c)
如果集合发生了改变返回true, 否则返回false - boolean removeAll(Collection c)
如果集合发生了改变返回true, 否则返回false - boolean retainAll(Collection c)
如果集合发生了改变返回true, 否则返回false - boolean containsAll(Collection c)
如果包含集合c中所有的元素返回true, 否则返回false
例子:假如ArrayList C的值为:bejing、beijing、beijing、wuhan、shenzhen。ArrayList C2的值为:beijing、wuhan、shenzhen。
C2.containsAll(C )依然会返回true
迷惑的时候想一想如果是你实现底层的操作,你会怎么做:从C中取出一个一个的元素,看在C2中是否有和它相同的元素。
·······················································································································································································································
- Object[] toArray()
将集合转换成数组
小结:
数组长度:arr.length 属性
字符串长度:s.length() 方法
集合大小:c.size() 方法
public class Demo05 {
public static void main(String[] args) {
Collection list = new ArrayList();
list.add("hello");
list.add("world");
list.add("java");
Object[] array = list.toArray();
for (int i = 0; i < array.length; i++) {
String s = (String) array[i];
if (s.equals("java")) {
array[i] = "javaSE";
}
}
//会发现改变了array的数据,但并没有改变list的数据
System.out.println(Arrays.toString(array));
System.out.println(list);
}
}
但实际开发中,我们更希望你对array进行操作,让这个操作影响到原本的集合
如何做呢?用Iterator iterator()
·······················································································································································································································
- Iterator iterator()
迭代器,集合的专用遍历方式 - Iterable接口
Iterator iterator() - Iterator接口
它是对集合进行迭代的迭代器
依赖于集合对象存在
boolean hasNext()
E next()
void remove()
public class Demo06 {
public static void main(String[] args) {
Collection list = new ArrayList();
list.add("hello");
list.add("java");
list.add("world");
list.add("java");
list.add("java");
//Iterator iterator()方法会实实在在的改变集合list中的元素
Iterator it = list.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
// void remove() 删除最近返回的元素
Iterator it2 = list.iterator();
while (it2.hasNext()) {
String s = (String) it2.next();
if ("java".equals(s)) {
it2.remove();
}
}
System.out.println(list);
//但其实刚刚讲过的collection中的方法 boolean remove(Object o)也能删除
//但是只会删除第一个值为o的元素。删除成功返回true,失败返回false。
list.remove("java");
System.out.println(list);
//迭代器+list.remove(s); 可以删除"java"吗? 不可以
//用集合的API修改集合的结构,所有的迭代器会失效
Iterator it3 = list.iterator();
while (it3.hasNext()) {
String s = (String) it3.next(); //ConcurrentModificationException并发修改异常
if ("java".equals(s)) {
list.remove(s);
}
}
System.out.println(list);
}
}
·······················································································································································································································
注意事项:
a. 用集合的API修改集合的结构,所有的迭代器会失效
用迭代器的API修改集合的结构,其它迭代器会失效
b. 用迭代器遍历集合的时候,不要使用while循环,可以使用for循环,最好使用foreach循环
public class Demo07 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("hello");
c.add("java");
c.add("world");
c.add("java");
c.add("java");
Iterator it1 = c.iterator();
while (it1.hasNext()) {
String s = (String) it1.next();
if ("java".equals(s)) it1.remove();
}
System.out.println(c);
// ... 茫茫多代码
Iterator it2 = c.iterator();
while (it2.hasNext()) {
String s = (String) it2.next();
if ("hello".equals(s)) it2.remove();
}
System.out.println(c);
}
}
上面这段代码,两个迭代器it1和it2对c遍历,这样写没有问题。
但是假如在用it2遍历时,不小心把it2.remove();写成了it1.remove();,那么就会报错:ConcurrentModificationException 并发修改异常。也就是说,你在用一个迭代器遍历时,只能访问这个迭代器的变量。
这就是对用迭代器的API修改集合的结构,其它迭代器会失效这句话的解释。
所以说:用迭代器遍历集合的时候,不要使用while循环,可以使用for循环,最好使用foreach循环。因为for循环中的变量只在本循环体内起作用。
如果我改成了for循环,后面就不可能用到it1了。
public class Demo07 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("hello");
c.add("java");
c.add("world");
c.add("java");
c.add("java");
for(Iterator it1 = c.iterator();it3.hasNext();){
String s = (String) it3.next();
System.out.println(s);
}
System.out.println(c);
// ... 茫茫多代码
for (Iterator it4 = c.iterator();it4.hasNext();) {
String s = (String) it4.next();
if(s.equals("java")) it4.remove();
}
System.out.println(c);
}
}
·······················································································································································································································
下面来看一看Iterator的实现原理:
推荐阅读