1、定义:集合是一种容器,专门用来存储对象
数组和集合的区别?
A: 长度区别
数组的长度固定
集合长度可变
B: 内容不同
数组存储的是同一种类型的元素
而集合可以存储不同类型的元素
C: 元素的数据类型问题
数组可以存储基本数据类型,也可以存储引用数据类型
集合只能存储引用类型
2、集合的继承体系结构
由于需求不同,Java 就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,
我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。
Collection
|--List
|--ArrayList
|--Vector
|--LinkedList
|--Set
|--HashSet
|--TreeSet
3、Collection 集合:集合体系的顶层接口
3.1 Collection 的功能概述:
1:添加功能
boolean add(Object obj): 添加一个元素
boolean addAll(Collection c): 添加一个集合的元素
2: 删除功能
void clear(): 移除所有元素
boolean remove(Object o): 移除一个元素
boolean removeAll(Collection c): 移除一个集合的元素 (是一个还是所有)
3: 判断功能
boolean contains(Object o):判断集合中是否包含指定的元素
boolean containsAll(Collection c):判断集合中是否包含指定的集合元素 (是一个还是所有)
boolean isEmpty():判断集合是否为空
4: 长度功能
int size(): 元素的个数
5: 交集功能
boolean retainAll(Collection c): 两个集合都有的元素
6:把集合转换为数组,可以实现集合的遍历
Object[] toArray()
- public class CollectionDemo {
- public static void main(String[] args) {
- // 测试不带All的方法
- // 创建集合对象
- // Collection c = new Collection(); //错误,因为接口不能实例化
- Collection c = new ArrayList();
- // boolean add(Object obj):添加一个元素
- // System.out.println("add:"+c.add("hello"));
- c.add("hello");
- c.add("world");
- c.add("java");
- // void clear():移除所有元素
- // c.clear();
- // boolean remove(Object o):移除一个元素
- // System.out.println("remove:" + c.remove("hello"));
- // System.out.println("remove:" + c.remove("javaee"));
- // boolean contains(Object o):判断集合中是否包含指定的元素
- // System.out.println("contains:"+c.contains("hello"));
- // System.out.println("contains:"+c.contains("android"));
- // boolean isEmpty():判断集合是否为空
- // System.out.println("isEmpty:"+c.isEmpty());
- //int size():元素的个数
- System.out.println("size:"+c.size());
- System.out.println("c:" + c);
- }
- }
- public class CollectionDemo2 {
- public static void main(String[] args) {
- // 创建集合1
- Collection c1 = new ArrayList();
- c1.add("abc1");
- c1.add("abc2");
- c1.add("abc3");
- c1.add("abc4");
- // 创建集合2
- Collection c2 = new ArrayList();
- // c2.add("abc1");
- // c2.add("abc2");
- // c2.add("abc3");
- // c2.add("abc4");
- c2.add("abc5");
- c2.add("abc6");
- c2.add("abc7");
- // boolean addAll(Collection c):添加一个集合的元素
- // System.out.println("addAll:" + c1.addAll(c2));
- //boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)
- //只要有一个元素被移除了,就返回true。
- //System.out.println("removeAll:"+c1.removeAll(c2));
- //boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)
- //只有包含所有的元素,才叫包含
- // System.out.println("containsAll:"+c1.containsAll(c2));
- //boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
- //假设有两个集合A,B。
- //A对B做交集,最终的结果保存在A中,B不变。
- //返回值表示的是A是否发生过改变。
- System.out.println("retainAll:"+c1.retainAll(c2));
- System.out.println("c1:" + c1);
- System.out.println("c2:" + c2);
- }
- }
- /*
- * 集合的遍历。其实就是依次获取集合中的每一个元素。
- *
- * Object[] toArray():把集合转成数组,可以实现集合的遍历
- */
- public class CollectionDemo3 {
- public static void main(String[] args) {
- // 创建集合对象
- Collection c = new ArrayList();
- // 添加元素
- c.add("hello"); // Object obj = "hello"; 向上转型
- c.add("world");
- c.add("java");
- // 遍历
- // Object[] toArray():把集合转成数组,可以实现集合的遍历
- Object[] objs = c.toArray();
- for (int x = 0; x < objs.length; x++) {
- // System.out.println(objs[x]);
- // 我知道元素是字符串,我在获取到元素的的同时,还想知道元素的长度。
- // System.out.println(objs[x] + "---" + objs[x].length());
- // 上面的实现不了,原因是Object中没有length()方法
- // 我们要想使用字符串的方法,就必须把元素还原成字符串
- // 向下转型
- String s = (String) objs[x];
- System.out.println(s + "---" + s.length());
- }
- }
- }
3.2、Iterator iterator(): 迭代器,集合的专用遍历方式
Object next(): 获取元素, 并移动到下一个位置。
NoSuchElementException:没有这样的元素,因为你已经找到最后了。
boolean hasNext(): 如果仍有元素可以迭代,则返回 true。
- public class IteratorDemo {
- public static void main(String[] args) {
- // 创建集合对象
- Collection c = new ArrayList();
- // 创建并添加元素
- // String s = "hello";
- // c.add(s);
- c.add("hello");
- c.add("world");
- c.add("java");
- // Iterator iterator():迭代器,集合的专用遍历方式
- Iterator it = c.iterator(); // 实际返回的肯定是子类对象,这里是多态
- while (it.hasNext()) {
- // System.out.println(it.next());
- String s = (String) it.next();
- System.out.println(s);
- }
- }
- }
3.3、在使用集合时需要注意一下几点:
1、集合中存储其实都是对象的地址。
2、集合中可以存储基本数值吗?不行,但是 jdk1.5 以后可以这么写,但是存储的还是对象 (基本数据类型包装类对象)。
3、存储时提升了 Object。取出时要使用元素的特有内容,必须向下转型。
4、List 集合:存储的元素是有序的(存储和取出的元素一致),带索引的,可重复的。
4.1、List 集合的特有功能:
A: 添加功能
void add(int index,Object element): 在指定位置添加元素
B: 获取功能
Object get(int index): 获取指定位置的元素
C: 列表迭代器
ListIterator listIterator():List 集合特有的迭代器
D: 删除功能
Object remove(int index):根据索引删除元素, 返回被删除的元素
E: 修改功能
Object set(int index,Object element): 根据索引修改元素,返回被修饰的元素
- public class ListDemo {
- public static void main(String[] args) {
- // 创建集合对象
- List list = new ArrayList();
- // 添加元素
- list.add("hello");
- list.add("world");
- list.add("java");
- // void add(int index,Object element):在指定位置添加元素
- // list.add(1, "android");//没有问题
- // IndexOutOfBoundsException
- // list.add(11, "javaee");//有问题
- // list.add(3, "javaee"); //没有问题
- // list.add(4, "javaee"); //有问题
- // Object get(int index):获取指定位置的元素
- // System.out.println("get:" + list.get(1));
- // IndexOutOfBoundsException
- // System.out.println("get:" + list.get(11));
- // Object remove(int index):根据索引删除元素,返回被删除的元素
- // System.out.println("remove:" + list.remove(1));
- // IndexOutOfBoundsException
- // System.out.println("remove:" + list.remove(11));
- // Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
- System.out.println("set:" + list.set(1, "javaee"));
- System.out.println("list:" + list);
- }
- }
- /*
- * List集合的特有遍历功能:
- * size()和get()方法结合使用
- */
- public class ListDemo2 {
- public static void main(String[] args) {
- // 创建集合对象
- List list = new ArrayList();
- // 添加元素
- list.add("hello");
- list.add("world");
- list.add("java");
- // Object get(int index):获取指定位置的元素
- // System.out.println(list.get(0));
- // System.out.println(list.get(1));
- // System.out.println(list.get(2));
- // IndexOutOfBoundsException
- // System.out.println(list.get(3));
- // 用循环改进
- // for (int x = 0; x < 3; x++) {
- // System.out.println(list.get(x));
- // }
- // 如果元素过多,数起来就比较麻烦,所以我们使用集合的一个长度功能:size()
- // 最终的遍历方式就是:size()和get()
- for (int x = 0; x < list.size(); x++) {
- // System.out.println(list.get(x));
- String s = (String) list.get(x);
- System.out.println(s);
- }
- }
- }
- /*
- * 列表迭代器:
- * ListIterator listIterator():List集合特有的迭代器
- * 该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法。
- *
- * 特有功能:
- * Object previous():获取上一个元素
- * boolean hasPrevious():判断是否有元素
- *
- * 注意:ListIterator可以实现逆向遍历,但是必须先正向遍历,才能逆向遍历,所以一般无意义,不使用。
- */
- public class ListIteratorDemo {
- public static void main(String[] args) {
- // 创建List集合对象
- List list = new ArrayList();
- list.add("hello");
- list.add("world");
- list.add("java");
- // ListIterator listIterator()
- 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);
- }
- System.out.println("-----------------");
- // 迭代器
- Iterator it = list.iterator();
- while (it.hasNext()) {
- String s = (String) it.next();
- System.out.println(s);
- }
- System.out.println("-----------------");
- }
- }
4.2、List 的子类特点
ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
List 有三个儿子,我们到底使用谁呢?
看需求 (情况)。
要安全吗?
要:Vector(即使要安全,也不用这个了,后面有替代的)
不要:ArrayList 或者 LinkedList
查询多:ArrayList
增删多:LinkedList
如果你什么都不懂,就用 ArrayList。
4.3、ArrayList 集合
- public class ArrayListDemo {
- public static void main(String[] args) {
- // 创建集合对象
- ArrayList array = new ArrayList();
- // 创建元素对象,并添加元素
- array.add("hello");
- array.add("world");
- array.add("java");
- // 遍历
- Iterator it = array.iterator();
- while (it.hasNext()) {
- String s = (String) it.next();
- System.out.println(s);
- }
- System.out.println("-----------");
- for (int x = 0; x < array.size(); x++) {
- String s = (String) array.get(x);
- System.out.println(s);
- }
- }
- }
4.4、Vector 集合
- /*
- * Vector的特有功能:
- * 1:添加功能
- * public void addElement(Object obj) 相当于add()
- * 2:获取功能
- * public Object elementAt(int index) 相当于get()
- * public Enumeration elements() 相当于Iterator iterator()
- * boolean hasMoreElements() hasNext()
- * Object nextElement() next()
- *
- * JDK升级的原因:
- * A:安全
- * B:效率
- * C:简化书写
- */
- public class VectorDemo {
- public static void main(String[] args) {
- // 创建集合对象
- Vector v = new Vector();
- // 添加功能
- v.addElement("hello");
- v.addElement("world");
- v.addElement("java");
- // 遍历
- for (int x = 0; x < v.size(); x++) {
- String s = (String) v.elementAt(x);
- System.out.println(s);
- }
- System.out.println("------------------");
- Enumeration en = v.elements(); // 返回的是实现类的对象
- while (en.hasMoreElements()) {
- String s = (String) en.nextElement();
- System.out.println(s);
- }
- }
- }
4.5、LinkedList 集合
- /*
- * LinkedList的特有功能:
- * A:添加功能
- * public void addFirst(Object e)给头部添加元素
- * public void addLast(Object e)给尾部添加元素
- * B:获取功能
- * public Object getFirst()获取头部元素
- * public Obejct getLast()获取尾部元素
- * C:删除功能
- * public Object removeFirst()获取头部元素,并删除头部元素
- * public Object removeLast()获取尾部元素,并删除尾部元素
- */
- public class LinkedListDemo {
- public static void main(String[] args) {
- // 创建集合对象
- LinkedList link = new LinkedList();
- // 添加元素
- link.add("hello");
- link.add("world");
- link.add("java");
- // public void addFirst(Object e)
- // link.addFirst("javaee");
- // public void addLast(Object e)
- // link.addLast("android");
- // public Object getFirst()
- // System.out.println("getFirst:" + link.getFirst());
- // public Obejct getLast()
- // System.out.println("getLast:" + link.getLast());
- // public Object removeFirst()
- System.out.println("removeFirst:" + link.removeFirst());
- // public Object removeLast()
- System.out.println("removeLast:" + link.removeLast());
- // 输出对象名
- System.out.println("link:" + link);
- }
- }
5、set 集合:存储的元素唯一,无序,方法和 Collection 一致。
- /*
- * Collection
- * |--List
- * 有序(存储顺序和取出顺序一致),可重复
- * |--Set
- * 无序(存储顺序和取出顺序不一致),唯一
- *
- * HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
- * 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,
- * 而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。
- */
- public class SetDemo {
- public static void main(String[] args) {
- // 创建集合对象
- Set set = new HashSet();
- // 创建并添加元素
- set.add("hello");
- set.add("java");
- set.add("world");
- set.add("java");
- set.add("world");
- // 增强for
- for (String s : set) {
- System.out.println(s);
- }
- }
- }
5.1、HashSet 集合:哈希表结构,不同步,保证元素唯一性的方式依赖于:hashCode(),equals() 方法。查询速度快。
注意:1、什么是哈希表呢?
哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会根据这些对象的特有数据结合相应的算法,算法这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组,即就是哈希表。
2、保证元素唯一的原理
当给哈希表中存放元素时,需要根据元素的特有数据结合相应的算法,这个算法其实就是 Object 中的 hashCode 方法。由于任何对象都是 Object 类的子类,所以任何对象有拥有这个方法。即就是在给哈希表中存放对象时,会调用对象的 hashCode 方法,算出对象在表中的存放位置,这里需要注意,如果两个对象 hashCode 方法算出结果一样,这样现象称为哈希冲突,这时会调用对象的 equals 方法,比较这两个对象是不是同一个对象,如果 equals 方法返回的是 true,那么就不会把第二个对象存放在哈希表中,如果返回的是 false,就会把这个值存放在哈希表中。
总结:保证元素的唯一,其实就是根据对象的 hashCode 和 equals 方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写 hashCode 和 equals 方法建立属于当前对象的比较方式。
- /*
- * HashSet:保证元素唯一的原理
- * A:底层数据结构是哈希表(是一个元素为链表的数组)
- * B:哈希表底层依赖两个方法:hashCode()和equals()
- * 步骤:
- * 首先比较哈希值
- * 如果相同,继续走,比较地址值或者走equals()
- * 如果不同,就直接添加到集合中
- * 按照方法的步骤来说:
- * 先看hashCode()值是否相同
- * 相同:继续走equals()方法
- * 返回true:说明元素重复,就不添加
- * 返回false:说明元素不重复,就添加到集合
- * 不同:就直接把元素添加到集合
- * 如果类没有重写这两个方法,默认使用的Object()。一般来说不同相同。
- * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
- */
- public class HashSetDemo {
- public static void main(String[] args) {
- // 创建集合对象
- HashSet hs = new HashSet();
- // 创建并添加元素
- hs.add("hello");
- hs.add("world");
- hs.add("java");
- hs.add("world");
- // 遍历集合
- for (String s : hs) {
- System.out.println(s);
- }
- }
- }
5.2、TreeSet 集合:保证元素唯一,并能够对元素按照某种规则(自然排序和比较器排序)进行排序。
注意: 1、如何保证元素唯一性的呢?
使用的对象比较方法的结果是否为 0,是 0,视为相同元素不存。
2、排序原理
A: 自然排序 (元素具备比较性)
让元素所属的类实现自然排序接口 Comparable
B: 比较器排序 (集合具备比较性)
让集合的构造方法接收一个比较器接口的子类对象 Comparator
自然排序:
- /*
- * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口
- */
- public class Student implements Comparable {
- private String name;
- private int age;
- public Student() {
- super();
- }
- public Student(String name, int age) {
- super();
- 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;
- }
- @Override
- public int compareTo(Student s) {
- // 主要条件 姓名的长度
- int num = this.name.length() - s.name.length();
- // 姓名的长度相同,不代表姓名的内容相同
- int num2 = num == 0 ? this.name.compareTo(s.name) : num;
- // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
- int num3 = num2 == 0 ? this.age - s.age : num2;
- return num3;
- }
- }
- /*
- * TreeSet:能够对元素按照某种规则进行排序。
- * 排序有两种方式
- * A:自然排序
- * B:比较器排序
- *
- * TreeSet集合的特点:排序和唯一
- *
- * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。
- */
- public class TreeSetDemo {
- public static void main(String[] args) {
- // 创建集合对象
- // 自然顺序进行排序
- TreeSet ts = new TreeSet();
- // 创建元素并添加
- // 20,18,23,22,17,24,19,18,24
- ts.add(20);
- ts.add(18);
- ts.add(23);
- ts.add(22);
- ts.add(17);
- ts.add(24);
- ts.add(19);
- ts.add(18);
- ts.add(24);
- // 遍历
- for (Integer i : ts) {
- System.out.println(i);
- }
- }
- }
比较器排序
- public class Student {
- private String name;
- private int age;
- public Student() {
- super();
- }
- public Student(String name, int age) {
- super();
- 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;
- }
- }
- /*
- * 需求:请按照姓名的长度排序
- *
- * TreeSet集合保证元素排序和唯一性的原理
- * 唯一性:是根据比较的返回是否是0来决定。
- * 排序:
- * A:自然排序(元素具备比较性)
- * 让元素所属的类实现自然排序接口 Comparable
- * B:比较器排序(集合具备比较性)
- * 让集合的构造方法接收一个比较器接口的子类对象 Comparator
- */
- public class TreeSetDemo {
- public static void main(String[] args) {
- // 创建集合对象
- // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
- // public TreeSet(Comparator comparator) //比较器排序
- // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
- // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
- // 而匿名内部类就可以实现这个东西,匿名内部类和下面的MyComparator效果一样
- TreeSet ts = new TreeSet(new Comparator() {
- @Override
- public int compare(Student s1, Student s2) {
- // 姓名长度
- int num = s1.getName().length() - s2.getName().length();
- // 姓名内容
- int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
- : num;
- // 年龄
- int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
- return num3;
- }
- });
- // 创建元素
- Student s1 = new Student("linqingxia", 27);
- Student s2 = new Student("zhangguorong", 29);
- Student s3 = new Student("wanglihong", 23);
- Student s4 = new Student("linqingxia", 27);
- Student s5 = new Student("liushishi", 22);
- Student s6 = new Student("wuqilong", 40);
- Student s7 = new Student("fengqingy", 22);
- Student s8 = new Student("linqingxia", 29);
- // 添加元素
- ts.add(s1);
- ts.add(s2);
- ts.add(s3);
- ts.add(s4);
- ts.add(s5);
- ts.add(s6);
- ts.add(s7);
- ts.add(s8);
- // 遍历
- for (Student s : ts) {
- System.out.println(s.getName() + "---" + s.getAge());
- }
- }
- }
- //或者去掉匿名内部类。增加一个MyComparator类
public class MyComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
// int num = this.name.length() - s.name.length();
// this -- s1
// s -- s2
// 姓名长度
int num = s1.getName().length() - s2.getName().length();
// 姓名内容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
// 年龄
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
}
5.3、LinkedHashSet:HashSet 的一个子类,底层数据结构由哈希表和链表组成保证元素的唯一和有序。
哈希表保证元素的唯一性。
链表保证元素有序。(存储和取出是一致)
- /*
- * LinkedHashSet:底层数据结构由哈希表和链表组成。
- * 哈希表保证元素的唯一性。
- * 链表保证元素有序。(存储和取出是一致)
- */
- public class LinkedHashSetDemo {
- public static void main(String[] args) {
- // 创建集合对象
- LinkedHashSet hs = new LinkedHashSet();
- // 创建并添加元素
- hs.add("hello");
- hs.add("world");
- hs.add("java");
- hs.add("world");
- hs.add("java");
- // 遍历
- for (String s : hs) {
- System.out.println(s);
- }
- }
- }
6、集合总结
Collection
|--List 有序, 可重复
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高
|--Set 无序, 唯一
|--HashSet
底层数据结构是哈希表。
如何保证元素唯一性的呢?
依赖两个方法:hashCode() 和 equals()
开发中自动生成这两个方法即可
|--LinkedHashSet
底层数据结构是链表和哈希表
由链表保证元素有序
由哈希表保证元素唯一
|--TreeSet
底层数据结构是红黑树。
如何保证元素排序的呢?
自然排序
比较器排序
如何保证元素唯一性的呢?
根据比较的返回值是否是 0 来决定
7、针对 Collection 集合我们到底使用谁呢
唯一吗?
是:Set
排序吗?
是:TreeSet
否:HashSet
如果你知道是 Set,但是不知道是哪个 Set,就用 HashSet。
否:List
要安全吗?
是:Vector
否:ArrayList 或者 LinkedList
查询多:ArrayList
增删多:LinkedList
如果你知道是 List,但是不知道是哪个 List,就用 ArrayList。
如果你知道是 Collection 集合,但是不知道使用谁,就用 ArrayList。
如果你知道用集合,就用 ArrayList。
8、在集合中常见的数据结构
ArrayXxx: 底层数据结构是数组,查询快,增删慢
LinkedXxx: 底层数据结构是链表,查询慢,增删快
HashXxx: 底层数据结构是哈希表。依赖两个方法:hashCode() 和 equals()
TreeXxx: 底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
来源: http://www.cnblogs.com/flei/p/6612760.html