------- android培训、java培训、期待与您交流! ----------
集合的由来:
java是一种面向对象的语言,对现实世界中的事物均以对象体现,为了方便对多个对象进行操作(对象数组的局限性)
为了方便我们对多个对象进行操作,java是提供了一种新的容器,就是集合类(框架)
:用于存储对象的容器
: 该容器的长度是可变的
:集合中存储的对象可以是任意类型的
集合与数组的区别:
集合:
长度是可变的
集合只能存储对象类型
集合可以存储多种引用数据类型的元素
数组:
长度是固定的
数组可以存储对象类型,也可以存储基本数据类型
数组存储的多个元素是同一种数据类型
由于数据在存储的时候,数据结构不一样,所以,就会出现多种类型的集合方便我们操作。
不管你是哪种类型的集合,都是满足一些常见的操作
集合框架的由来:(理解)
由于多种集合类的数据结构不同,通过不断的向上抽取,形成了集合的体系结构。
学习和使用体系结构的方式。
学习顶层,因为顶层定义的是共性的东西。
使用底层,因为底层是具体实现的东西。
数据结构:
组织数据的方式。
但是,操作的方式又不一样,这个时候,就要向上抽取,最终形成一个集合体系结构
Collection接口功能: (重点,能够把数据放到集合中,然后把数据从集合中遍历出来)
1、添加元素:
boolean add(Object obj);//添加单个元素
boolean addAll(Collection c);添加多个元素
2、判断元素:
boolean contains(Object obj);判断元素是否存在。
boolean containsAll(Collection c);判断一个集合的元素是否包含在当前集合中
boolean isEmpty();判断集合是否为空
3、删除元素:
void clear();移除所有元素。这个方法太暴力了。
boolean remove(Object o);移除单个元素。
boolean removeALL(Collection c);移除多个元素。
4、获取元素:
Iterator iterator();返回集合上的一个迭代器
5、交集:
boolean retainAll(Collection c)交集
6、集合元素的个数:
int size();元素个数
7、把集合转成数组
Object[] toArray(); 建议不要使用此方法进行集合的遍历
迭代器的使用:
Iterator iterator();
迭代器中的三个方法:
boolean hasNext(); 判断是否还有元素
Object next():获取元素,并且还可以自动指向下一个元素
void remove(); 删除元素:
原理: 每种集合的存储方式不一样,所以,它的取出方式也不一样
但是,他们都应该有获取的功能,所以,进行了抽取
当你遍历某种类型的集合的时候,就由该类型的集合自己去实现迭代器接口
*************************************
集合操作的思路:
A:创建集合对象
B:创建元素对象
C:把元素添加到集合中
D:遍历集体
**通过集合对象获取迭代器对象
**调用迭代器对象的hasNext()方法判断是否还有元素
**调用迭代器对象的next()方法获取元素。
例如:
class IteratorDemo
{
public static void main(String[] args)
{
//创建集合对象
Collection c=new ArrayList();
//添加元素
c.add("hello");
c.add("world");
c.add("itcast");
System.out.println(c);
//遍历
//用数组实现的,这种不用Object[] toArray()
//迭代器的实现
Iterator it=c.iterator(); //返回的是实现了迭代器接口的子类对象
//获取元素
while(it.hasNext())//判断是否还有元素
{
//
Object obj=it.next()//可以直接由Object类的进行接收
System.out.println(it.next()); //可以直接打印出来
}
}
}
例2:
*
* 集合存储自定义对象
*/
public class CollectionDemo {
public static void main(String[] args) {
// 创建集合对象
Collection c = new ArrayList();
// 创建元素对象
Student s1 = new Student("东方不败", 20);
Student s2 = new Student("林平之", 18);
Student s3 = new Student("岳不群", 19);
// 添加元素
c.add(s1);
c.add(s2);
c.add(s3);
// 遍历元素
// 通过集合对象获取迭代器对象
Iterator it = c.iterator();
// 通过hasNext()方法判断
while (it.hasNext()) {
// 通过next()方获取元素
// System.out.println(it.next().toString());
Student s = (Student) it.next();
// System.out.println(s);
System.out.println(s.getName() + "***" + s.getAge());
}
}
}
-----------------------List
Collection
|----List
元素有序(存入顺序和取出顺序一致),元素可以重复
|---Set
元素是无序,元素要求唯一
List接口的功能:
1、添加元素
void add(int index,Object obj);指定位置添加指定元素
2、获取元素:
Object get(int index):根据指定索引获取元素
3、列表迭代器
ListIterator listIterator();
4、删除元素:
Object remove(int index);删除指定位置的元素
5、修改元素:
Object set(int index,Object element);修改指定位置的元素
size()方法,它可以获取集合的元素个数。
--------------------------------------------------------
例:get方法可以根据指定的索引获取单个元素
那么List体系的集合就多了一种遍历方式:
我们想到了size()方法,它可以获取集合的元素个数
这样的话,我们就可以从0开始获取每个元素的索引
public class ListDemo2
{
//创建集合对象
List list=new new ArrayList();
//添加元素
list.add();
//遍历
for(int x=0;x<list.size();x++)
{
//Stirng s=(String)lis.get(x);
System.out.println(list.get(x));
}
// 这种方法效率不高,可以优化
// list.size()每次循环,都去调用了方法计算集合的元素个数
// 如果元素过多,这种方式不好
// int length = list.size();
// for (int x = 0; x < length; x++) {
// String s = (String) list.get(x);
// System.out.println(s);
// }
在集合元素比较多的时候 可以使用此方法
}
---------list迭代器的使用
Iterator
hasNext()
next();
----ListIterator listIterator();列表迭代器遍历集合元素
有自己的特殊功能,可以实现在逆向遍历
1、Object previous(); //读取一个元素
2、boolean hasPrevious();//判断是否有下一个元素
例1:
Iterator it=it.iterator();
while(lit.hasPrevious())
{
String s=(String)lit.previous();
System.out.println(s);
}
例2:
* 要查找集合中有没有是zhangsan这个字符串。
* 如果有,则在添加一个lisi进去。
*
* Exception in thread "main" java.util.ConcurrentModificationException:并发修改异常
* 在使用迭代器迭代元素的时候,不能使用集合去操作元素,否则,就会出现并发修改异常。
* 那么,请问如何解决这个问题,并能够让元素添加成功:
* 1:在迭代器迭代的过程中,使用迭代器对象去添加元素。
* 2:不用迭代器遍历,用普通for循环遍历,用集合添加元素
*/
public class ListDemo4 {
public static void main(String[] args) {
// 创建集合对象
List list = new ArrayList();
list.add("zhaoliu");
list.add("zhangsan");
list.add("wangwu");
// 请问如何实现我的需求
ListIterator lit = list.listIterator();
while (lit.hasNext()) {
String s = (String) lit.next();
// 判断
if ("zhangsan".equals(s)) {
// void add(E e)
lit.add("lisi"); //只能使用迭代器进行数据的添加
// list.add("lisi");
}
}
/*
for(int x=0; x<list.size();x++){
String s = (String)list.get(x);
if("zhangsan".equals(s)){
list.add("lisi");
}
}
*/
System.out.println("list:" + list);
}
}
-----------------------------------------------List集合的使用------------------------------------------------------------------------
list的儿子的特点:
|---ArrayList
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
|---Vector
底层数据结构是数组,查询快,增删慢
线程安全,效率低
|---LinkedList
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
使用总结:
我们开发中到底使用哪个子类呢
是否考虑线程安全问题
考虑:
使用Vector
不考虑:
使用ArrayList 或者LinkedList
如果查询多,增删少,用ArrayList
如果查询少,增删少,用LinkedList
如果你还是不知道 ,用ArrayList
// 方式3
//注意:如果使用列表迭代器,我们虽然说了它可以逆序遍历。
//但前提是先正向遍历到结尾了。然后才能逆序遍历。
ListIterator lit = array.listIterator();
while (lit.hasPrevious()) {
String s = (String) lit.previous();
System.out.println(s);
Vector的特殊方法:
1:添加元素
* void addElement(Object obj) -- JDK1.2 后改为了 add(Object obj)
2: 获取元素
* Object elementAt(int index) -- JDK1.2后就改为了 get(int index)
3:遍历元素
Enumeration elements() -- JDK1.2后就改为了 Iterator iterator()
boolean hasMoreElements() -- JDK1.2后就改为了 boolean hasNext()
Object nextElement() -- JDK1.2后就改为了 Object next()
LinkedList的特殊方法:
1:添加元素
void addFirst(Object obj)
void addLast(Object obj)
2:删除元素
Object removeFirst()
Object removeLast()
3:获取元素
Object getFirst()
Object getLast()
泛型:是一种特殊的类型,它把指定类型的工作推迟代码声明并实例化类或方法的时候进行。
泛型的体现:<数据类型>
在我们使用泛型之前,代码会有黄线警告,还可能会出现类型转换异常。
我们肯定要解决这个问题,那么,怎么解决呢?
我们在想想我们曾经使用的数组:
String[] strArray = new String[3];
strArray[0] = "hello";
strArray[1] = "world";
strArray[2] = 10;
for(int x=0; x<strArray.length; x++)
{
String s = strArray[x];
System.out.println(s);
}
通过这个例子,我们看到,这里已经出问题了,这个时候,我们需要改代码。
通过这个例子我们还发现这个数组里面到底存储什么类型的数据,我一开始就知道了。
这样的话,我们存入数据的时候,如果类型不匹配,立马就报错了,我们就马上改正了。
还有第二点,这样可以避免运行时期的类型转换异常。
泛型的好处:
1:将原先时期出现的ClassCastException问题,转移到了编译时期。
2:泛型的出现避免了强制转换的麻烦。
3:优化了程序设计
----------------------------------------------------Set集合------------------------------------------------
1:Set(掌握)
(1)Set集合的特点:元素无序,唯一(掌握)
(2)Set的体系结构(掌握)
Set
|--HashSet
底层数据结构是哈希表。
如何保证元素的唯一性呢?
它依赖两个方法:hashCode()和equals()
首先判断哈希值是否相同:
不同:就把元素添加到集合中。
相同:继续进入equals方法比较
返回true,说明元素重复,不存。
返回false,就把元素添加到集合中。
|--TreeSet
底层数据结构是二叉树。
可以让集合中的元素排序。
如何保证元素的唯一性的呢?
它是根据比较返回的值是0,说明元素是重复的,就不添加。
有两种实现方案:
A:让自定义对象具备比较性
实现Comparable接口
B:让集合具备比较性
实现Comparator接口
如果两种情况都存在,以B为主。
(3)案例:(掌握)
用HashSet存储自定义对象,并去掉重复元素
用TreeSet存储自定义对象,并按需求排序和去掉重复值
(4)自学LinkedHashSet(了解)
底层数据结构是由哈希表和链表组成。
特点:
有序,唯一
请用一个案例验证总结的特点。
2:泛型(理解)
(1)泛型类
(2)泛型方法
(3)泛型接口
(4)重点掌握集合中添加泛型的使用。
3:增强for(掌握)
(1)好处:简化了数组和Collection集合的遍历。(掌握)
(2)格式(掌握)
for(Collection集合或者数组对象的元素类型 变量 : Collection集合或者数组对象)
{
//使用变量即可
}
(3)案例:(掌握)
能够使用增强for遍历数组,Collection集合。
例如:
需求:我认为成员属性相同对象即为同一个对象。
*
* 我们重写了equals方法,发现没有达到效果。
* 通过测试,发现根本没有执行equals方法。
* 那么,问题出现在了什么地方呢?
* 通过思考,我们估计问题是出现在了add方法上。
* 所以,我们要研究add方法的源码。
* 通过查看源码,我们发现这个add方法和hashCode()及equals()有关。
* 而且是当哈希值相同的时候,采取执行equals方法。
*
* HashSet是如何保证元素的唯一性的呢?
* 底层数据结构是哈希表。
* 哈希表依赖的是哈希值存储数据的。
* 这个集合首先会根据hashCode方法去判断哈希值是否相同,
* 如果不同,则认为是不同的元素,就添加到集合中。
* 如果相同,就会走equals方法,这样就可以实现根据自己的需求进行比较。
* 如果返回值是true,说明该元素在集合中存在,就不添加。
* 如果返回值是false,直接添加元素。
*/
public class HashSetDemo {
public static void main(String[] args) {
// 创建集合对象
HashSet<Person> hs = new HashSet<Person>();
// 创建元素对象
Person p1 = new Person("林青霞", 25);
Person p2 = new Person("张曼玉", 28);
// 添加元素
hs.add(p1);
hs.add(p2);
// 遍历
Iterator<Person> it = hs.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.println(p.getName() + "***" + p.getAge());
}
}
}
例如:
我们的TreeSet集合是用于保证元素排序和唯一的。
* 而我们现在的这种操作,并没有让集合中的元素进行排序。
* 通过运行时期的异常,我们可以知道解决
* 方案1:让自定义对象实现Comparable接口
public int compareTo(Person p) {
// 小-大 (this - p)
// 大-小(p - this)
// 按照姓名的从短到长,年龄从大到小顺序排序,并去掉重复元素(姓名和年龄相同即为重复元素)。
// 谁调用this代表谁
int num = this.name.length() - p.name.length();
int num2 = (num == 0) ? (p.age - this.age) : num;
// 追加条件,这个条件是需要我们自己思考的
int num3 = (num2 == 0) ? (this.name.compareTo(p.name)) : num2;
return num3;
}。
* 方案2:让集合具备比较性
* 使用TreeSet带比较器的构造方法
*
* 当Person类具备比较性的时候,是指Person类实现Comparable接口
* 集合也具备比较性的时候,是指TreeSet接受了实现Comparator接口的子类对象
* 以集合具备比较性为主。这个时候,也就是说自定义对象没有必要再去实现比较性的接口。
*
* TreeMap -- put
*
* 需求:成员属性相同的元素为同一对象。我想让元素按照年龄从大到小排序。
*
* TreeSet保证元素唯一性的原理?
* 根据比较方法返回的值是否是0来确定该元素是否是重复元素。
*
* 在用TreeSet保证元素唯一的时候,我们还得考虑元素的排序。
* 而排序的时候,一定要注意排序的主次要条件。
*
*/
public class TreeSetDemo3 {
public static void main(String[] args) {
// 创建集合对象
// 以后注意,如果一个方法的参数是一个接口类型的
// 那么,你肯定传递的是一个实现了接口的子类对象
// 匿名对象的使用
TreeSet<Person> ts = new TreeSet<Person>(new MyComparator());
// 创建元素对象
Person p1 = new Person("陆毅", 30);
// 添加元素
ts.add(p1);
// 遍历元素
Iterator<Person> it = ts.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.println(p.getName() + "***" + p.getAge());
}
}
}
-------------------------------------- 增强for循环-------------------------------------------------
* 格式:
* for(Collection集合或者数组对象中元素的数据类型 变量名 : Collection集合或者数组对象)
* {
* 在这个里面直接使用这个变量,其实就是依次获取到的集合或者数组中的元素。
* }
*
* 增强for就是为了方便对Collection集合或者数组的遍历。
* 也是可以用于替代迭代器的。
*/
-------------------------------------------------:Map(掌握)-----------------------------------------------
(1)Map:存储的是键值对形式的数据的集合。(了解)
(2)Map的特点:(了解)
数据是以键值对形式存在
键不能是重复的
值可以重复
(3)Map接口的功能:(掌握)
A:添加元素
V put(K key,V value)
B:判断元素
boolean containsKey(K key)
boolean containsValue(V value)
boolean isEmpty()
C:删除元素
V remove(K key)
D:长度
int size()
E:获取
V get(k key)
Set<K> keySet()
Collection<V> values()
Set<Map.Entry<K,V>> entrySet()
(4)Map案例:(掌握)
Map存储字符串并遍历:
Map<String,String> map = new HashMap<String,String>();
map.put("it001","zhangsan");
map.put("it002","lisi");
map.put("it003","wangwu");
//遍历
//方式1:丈夫找妻子
Set<String> set = map.keySet();
for(String key : set)
{
String value = map.get(key);
System.out.println(key+"***"+value);
}
//方式2:通过结婚证找丈夫和妻子
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for(Map.Entry<String,String> me : entrySet)
{
String key = me.getkey();
String value = me.getValue();
System.out.println(key+"***"+value);
}
(5)Map的体系结构(掌握)
Map:(Map体系的数据结构对键有效,跟值无关)
|--HashMap
底层数据结构是哈希表。
如何保证键的唯一性呢?
依赖hashCode()和equals()方法
线程不安全,效率高。允许null键和值。
|--Hashtable
底层数据结构是哈希表。
如何保证键的唯一性呢?
依赖hashCode()和equals()方法
线程安全,效率低。不允许null键和值。
|--TreeMap
底层数据结构是二叉树。
如何保证键的唯一性呢?
两种方式:
自定义元素具备比较性
集合具备比较性
线程不安全,效率高。允许null值,不允许null键。
那么,我们一般使用谁?
如果有排序需求,用TreeMap,否则全部使用HashMap。
(6)案例:
统计字符串中每个字符出现的次数(掌握)
czbk集合的数据存储和遍历(理解)
2:总结集合的使用规律:
是否是键值对形式:
是:Map体系
是否需要排序:
是:TreeMap
不是:HashMap
不知道:HashMap
不是:Collection体系
是否要保证元素唯一:
是:Set
是否要排序:
是:TreeSet
不是:HashSet
不知道:HashSet
不是:List
查询多:ArrayList
增删多:LinkedList
不知道:ArrayList
3:遍历方式:
Collection:
List:
普通for
增强for
//迭代器
Set:
增强for
//迭代器
Map:没有直接遍历方式,需要通过转换。
方式1:丈夫找妻子
//方式2:通过结婚证找丈夫和妻子
4:集合的底层数据结构规律:
ArrayXxx:底层数据结构是数组,查询快,增删慢。
LinkXxx:底层数据结构是链表,查询慢,增删快。
HashXxx:底层数据结构是哈希表。
依赖hashCode()方法和equals()方法
TreeXxx:底层数据结构是二叉树
两种方式实现排序:
自定义元素具备比较性
集合具备比较性
本文深入讲解Java集合框架的原理和应用,包括集合的由来、集合与数组的区别、集合框架的体系结构等内容,并通过具体案例介绍了List、Set、Map等接口的使用方法。
1497

被折叠的 条评论
为什么被折叠?



