一、Set集合,其主要实现类有HashSet、TreeSet。存放对象的引用,不允许有重复对象。
通过java的equals()方法判别。如果有特殊需求须重载equals()方法。
1、HashSet(),调用对象的hashCode()方法,获得哈希码,然后再集合中计算存放对象的位置。通过比较哈希码与equals()方法来判别是否重复。所以,重载了equals()方法同时也要重载hashCode()方法。
2、TreeSet(),继承ShortedSet接口,能够对集合中对象排序。默认排序方式是自然排序,但该方式只能对实现了Comparable接口的对象排序,java中对Integer、Byte、Double、Character、String等数值型和字符型对象都实现了该接口。
如果有特殊排序,须重载该接口下的compareTo()方法或通过Comparator接口的实现类构造集合。
二、List集合,其主要实现类有LinkedList、ArrayList,前者实现了链表结构,后者可代表大小可变的数组。List的特点是能够以线性方式储蓄对象,并允许存放重复对象。List能够利用Collections类的静态方法sort排序。sort(List list)自然排序;sort(List listm,Comparator comparator)客户化排序。
三、Map集合,其主要实现类有HashMap、TreeMap。Map对值没有唯一性要求,对健要求唯一,如果加入已有的健,原有的值对象将被覆盖。HashMap类按照哈希算法来存取键对象,可以重载equals()、hashCode()方法来比较键,但是两者必须一致。TreeMap,可自然排序,也可通过传递Comparator的实现类构造TreeMap。
(1)集合的由来?
我们学习的是Java – 面向对象 – 操作很多对象 – 存储 – 容器(数组和StringBuffer) – 数组
而数组的长度固定,所以不适合做变化的需求,Java就提供了集合供我们使用。
(2)集合和数组的区别?
A:长度区别
数组固定
集合可变
B:内容区别
数组可以是基本类型,也可以是引用类型
集合只能是引用类型
C:元素内容
数组只能存储同一种类型
集合可以存储不同类型(其实集合一般存储的也是同一种类型)
(3)集合的继承体系结构?
由于需求不同,Java就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,
我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。
Collection:
|–List 有序(元素存入集合的顺序和取出的顺序一致),元素都有索引,而且元素可以重复。
|–ArrayList
|–Vector
|–LinkedList
|–Set 无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
|–HashSet
|–TreeSet
Collection的功能:
A:添加功能
boolean add(Object obj):向集合中添加一个元素
boolean addAll(Collection c):向集合中添加一个集合的元素
B:删除功能
void clear():删除集合中的所有元素
boolean remove(Object obj):向集合中删除指定的元素
booleanremoveAll(Collection c):向集合中删除一个指定的集合元素
C:判断功能
boolean isEmpty():判断集合是否为空
boolean contains(Object obj):判断集合中是否存在指定的元素
boolean containsAll(Collection c):判断集合中是否存在指定的元素
D:遍历功能
Iterator iterator():就是用来获取集合中每一个元素
E:长度功能
int size():获取集合中的元素个数
F:交集功能
boolean retainAll(Collection c):判断两个集合中是否有相同的元素
G:转换功能
Object[] toArray():把集合变成数组
小练习:遍历集合中的元素,判断是否存在元素“hello”。
/* * 请遍历集合:也就是获取到集合中的每一个元素。 * 判断集合中是否存在"hello"这个元素. * 注意: * 在往集合中添加元素的时候,集合默认接收的是Object类型。 * 也就是说你开始存储字符串的时候,其实做了一个向上转型的操作。 * * 在获取元素的时候,默认还是以Object类型的返回。 * 但是,你明明知道这应该是String类型。 * 所以,如果你想使用String类型的特殊功能,就必须做向下转型。 * 如果仅仅是为了看结果,就不用。因为通过多态的形式,最终输出语句调用的是String类的toString() */
public class CollectionDemo2 {
public static void main(String[] args) {
flag=true; //元素标记符,
Collection c = new ArrayList(); //创建集合对象
// 添加元素
c.add("hello"); // String -- Object
c.add("world");
c.add("java");
// 直接使用判断功能
// System.out.println("contains:"+c.contains("hello"));
// System.out.println("c:" + c);//若存在,则会输出true
// 遍历集合,获取到每一个元素,然后判断这个元素是否是hello
// Object[] toArray():把集合变成数组。
Object[] objs = c.toArray();
for (int x = 0; x < objs.length; x++) {
//将Object类型的数组强制转换为String类型
String s = (String) objs[x];
if(s.equals("hello")){
flag=true; //如果存在,就输出真,否则输出假
}else{
flag=false;
}
System.out.println(s + "***" + s.length()+"***"+flag);
}
}
}
小练习:用迭代器遍历集合中的元素。
/* * 成员方法: * Object next():获取元素,并自动移动到下一个位置等待获取。 * boolean hasNext():判断迭代器中是否还有元素。 * NoSuchElementException:没有这样的元素异常。你已经获取到元素末尾了,你还要获取,已经没有元素了。所以报错了。 */
public class IteratorDemo {
public static void main(String[] args) {
// 创建对象
Collection c = new ArrayList();
// 添加元素
c.add("hello");
c.add("world");
c.add("java");
// 方式1
// Object[] objs = c.toArray();
// for (int x = 0; x < objs.length; x++) {
// String s = (String) objs[x];
// System.out.println(s);
// }// 方式2
// Iterator iterator():就是用来获取集合中每一个元素。
// 通过集合对象获取迭代器对象
Iterator it = c.iterator();// 这是返回的是Iterator的子类对象,多态
while (it.hasNext()) {
// System.out.println(it.next());
String s = (String) it.next();
System.out.println(s);
} } }
list接口
List本身是Collection接口的子接口,具备Collection的所有方法。现在学习list体系特有的共性方法,查阅方法发现List的特有方法都有索引,这是该集合最大的特点。
1)List特有功能:
A:添加功能
void add(int index,Object obj):在指定位置添加元素
B:删除功能
Object remove(int index):根据指定索引删除元素,并把删除的元素返回
C:修改功能
Object set(int index,Object obj):把指定索引位置的元素修改为指定的值,返回修改前的值。
D:获取功能
Object get(int index):返回指定元素在集合中第一次出现的索引
int indexOf(Object obj):获取指定位置的元素,如果该元素不存在返回-1;所以,通过-1,可以判断一个元素是否存在 int lastIndexOf(Object obj):反向索引指定元素的位置
List subList(start,end):获取子列表
ListIterator listIterator():列表迭代器(List集合特有的迭代器)
2)List的遍历方式
A:Iterator 迭代器
B:ListIterator迭代器(了解)
C:普通for(和list的get方法使用)
3)ListIterator迭代器
A:是Iterator的子接口。
B:有自己的特有功能,可以逆向遍历数据,但是需要先正向遍历。一般不用。
/* * ListIterator listIterator():列表迭代器 * * boolean hasNext() * Object next() * * 特有功能: * boolean hasPrevious() * Object previous() * * 虽然,可以逆向遍历,但是,要求先正向遍历,然后才能逆向遍历。 */
public class ListDemo5 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
// 遍历
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
System.out.println(s);
}
System.out.println("----------------");
// System.out.println(lit.previous());
// System.out.println(lit.previous());
// System.out.println(lit.previous());
// // NoSuchElementException
// System.out.println(lit.previous());
// 逆向遍历
while (lit.hasPrevious()) {
String s = (String) lit.previous();
System.out.println(s);
}
}
}
4)面试题:并发修改异常
A:并发修改异常的产生原因:用迭代器遍历集合,用集合去操作集合。
B:解决方案:a:使用集合操作。
b:使用列表迭代器操作。
代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/* * ListIterator listIterator():列表迭代器 * * public interface ListIterator extends Iterator * * 面试题:ConcurrentModificationException:并发修改异常。 * 这是个什么异常,怎么产生的,怎么解决的? * 怎么产生: * 当我们通过迭代器迭代元素的过程中,又通过集合去添加了元素。这种情况是不允许的。 * 因为迭代器是依赖于集合存在的,如果集合发生改变,迭代器也应该相应的发生改变。 * 而我们目前看到的确实,迭代器没变,集合变了。所以,报出了一个并发修改异常。 * * 注意问题:通过迭代器遍历集合的时候,是不能通过集合去操作(添加,删除)。 * 那么,我们可不可以这样理解呢? * A:全部通过迭代器操作:元素是添加到刚遍历的那个元素后面。 * 通过迭代器迭代的时候,可以通过迭代器对集合进行操作。 * B:全部通过集合操作:元素是添加到最后的。 * 通过集合普通for遍历的时候,可以通过集合去操作。 */
public class ListDemo4 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
// 添加元素
list.add("hello");
list.add("world");
list.add("java");
// 迭代器
// Iterator it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// System.out.println(s);
// }
// System.out.println("-----------");
// 需求:请遍历集合,判断其中是否有"hello"这个元素,如果有,就再添加一个元素:"IOS"
// Iterator it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// if ("hello".equals(s)) {
// list.add("IOS");
// // it = list.iterator();//这样从原理是可以解决的,但是它会引起另外一个问题。
// }
// }
// System.out.println("list:" + list);
// System.out.println("-----------");
// 完全通过集合实现
// for (int x = 0; x < list.size(); x++) {
// String s = (String) list.get(x);
// if ("hello".equals(s)) {
// list.add("IOS");
// }
// }
// System.out.println("list:"+list);
// System.out.println("-----------");
// 遍历
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
if ("hello".equals(s)) {
lit.add("IOS");
}
}
System.out.println("list:" + list);
}
}
5)List:
|–ArrayList:底层数据结构是数组,线程不安全(即不同步),它的出现替代了Vector,增删的效率很慢,但是查询的效率很高。
|–Vector:底层数据结构是数组,线程安全,无论增删还是查询都非常慢。
|–LinkedList:底层是链表,线程不安全,对元素的增删的操作效率很高,查询效率低。
ArrayList的小练习:
需求:我现在用ArrayList存储多个字符串元素。
比如说数据如下:hello,world,java,hello,.net,java,php,IOS,java,android
我要求你写程序,实现去除重复元素。也就是说结果是:hello,world,java,.net,php,IOS,android
5)List:
|--ArrayList:底层数据结构是数组,线程不安全(即不同步),它的出现替代了Vector,增删的效率很慢,但是查询的效率很高。
|--Vector:底层数据结构是数组,线程安全,无论增删还是查询都非常慢。
|--LinkedList:底层是链表,线程不安全,对元素的增删的操作效率很高,查询效率低。
ArrayList的小练习:
需求:我现在用ArrayList存储多个字符串元素。
比如说数据如下:hello,world,java,hello,.net,java,php,IOS,java,android
我要求你写程序,实现去除重复元素。也就是说结果是:hello,world,java,.net,php,IOS,android
方法二:
/* * 在同一个集合上操作:双层循环实现 * 第一方式没有问题,第二种可能有问题。 * 但是,第二种的问题也是可以解决的? * 怎么解决呢? * 把每次删除掉元素的那个位置,在回来比较一次即可。 */
public class ArrayListTest2 {
public static void main(String[] args) {
// 创建旧集合,并添加元素
ArrayList array = new ArrayList();
array.add("hello");
array.add("world");
array.add("java");
array.add("hello");
array.add(".net");
array.add("java");
array.add("java");
array.add("java");
array.add("php");
array.add("IOS");
array.add("java");
array.add("android");
// 这下面的代码和选择排序类似。理解即可。最好通过断点看过程。
for (int x = 0; x < array.size() - 1; x++) {
for (int y = x + 1; y < array.size(); y++) {
if (array.get(y).equals(array.get(x))) {
array.remove(y);
y--;
}
}
}
// 遍历
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}
下面是一个面试题:用ArrayList存储学生,如何去除重复的元素?
“`
import java.util.ArrayList;
import java.util.Iterator;
/*
* ArrayList如果存储的是学生,那么,怎么去除重复元素呢?
* 问题:如何知道学生是重复的。
* 需求:如果学生的姓名和年龄相同,我就认为是同一个学生。即重复值。
*
* 通过简单分析,我们估计是判断那里出问题了。
* 怎么办呢?
* 看判断的方法。
* 而我们又知道,判断的方法是API提供的。不是自己的写的。
* 看源码,看底层到底怎么实现的。
* 通过看源码,我们发现,底层依赖的是equals()。
* 由于学生类中,我们并没有equals()方法,所以,默认用的是Object的方法。
* 而Object类的方法,默认比较的是地址值。
* 由于学生对象都是new出来的,地址值肯定不一样,所以从这个角度考虑结论是正确的。
* 但是不符合我们的需求。
* 肿么办?
* 重写equals(),让他按照我们的需要来比较。
*/
//标准学生类
public class Student {
//定义两个成员变量
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//重写equals方法
@Override
public boolean equals(Object obj) {
// 提高效率
if (this == obj) {
return true;
}
// 提高健壮性
if (!(obj instanceof Student)) {
return false;
}
// 向下转换
Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
}
}
public class ArrayListTest3 {
public static void main(String[] args) {
ArrayList array = new ArrayList();
Student s1 = new Student("301宿舍--笨笨", 22);
Student s2 = new Student("301宿舍--姗姗", 23);
Student s3 = new Student("301宿舍--姗姗", 30);
Student s4 = new Student("301宿舍--红红", 20);
Student s5 = new Student("301宿舍--红红", 20);
Student s6 = new Student("301宿舍--蛋蛋", 24);
Student s7 = new Student("301宿舍--媛媛", 22);
Student s8 = new Student("301宿舍--歪歪", 23);
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
// 创建新集合
ArrayList array2 = new ArrayList();
// 遍历旧集合,获取到每一个元素
Iterator it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
// 在新集合中判断,看是否存在这个元素
if (!array2.contains(s)) {
// 如果s不再array2中存在,就添加
array2.add(s);
}
}
// array2就是没有重复元素的集合。
// 遍历array2
for (int x = 0; x < array2.size(); x++) {
Student s = (Student) array2.get(x);
System.out.println(s.getName() + "***" + s.getAge());
}
}
}
“`