栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java集合之单列集合

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java集合之单列集合

  • 什么是集合

集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)

  • 集合和数组的区别
数组在存储多个数据方面的特点

> 一旦初始化以后,其长度就确定了。
> 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。比如:String[] arr;int[] arr1;Object[] arr2;只能存储对于定义的类型元素

数组在存储多个数据方面的缺点(集合可以很好的解决)

> 一旦初始化以后,其长度就不可修改。
> 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
> 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
> 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

总结

>数组是固定长度的;集合可变长度的。
>数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
>数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型(其实集合一般存储的数据也是同一类型的)。

  • 集合框架(常用集合类)

Collection 单列集合,用来存储一个一个的对象
|——- List 接口:元素按进入先后有序保存,可重复(”动态“数组)
|—————- LinkedList 接口实现类, 底层是链表实现的,增和删比较快,查找和修改比较慢,没有同步, 线程不安全
|—————- ArrayList 接口实现类, 底层是数组实现的, 随机访问,查找和修改快,增和删比较慢, 没有同步,线程不安全
|—————- Vector 接口实现类 底层是数组实现的,同步,线程安全
|———————- Stack 是Vector类的实现类
|——- Set接口:存储无序的、不可重复的数据   -->高中讲的“集合”
|—————- HashSet 使用hash表(数组)存储元素
|————————- LinkedHashSet 链表维护元素的插入次序,可以保证存储的元素唯一
|—————-TreeSet 底层是二叉树算法实现,元素排好序

Map接口:双列集合,用来存储一对(key - value)一对的数据   -->高中函数:y = f(x)
|———- Hashtable 接口实现类, 同步, 线程安全
|———- HashMap 接口实现类 ,没有同步, 线程不安全-
|—————–- LinkedHashMap 双向链表和哈希表实现
|—————–- WeakHashMap
|——–- TreeMap 红黑树对所有的key进行排序
|———- IdentifyHashMap

  • Collection接口中的方法的使用
在集合末尾添加元素——boolean add(E e)
@Test
    public void test1(){
        Collection coll = new ArrayList();
        coll.add("aaa");
        coll.add(123);//自动装箱
        coll.add(new Date());
        System.out.println(coll);
    }
获取添加的元素的个数——int size()
System.out.println(coll.size());//3
将集合中的元素添加到当前的集合中——boolean addll(Collection c)
Collection coll1 = new ArrayList();
coll1.add("bbb");
coll.addAll(coll1);
System.out.println(coll);//[aaa, 123, Fri Jun 10 15:30:17 CST 2022, bbb]
清空集合中所有的元素——void clear()
coll.clear();
System.out.println(coll);//[]
判断当前集合是否为空——boolean isEmpty()
System.out.println(coll.isEmpty());//true
判断集合中是否包含某元素——boolean contains(Object o)   
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("嘻戏i"));
coll.add(new Person("嘻戏i",31));
System.out.println(coll.contains(123));//true
System.out.println(coll.contains(new String("嘻戏i")));//true
//我们在判断时会调用obj对象所在类的equals()。Person类未重写equals方法则该处为false,反之为true
System.out.println(coll.contains(new Person("嘻戏i",31)));//false -->true
判断某一集合中的所有元素是否都存在于当前集合中——boolean containsAll(Collection c)
Collection coll1 = Arrays.asList(123,"嘻戏i");
System.out.println(coll.containsAll(coll1));//true
从集合中移除某一元素——boolean remove(Object o)
coll.remove(123);
System.out.println(coll);//[嘻戏i, Person{name='嘻戏i', age=31}]
从集合中移除某一集合中所有的元素(差集)——boolean removeAll(Collection c)
coll.removeAll(coll1);
System.out.println(coll);//[Person{name='嘻戏i', age=31}]去除和coll1相同的元素
获取当前集合和另一集合的交集,并返回给当前集合boolean retainAll(Collection c)
Collection coll = new ArrayList();
coll.add(123);
coll.add("嘻戏i");
coll.add(new Person("嘻戏i",31));
coll.add(false);

Collection coll1 = Arrays.asList(123,"嘻戏i","aaa");
coll.retainAll(coll1);
System.out.println(coll);//[123, 嘻戏i]
System.out.println(coll1);//[123, 嘻戏i, aaa]
判断当前集合和形参集合是否相同——boolean equals(Object o)
boolean equals = coll.equals(coll1);
//要想返回true 需要当前集合和形参集合的元素都相同。(因为我们这里使用的是collection子类ArrayList是有序的,所有元素的位置也需要一致)
System.out.println(equals);
返回当前对象的哈希值——int hashcode()
int i = coll.hashCode();
System.out.println(i);
集合转数组——Object[] toArray()
Collection coll = new ArrayList();
coll.add("嘻戏i");
coll.add(123);
coll.add(new Person("嘻戏i",31));

Object[] objects = coll.toArray();
for (int i = 0; i < objects.length; i++) {
    System.out.println(objects[i]);
}
数组转集合——调用Arrays类的静态方法asList()
List list = Arrays.asList(new String[]{"aa","bb","cc"});
System.out.println(list);//[aa, bb, cc]

//基本数据类型的数组转化成集合时,会将整个数组默认一个整体
List list1 = Arrays.asList(new int[]{111,222,333});
System.out.println(list1);//[[I@3d82c5f3]

List list2 = Arrays.asList(new Integer[]{111,222,333});
System.out.println(list2);//[111, 222, 333]
遍历集合元素:迭代器——Iterator iterator()
public void test5() {
    Collection coll = new ArrayList();
    coll.add("嘻戏");
    coll.add(123);
    coll.add(new Person("嘻戏", 28));

    Iterator iterator = coll.iterator();//获取迭代器
    while (iterator.hasNext()) { //hasNext():判断是否还有下一个元素
        System.out.println(iterator.next()); //next():①指针下移 ②将下移以后集合位置上的元素返回
    }
}
  •  遍历集合元素的方法:
使用迭代器Iterator
public void test5() {
Collection coll = new ArrayList();
coll.add("嘻戏");
coll.add(123);
coll.add(new Person("嘻戏", 28));

Iterator iterator = coll.iterator();//获取迭代器
//方式一:不推荐
//        for (int i = 0; i < coll.size(); i++) {
//            System.out.println(iterator.next());
//        }
//方式二:推荐
while (iterator.hasNext()) { //hasNext():判断是否还有下一个元素
    System.out.println(iterator.next()); //next():①指针下移 ②将下移以后集合位置上的元素返回
}

使用迭代器Iterator的错误方式

下面三种错误方式代码用到的集合

Collection coll = new ArrayList();
coll.add("嘻戏");
coll.add(123);
coll.add(new Person("嘻戏", 28));
错误方式1: 报异常:NoSuchElementException
//方式1.1
Iterator iterator1 = coll.iterator();
while (iterator1.next() != null){
    System.out.println(iterator1.next());
}
//方式1.2
System.out.println(iterator.next());
System.out.println(iterator.next());
//报异常:NoSuchElementException
System.out.println(iterator.next());
错误方式2 一直无限循环下去
//集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
while (coll.iterator().hasNext()){
    System.out.println(coll.iterator().next());
}
//错误方式3 关于Iterator中的remove()
//如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。
Iterator iterator2 = coll.iterator();
while (iterator2.hasNext()){
//            iterator2.remove(); //报异常:IllegalStateException
    //正确操作:删除集合中的new Person("嘻戏",28)
    Object obj = iterator2.next();
    if (new Person("嘻戏",28).equals(obj)){
        iterator2.remove();
    }
}
iterator2 = coll.iterator();
while (iterator2.hasNext()){
    System.out.println(iterator2.next());
}
增强for循环遍历集合元素
Collection coll = new ArrayList();
coll.add(123);
coll.add("嘻戏");
coll.add(new Person("嘻戏",28));

//for(集合元素的类型 局部变量 : 集合对象)
//内部仍然调用了迭代器。
for (Object obj: coll) {
    System.out.println(obj);
}

System.out.println("*****************");
//for循环和增加for循环
String[] arr = new String[]{"MM","MM","MM"};
for (int i = 0; i < arr.length; i++) {
//           arr[i] = "GG";//改变了字符串arr
}

for (String s :
        arr) {
    s = "GG";//只改变了局部变量s,未改变字符串arr
//            System.out.println(s);
}
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}
  • List接口框架

|----Collection接口:单列集合,用来存储一个一个的对象
          |----List接口:存储有序的、可重复的数据。  -->“动态”数组,替换原有的数组
              |----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
              |----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
              |----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储

 ArrayList的源码分析

1 jdk 7情况下
       ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData
       list.add(123);//elementData[0] = new Integer(123);

       list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
       默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
 
       结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
2 jdk 8中ArrayList的变化:
      ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没有创建长度为10的数组
      list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]

      后续的添加和扩容操作与jdk 7 无异。
3 小结:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。

LinkedList的源码分析

LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null
      list.add(123);//将123封装到Node中,创建了Node对象。

      其中,Node定义为:体现了LinkedList的双向链表的说法

private static class Node {
             E item;
             Node next;
             Node prev;

             Node(Node prev, E element, Node next) {
             this.item = element;
             this.next = next;
             this.prev = prev;
             }
         }
Vector的源码分析

jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。在扩容方面,默认扩容为原来的数组长度的2倍。

总结

ArrayList、LinkedList、Vector三者的异同:

同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据

异:通过上面的源代码分析

 List接口中的常用方法

增:

在index位置插入元素 ——void add(int index, Object ele)

list.add(1,456);

从index位置开始将另外集合中的所有元素添加进来 ——boolean addAll(int index, Collection eles)

List list1 = Arrays.asList(1,2,3);
//从list索引2的位置开始将list1中的所有元素添加进来
list.addAll(2,list1);
//从list末尾的位置开始将list1中的所有元素当做一个整体添加进来
list.add(list1);

删:

 移除指定索引位置的元素,并返回此元素——Object remove(int index) / boolean remove(Object obj)

//删除list集合中索引为2的元素,并返回该元素
Object Obj = list.remove(2);
System.out.println(Obj);
//删除list集合中list1集合,有就返回true,没有返回false
boolean obj1 = list.remove(list1);
System.out.println(obj1);

改:

 设置指定索引位置的元素为其他元素——Object set(int index, Object ele)

Object obj2 = list.set(3, 33);
System.out.println(obj2);

查:

获取指定索引位置的元素 ——Object get(int index)

Object obj3 = list.get(3);
System.out.println(obj3);

获取集合长度——int size()

int size = list.size();

返回obj在集合中首次出现的位置(集合中不存在查询的元素返回-1)——int indexOf(Object obj)

int i = list.indexOf(123);

返回obj在当前集合中末次出现的位置——int lastIndexOf(Object obj)

int i2 = list.lastIndexOf(123);

返回从fromIndex到toIndex位置的子集合(左闭右开)——List subList(int fromIndex, int toIndex)

List list2 = list.subList(1, 4);
List集合遍历

Iterator迭代器方式

Iterator iterator = list.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}

增强for循环

for (Object obj : list) {
    System.out.println(obj);
}

普通for循环(List集合有索引,结合get方法,可以用普通for循环)

for (int j = 0; j < list.size(); j++) {
    System.out.println(list.get(j));
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/995709.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号