java基础--集合

来源:互联网 发布:三个阿道夫知乎 编辑:程序博客网 时间:2024/06/06 01:17



一、集合(Collection集合)

(1)集合的由来?

我们学习的是Java -- 面向对象 -- 操作很多对象 -- 存储 -- 容器(数组和StringBuffer) -- 数组

而数组的长度固定,所以不适合做变化的需求,Java就提供了集合供我们使用。

(2)集合和数组的区别?

A:长度区别

数组固定

集合可变

B:内容区别

数组可以是基本类型,也可以是引用类型

集合只能是引用类型

C:元素内容

数组只能存储同一种类型

集合可以存储不同类型(其实集合一般存储的也是同一种类型)

(3)集合的继承体系结构?

由于需求不同,Java就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,

我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。


(4)Collection的功能概述

A:添加功能

boolean add(Object obj):添加一个元素

boolean addAll(Collection c):添加一个集合的元素

B:删除功能

void clear():移除所有元素

boolean remove(Object o):移除一个元素

boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)

C:判断功能

boolean contains(Object o):判断集合中是否包含指定的元素

boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)

boolean isEmpty():判断集合是否为空

D:获取功能

Iterator<E> iterator()(重点)

E:长度功能

int size():元素的个数

F:交集(了解)

boolean retainAll(Collection c)   返回值表示的是调用者集合是否发生过改变

G:把集合转数组(了解)

Object[] toArray():把集合转成数组,可以实现集合的遍历

(5)Collection集合的遍历

A:把集合转数组(了解)

B:迭代器(集合专用方式)

C;代码演示

public class Test {public static void main(String[] args) {// 创建集合对象Collection c = new ArrayList();//添加元素c.add("hello");c.add("world");c.add("java");//遍历第一种方法//把集合转为数组Object[] array = c.toArray();//遍历数组for (int i = 0; i < array.length; i++) {Object object = array[i];System.out.println(object);}System.out.println("-----------------");//遍历第二种方法//用迭代器方法Iterator  i = c.iterator();  //获取迭代器while(i.hasNext()){String s = (String)i.next();System.out.println(s);}}}

(7)Collection集合的遍历步骤

集合的操作步骤:

A:创建集合对象

B:创建元素对象

C:把元素添加到集合

D:遍历集合


二、集合(List集合)

(1)List是Collection的子接口

特点:有序(存储顺序和取出顺序一致),可重复。

(2)List的特有功能:

A:添加功能

void add(int index,Object element):在指定位置添加元素

B:删除功能

Object remove(int index):根据索引删除元素,返回被删除的元素

C:获取功能

Object get(int index):获取指定位置的元素

D:迭代器功能

ListIterator listIterator():List集合特有的迭代器

E:修改功能

Object set(int index,Object element):根据索引修改元素,返回被修饰的元素

(3)List集合的特有遍历功能

A:由size()和get()结合。

B:代码演示

public class Test {public static void main(String[] args) {// 创建集合对象List list = new ArrayList();// 添加元素list.add("hello");list.add("world");list.add("java");//循环遍历for (int x = 0; x < list.size(); x++) {String s = (String) list.get(x);System.out.println(s);}}}

(4)列表迭代器的特有功能;(了解)

可以逆向遍历,但是要先正向遍历,所以无意义,基本不使用。

(5)并发修改异常

A:出现的现象

迭代器遍历集合,集合修改集合元素

// 创建List集合对象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();if ("world".equals(s)) {list.add("javaee"); //添加不了会出现并发修改异常}}

B:原因

迭代器是依赖于集合的,而集合的改变迭代器并不知道。

C:解决方案

a:迭代器遍历,迭代器修改(ListIterator)

// 方式1:迭代器迭代元素,迭代器修改元素// 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIteratorListIterator lit = list.listIterator();while (lit.hasNext()) {String s = (String) lit.next();if ("world".equals(s)) {lit.add("javaee");}}

b:集合遍历,集合修改(size()和get())

 // 方式2:集合遍历元素,集合修改元素(普通for) for (int x = 0; x < list.size(); x++) { String s = (String) list.get(x); if ("world".equals(s)) { list.add("javaee"); } }

(6)常见数据结构

A:栈 :先进后出

B:队列: 先进先出

C:数组: 查询快,增删慢

D:链表: 查询慢,增删快

(7)List的子类特点(面试题)

ArrayList

底层数据结构是数组,查询快,增删慢。

线程不安全,效率高。

Vector

底层数据结构是数组,查询快,增删慢。

线程安全,效率低。

LinkedList

底层数据结构是链表,查询慢,增删快。

线程不安全,效率高。

到底使用谁呢?看需求?

分析:

要安全吗?

要:Vector(即使要,也不使用这个,后面再说)

不要:ArrayList或者LinkedList

查询多;ArrayList

增删多:LinkedList

什么都不知道,就用ArrayList。


三、集合(List的子类)

(1)ArratList

A:有没特有功能需要学习

(2)Vector

A:特有功能

a:添加

public void addElement(Object obj)

b:获取

public Object elementAt(int index)   

public Enumeration elements()

boolean hasMoreElements()

Object nextElement()

(3)LinkedList

A:特有功能

a:添加

public void addFirst(Object e)

public void addLast(Object e)

b:删除

public Object removeFirst()

public Object removeLast()

c:获取

public Object getFirst()

public Obejct getLast()

(4)案列

A:去除集合中的多个字符串的重复元素,如果字符串的内容相同,即为重复元素

/* * ArrayList去除集合中字符串的重复值(字符串的内容相同) *  * 分析: * A:创建集合对象 * B:添加多个字符串元素(包含内容相同的) * C:创建新集合 * D:遍历旧集合,获取得到每一个元素 * E:拿这个元素到新集合去找,看有没有 * 有:不搭理它 * 没有:就添加到新集合 * F:遍历新集合 */public class ArrayListDemo {public static void main(String[] args) {// 创建集合对象ArrayList array = new ArrayList();// 添加多个字符串元素(包含内容相同的)array.add("hello");array.add("world");array.add("java");array.add("world");array.add("java");array.add("world");array.add("world");array.add("world");array.add("world");array.add("java");array.add("world");// 创建新集合ArrayList newArray = new ArrayList();// 遍历旧集合,获取得到每一个元素Iterator it = array.iterator();while (it.hasNext()) {String s = (String) it.next();// 拿这个元素到新集合去找,看有没有if (!newArray.contains(s)) {newArray.add(s);}}// 遍历新集合for (int x = 0; x < newArray.size(); x++) {String s = (String) newArray.get(x);System.out.println(s);}}}
/* * 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同) * 要求:不能创建新的集合,就在以前的集合上做。 */public class ArrayListDemo2 {public static void main(String[] args) {// 创建集合对象ArrayList array = new ArrayList();// 添加多个字符串元素(包含内容相同的)array.add("hello");array.add("world");array.add("java");array.add("world");array.add("java");array.add("world");array.add("world");array.add("world");array.add("world");array.add("java");array.add("world");// 由选择排序思想引入,我们就可以通过这种思想做这个题目// 拿0索引的依次和后面的比较,有就把后的干掉// 同理,拿1索引...for (int x = 0; x < array.size() - 1; x++) {for (int y = x + 1; y < array.size(); y++) {if (array.get(x).equals(array.get(y))) {array.remove(y);y--;}}}// 遍历集合Iterator it = array.iterator();while (it.hasNext()) {String s = (String) it.next();System.out.println(s);}}}
B:去除集合中的多个自定义对象的重复元素

分析:比如自定义一个学生类,contains()方法的底层依赖的是equals()方法。

而我们的学生类中没有equals()方法,这个时候,默认使用的是它父亲Object的equals()方法;

Object()的equals()默认比较的是地址值,所以,它们进去了。因为new的东西,地址值都不同;

按照我们自己的需求,比较成员变量的值,重写equals()即可。其他代码就很简单了

C:用LinkedList模拟一个栈数据结构的集合类,并测试

分析:题目的意思是定义一个类用LinkedList实现栈数据结果

栈的特点是先进后出,可以用LinkedList的特有功能addFirst()和removeFirst()来实现

/** * 自定义的栈集合 *  */public class MyStack {private LinkedList link;public MyStack() {link = new LinkedList();}public void add(Object obj) {link.addFirst(obj);}public Object get() {// return link.getFirst();return link.removeFirst();}public boolean isEmpty() {return link.isEmpty();}}
/* * MyStack的测试 */public class MyStackDemo {public static void main(String[] args) {// 创建集合对象MyStack ms = new MyStack();// 添加元素ms.add("hello");ms.add("world");ms.add("java");while(!ms.isEmpty()){System.out.println(ms.get());}}}

D:获取10个1-20之间的随机数,要求不能重复

/* * 获取10个1-20之间的随机数,要求不能重复 *  * 用数组实现,但是数组的长度是固定的,长度不好确定。 * 所以我们使用集合实现。 *  * 分析: * A:创建产生随机数的对象 * B:创建一个存储随机数的集合。 * C:定义一个统计变量。从0开始。 * D:判断统计遍历是否小于10 * 是:先产生一个随机数,判断该随机数在集合中是否存在。 * 如果不存在:就添加,统计变量++。 * 如果存在:就不搭理它。 * 否:不搭理它 * E:遍历集合 */public class RandomDemo {public static void main(String[] args) {// 创建产生随机数的对象Random r = new Random();// 创建一个存储随机数的集合。ArrayList<Integer> array = new ArrayList<Integer>();// 定义一个统计变量。从0开始。int count = 0;// 判断统计遍历是否小于10while (count < 10) {//先产生一个随机数int number = r.nextInt(20) + 1;//判断该随机数在集合中是否存在。if(!array.contains(number)){//如果不存在:就添加,统计变量++。array.add(number);count++;}}//遍历集合for(Integer i : array){System.out.println(i);}}}

四、集合(Set集合)

(1)Set集合的特点

无序,唯一

(2)HashSet集合

A:底层数据结构是哈希表(是一个元素为链表的数组)

B:哈希表底层依赖两个方法:hashCode()和equals()

执行顺序:

首先比较哈希值是否相同

相同:继续执行equals()方法

返回true:元素重复了,不添加

返回false:直接把元素添加到集合

C:如何保证元素唯一性的呢?

由hashCode()和equals()保证的

(3)TreeSet集合

A:底层数据结构是红黑树(是一个自平衡的二叉树)

B:保证元素的排序方式

a:自然排序(元素具备比较性)

让元素所属的类实现Comparable接口

代码:

/* * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口 */public class Student implements Comparable<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;}@Overridepublic int compareTo(Student s) {// return 0;// return 1;// return -1;// 这里返回什么,其实应该根据我的排序规则来做// 按照年龄排序,主要条件int num = this.age - s.age;// 次要条件// 年龄相同的时候,还得去看姓名是否也相同// 如果年龄和姓名都相同,才是同一个元素int num2 = num == 0 ? this.name.compareTo(s.name) : num;return num2;}}

b:比较器排序(集合具备比较性)

让集合构造方法接收Comparator的实现类对象

代码:用内部匿名类实现

// 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象// 而匿名内部类就可以实现这个东西TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {@Overridepublic 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;}});

(4)案例

A:获取无重复的随机数

/* * 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。 *  * 分析: * A:创建随机数对象 * B:创建一个HashSet集合 * C:判断集合的长度是不是小于10 * 是:就创建一个随机数添加 * 否:不搭理它 * D:遍历HashSet集合 */public class HashSetDemo {public static void main(String[] args) {// 创建随机数对象Random r = new Random();// 创建一个Set集合HashSet<Integer> ts = new HashSet<Integer>();// 判断集合的长度是不是小于10while (ts.size() < 10) {int num = r.nextInt(20) + 1;ts.add(num);}// 遍历Set集合for (Integer i : ts) {System.out.println(i);}}}


五、Collection集合总结

Collection

|--List 有序,可重复

|--ArrayList

底层数据结构是数组,查询快,增删慢

底层数据结构是数组,查询快,增删慢

|--Vector

底层数据结构是数组,查询快,增删慢

线程安全,效率低

|--LinkedList

底层数据结构是链表,查询慢,增删快

线程不安全,效率高

|--Set 无序,唯一

|--HashSet

底层数据结构是哈希表

如何保证元素唯一性的呢?

依赖两个方法:hashCode()和equals()

|--LinkedHashSet

底层数据结构是链表和哈希表

由链表保证元素有序

由哈希表保证元素唯一

|--TreeSet

底层数据结构是红黑树

如何保证元素排序的呢?

自然排序

比较器排序

如何保证元素唯一性的呢?

根据比较的返回值是否是0来决定


六、集合(Map集合)

(1)将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值

(2)Map和Collection的区别?

A:Map 存储的是键值对形式的元素,键唯一,值可以重复。夫妻对

B:Collection 存储的是单独出现的元素,子接口Set元素唯一,子接口List元素可重复。光棍

(3)Map接口功能概述

A:添加功能

V put(K key,V value):添加元素

B:删除功能

void clear():移除所有的键值对元素

V remove(Object key):根据键删除键值对元素,并把值返回

C:判断功能

boolean containsKey(Object key):判断集合是否包含指定的键

boolean containsValue(Object value):判断集合是否包含指定的值

boolean isEmpty():判断集合是否为空

D:获取功能

Set<Map.Entry<K,V>> entrySet():

V get(Object key):根据键获取值

Set<K> keySet():获取集合中所有键的集合

Collection<V> values():获取集合中所有值的集合

E:长度功能

int size():返回集合中的键值对的对数

(4)Map集合的遍历

A:键找值

a:获取所有键的集合

b:遍历键的集合,得到每一个键

c:根据键到集合中去找值

B:键值对对象找键和值

a:获取所有的键值对对象的集合

b:遍历键值对对象的集合,获取每一个键值对对象

c:根据键值对对象去获取键和值

代码体现:

Map<String,String> hm = new HashMap<String,String>();hm.put("it002","hello");hm.put("it003","world");hm.put("it001","java");//方式1 键找值Set<String> set = hm.keySet();for(String key : set) {String value = hm.get(key);System.out.println(key+"---"+value);}//方式2 键值对对象找键和值Set<Map.Entry<String,String>> set2 = hm.entrySet();for(Map.Entry<String,String> me : set2) {String key = me.getKey();String value = me.getValue();System.out.println(key+"---"+value);}

(5)HashMap集合

HashMap:是基于哈希表的Map接口实现

哈希表的作用是用来保证键的唯一性的

要保证唯一性必须重写hashCode()和equals()方法

(6)LinkedHashMap集合

LinkedHashMap:是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序

由哈希表保证键的唯一性

由链表保证键盘的有序(存储和取出的顺序一致)

(7)TreeMap集合

TreeMap:是基于红黑树的Map接口的实现

保证元素排序的方式:

a:自然排序(元素具备比较性)

让元素所属的类实现Comparable接口

b:比较器排序(集合具备比较性)

让集合构造方法接收Comparator的实现类对象

(8)案列

A:统计一个字符串中每个字符出现的次数


/* * 需求 :"aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1) *  * 分析: * A:定义一个字符串(可以改进为键盘录入) * B:定义一个TreeMap集合 * 键:Character * 值:Integer * C:把字符串转换为字符数组 * D:遍历字符数组,得到每一个字符 * E:拿刚才得到的字符作为键到集合中去找值,看返回值 * 是null:说明该键不存在,就把该字符作为键,1作为值存储 * 不是null:说明该键存在,就把值加1,然后重写存储该键和值 * F:定义字符串缓冲区变量 * G:遍历集合,得到键和值,进行按照要求拼接 * H:把字符串缓冲区转换为字符串输出 *  * 录入:linqingxia * 结果:result:a(1)g(1)i(3)l(1)n(2)q(1)x(1) */public class TreeMapDemo {public static void main(String[] args) {// 定义一个字符串(可以改进为键盘录入)Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String line = sc.nextLine();// 定义一个TreeMap集合TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();//把字符串转换为字符数组char[] chs = line.toCharArray();//遍历字符数组,得到每一个字符for(char ch : chs){//拿刚才得到的字符作为键到集合中去找值,看返回值Integer i =  tm.get(ch);//是null:说明该键不存在,就把该字符作为键,1作为值存储if(i == null){tm.put(ch, 1);}else {//不是null:说明该键存在,就把值加1,然后重写存储该键和值i++;tm.put(ch,i);}}//定义字符串缓冲区变量StringBuilder sb=  new StringBuilder();//遍历集合,得到键和值,进行按照要求拼接Set<Character> set = tm.keySet();for(Character key : set){Integer value = tm.get(key);sb.append(key).append("(").append(value).append(")");}//把字符串缓冲区转换为字符串输出String result = sb.toString();System.out.println("result:"+result);}}

(9)面试题

A:Hashtable和HashMap的区别?

Hashtable:线程安全,效率低。不允许null键和null值

HashMap:线程不安全,效率高。允许null键和null值

B:List,Set,Map等接口是否都继承子Map接口?

List,Set不是继承自Map接口,它们继承自Collection接口

Map接口本身就是一个顶层接口


七、Collections工具类

(1)是针对集合进行操作的工具类

(2)面试题:Collection和Collections的区别

A:Collection 是单列集合的顶层接口,有两个子接口List和Set

B:Collections 是针对集合进行操作的工具类,可以对集合进行排序和查找等

(3)常见的几个小方法:

A:public static <T> void sort(List<T> list)  排序 默认情况下是自然顺序

B:public static <T> int binarySearch(List<?> list,T key)   二分查找

C:public static <T> T max(Collection<?> coll)    最大值

D:public static void reverse(List<?> list)   反转

E:public static void shuffle(List<?> list)  随机置换

(4)案例

A:模拟斗地主洗牌和发牌并对牌进行排序

/* * 思路: * A:创建一个HashMap集合 * B:创建一个ArrayList集合 * C:创建花色数组和点数数组 * D:从0开始往HashMap里面存储编号,并存储对应的牌 *        同时往ArrayList里面存储编号即可。 *      E:洗牌(洗的是编号) *      F:发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收) *      G:看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌) */public class PokerDemo {public static void main(String[] args) {// 创建一个HashMap集合HashMap<Integer, String> hm = new HashMap<Integer, String>();// 创建一个ArrayList集合ArrayList<Integer> array = new ArrayList<Integer>();// 创建花色数组和点数数组// 定义一个花色数组String[] colors = { "♠", "♥", "♣", "♦" };// 定义一个点数数组String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q","K", "A", "2", };// 从0开始往HashMap里面存储编号,并存储对应的牌,同时往ArrayList里面存储编号即可。int index = 0;for (String number : numbers) {for (String color : colors) {String poker = color.concat(number);hm.put(index, poker);array.add(index);index++;}}hm.put(index, "小王");array.add(index);index++;hm.put(index, "大王");array.add(index);// 洗牌(洗的是编号)Collections.shuffle(array);// 发牌(发的也是编号,为了保证编号是排序的,就创建TreeSet集合接收)TreeSet<Integer> fengQingYang = new TreeSet<Integer>();TreeSet<Integer> linQingXia = new TreeSet<Integer>();TreeSet<Integer> liuYi = new TreeSet<Integer>();TreeSet<Integer> diPai = new TreeSet<Integer>();for (int x = 0; x < array.size(); x++) {if (x >= array.size() - 3) {diPai.add(array.get(x));} else if (x % 3 == 0) {fengQingYang.add(array.get(x));} else if (x % 3 == 1) {linQingXia.add(array.get(x));} else if (x % 3 == 2) {liuYi.add(array.get(x));}}// 看牌(遍历TreeSet集合,获取编号,到HashMap集合找对应的牌)lookPoker("风清扬", fengQingYang, hm);lookPoker("林青霞", linQingXia, hm);lookPoker("刘意", liuYi, hm);lookPoker("底牌", diPai, hm);}// 写看牌的功能public static void lookPoker(String name, TreeSet<Integer> ts,HashMap<Integer, String> hm) {System.out.print(name + "的牌是:");for (Integer key : ts) {String value = hm.get(key);System.out.print(value + " ");}System.out.println();}}



0 0