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

Day

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

Day

对于数据的存储,我们已经介绍了数组,但是数组存储存在着很多的不足,如:
① 一旦初始化以后,其长度就不可修改
② 对于添加、删除、插入数据等操作非常不便,效率不高
③ 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足
④ 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用

Java集合分为Collection和Map两种体系

java集合超详解

一.Collection接口

Collection接口用于存储单列数据,
1)List接口:元素有序、可重复的集合
2)Set接口:元素无序、不可重复的集合

1.Collection接口中的主要方法

//Collection集合的主要方法说明
public class CollectionTest {
    public static void main(String[] args) {
        Collection arrayList = new ArrayList();
        Collection arrayList1 = new ArrayList();
        //1.add(object obj):向集合中添加元素
        arrayList.add("hello");
        arrayList.add(123);
        arrayList1.add('A');
        arrayList1.add(new String("中国"));
        //2.size():返回集合元素个数
        System.out.println(arrayList.size());
        //3.addAll(Collection c):将指定集合c中的元素添加到指定集合中
        arrayList.addAll(arrayList1);
        System.out.println(arrayList.size());
        //4.clear():删除集合中的所有元素
        //arrayList.clear();
        System.out.println(arrayList.size());
        //5.isEmpty():判断当前集合是否为空
        System.out.println(arrayList.isEmpty());
        //6.contains(object obj):判断当前集合是否包含指定元素
        //注意:此时实际调用的是实际对象obj重写后的equals()方法,若没有重写,则调用的是Object类中的equals()方法==
        System.out.println(arrayList1.contains(new String("中国")));//true
        //7.containsAll(collection c):判断该集合是否包含指定集合c中所有的元素
        System.out.println(arrayList.containsAll(arrayList1));
        System.out.println(arrayList);
        //8.equals(collection c):判断该集合是否和指定集合c相等(元素相同,注意集合有序时还要顺序相同)
        System.out.println(arrayList.equals(arrayList1));
        //9.remove(object o):删除该集合中指定的元素
        System.out.println(arrayList.remove(123));
        System.out.println(arrayList);
        //10.removeAll(collection c):删除包含指定集合c中所有的元素,返回boolean值
        System.out.println(arrayList.removeAll(arrayList1));//true
        //11.retainAll(Collection c):保留包含指定集合c中所有的元素
        System.out.println(arrayList);
        System.out.println(arrayList1);
        System.out.println(arrayList.retainAll(arrayList1));//true
        //12.hashCode();返回当前对象的哈希值
        System.out.println(arrayList.hashCode());
        //13.toArray():集合--->数组
        Object[] array = arrayList1.toArray();
        for(int i=0;i集合
        List strings = Arrays.asList(new String[]{"AA", "BB", "CC"});
        System.out.println(strings);
        List ints = Arrays.asList(new int[]{1, 1, 3, 44});
        System.out.println(ints);//[[I@6d6f6e28]认为是一个元素,要写成对应的包装类就可以了
        List integers = Arrays.asList(new Integer[]{11, 22, 33});
        System.out.println(integers);
    }
}

2.Collection集合中元素的遍历
迭代器模式:提供了一种方法访问一个容器对象中各个元素,而不需要暴露对象的内部细节。
(1)迭代器实现集合遍历

@Test//iterator迭代器,实现集合的遍历操作。
public void test01(){
    Collection arrayList = new ArrayList();
    arrayList.add("ABC");
    arrayList.add(new String("中国"));
    arrayList.add(123);
    //① next():迭代中的下一个元素 ② hasNext():判断下一个元素是否存在
    Iterator iterator = arrayList.iterator();
    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }
}

集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前,此外,迭代器本身不存储数据,只是用于遍历集合。

(2)增强for循环实现集合遍历

@Test//增强for循环遍历集合、数组
public void test03(){
    Collection arrayList = new ArrayList();
    arrayList.add("ABC");
    arrayList.add(new String("中国"));
    arrayList.add(123);
    for(Object obj: arrayList){//实际就是将值赋值给obj后输出
        System.out.println(obj);
    }
}

3.使用迭代器删除指定的元素

@Test
public void test02(){
    Collection arrayList = new ArrayList();
    arrayList.add("ABC");
    arrayList.add(new String("中国"));
    arrayList.add(123);
    Iterator iterator = arrayList.iterator();
    while(iterator.hasNext()){
        //iterator.remove();
        Object next = iterator.next();//必须先next(),后remove(),否则会IllegalStateException
        if(next.equals("ABC")){
            iterator.remove();
        }
    }
}
二.List接口


List集合元素有序、可重复,实现了动态”数组“,线性存储,可以用于替换原有的数组。
1.ArrayList(最常用)
JDK 7下:

源码分析:ArrayList list = new ArrayList();底层是创建了长度为10的Object[] elementData数组,执行list.add(数据)时,当添加的个数超过10个,就会扩容为原来容量的1.5倍,并将原来的数据复制到新的list中。
开发建议使用带参数的构造器,指定长度:ArrayList list = new ArrayList(int Capacity);
JDK 8以后

源码分析: ArrayList list = new ArrayList();底层Object[] elementData初始化为{},当执行第一次list.add()后,才创建了长度为10的数组,后续操作和上述一样实现扩容。
List常用方法
Lis接口t继承自Collection接口,允许出现重复的元素,元素有序,可以使用索引访问,不但继承了Collection的全部方法,还增加了一些特有方法:

public class ListTest {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        List list = Arrays.asList(1, 2, 3, 5);
        //1.boolean add(object obj):向集合中添加一个元素
        arrayList.add("Hello");
        arrayList.add(111);
        arrayList.add(true);
        arrayList.add(new String("设计模式"));
        System.out.println(arrayList);
        //2.boolean addAll(Collection c):将指定的集合添加到该集合中
        arrayList.addAll(list);
        System.out.println(arrayList);
        //3.Object set(int index,Object element):修改指定索引处的元素,返回修改后的结果
        System.out.println(arrayList.set(0,"小王"));
        //4.Object get(int index):返回索引位置处的元素
        System.out.println(arrayList.get(0));
        //5.Object remove(int index):删除指定位置的元素,返回删除的元素
        //Object remove(object obj):
        System.out.println(arrayList.remove(0));
        //6.void add(int index,Object obj):在指定的位置插入元素,返回插入后的集合
        arrayList.add(0,"小吕");
        System.out.println(arrayList);
        //7.int size():返回该集合的长度
        System.out.println(arrayList.size());
        //8.List subList(int fromIndex,int toIndex):返回索引之间的子集合(左闭右开),原集合不变
		System.out.println(arrayList.subList(1,5));
		System.out.println(arrayList);
    }
}

集合三种遍历操作:

@Test
public void test01(){
    ArrayList arrayList = new ArrayList();
    arrayList.add("Hello");
    arrayList.add(111);
    arrayList.add(true);
    arrayList.add(new String("设计模式"));
    //1.iterator迭代器
    Iterator iterator = arrayList.iterator();
    while (iterator.hasNext()){
        System.out.print(iterator.next()+"t");
    }
    System.out.println();
    //2.增强for循环
    for(Object obj: arrayList){
        System.out.print(obj+"t");
    }
    System.out.println();
    //3.普通for循环
    for(int i=0;i 

2.linkedList

源码分析:linkedList linkedList = new linkedList();内部声明了Node类型的first和last属性维护一个双向循环链表,默认值为null;当执行linkedList .add(123);将123封装到Node中,创建了Node对象。
linkedList中部分常见的特有方法

public class ListTest02 {
    public static void main(String[] args) {
        linkedList linkedList = new linkedList();
        //1.void add(Object obj):添加元素
        linkedList.add("Java");
        //2.void add(int index,E element):指定位置插入指定元素
        linkedList.add(0,"设计模式");
        //3.void addFirst(Object obj):将指定元素插入集合开头
        linkedList.addFirst(123);
        //4.boolean offer(Object obj):向集合尾部追加元素
        System.out.println(linkedList.offer("offer"));//true
        //5.void push(Object obj):向集合头部追加元素
        linkedList.push(true);
        System.out.println(linkedList);//[true, 123, 设计模式, Java, offer]
        //6.Object poll():移除并返回第一个元素
        System.out.println(linkedList.poll());//true
        //7.Object peek():获取集合中的第一个元素
        Object peek = linkedList.peek();
        System.out.println(peek);//123
        System.out.println(linkedList);//[123, 设计模式, Java, offer]
        //8.Object removeFirst():删除集合中第一个元素,返回删除的元素
        System.out.println(linkedList.removeFirst());//123
        //9.Object pollLast():删除集合最后一个元素,返回删除的元素
        System.out.println(linkedList.pollLast());//offer
        System.out.println(linkedList);//[设计模式, Java]
    }
}

3.Vector
Vector线程安全,在JDK 7和JDK 8使用Vector()构造器创建时创建的数组长度为10,扩容方面扩容为原来长度的2倍。

三.Set接口


Set接口也继承自Collection接口,底层数组长度为16,但未对Collection接口中的方法进行扩充,Set接口中的元素无序,不可重复,添加对象时该对象所在的类必须重写hashCode()和equals()方法,判断两个对象相同使用equals()方法。
① 无序性:不等于随机性,存储的元素不是连续存储,而是根据hash值存储。
② 不可重复性:当向HashSet集合中添加元素时,首先会调用该元素的hashCode()方法来确定该元素的存储位置,然后再调用元素的equals()方法来确保该位置没有重复元素。

1.HashSet
作为Set的主要实现类,线程不安全,底层是数组加链表,可以存储null值。

public class HashSetTest {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(123);
        hashSet.add(true);
        hashSet.add(new String("Java"));
        hashSet.add(new User("小王", 18));
        hashSet.add(new User("小王", 18));
        Iterator iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
class User{
    private String name;
    private int age;
    public User() {
    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        System.out.println("User类的equals方法调用了...");
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age &&
                Objects.equals(name, user.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}


1.1linkedHashSet:
作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序输出,对于频繁的遍历操作,linkedHashset效率高于HashSet。

public class linkedHashSetTest {
    public static void main(String[] args) {
        linkedHashSet linkedHashSet = new linkedHashSet();
        linkedHashSet.add("Java");
        linkedHashSet.add(1234);
        linkedHashSet.add(new String("设计模式"));
        linkedHashSet.add(true);
        Iterator iterator = linkedHashSet.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+"t");
        }
    }
}


2.TreeSet
TreeSet是Set接口的一个实现类,底层采用平衡二叉树存储元素,使得TreeSet集合中不存在相同的元素,并且可以对元素加进行排序。要求向TreeSet中添加的元素必须是相同类的对象。
① 自然排序:比较两个对象是否相同的标准为: compareTo()返回0,不再是equals().

public class TreeSetTest {//TreeSet自然排序实现
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Person(18,"ALi"));
        treeSet.add(new Person(18,"Jhon"));
        treeSet.add(new Person(17,"Jack"));
        treeSet.add(new Person(19,"Tom"));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
class Person implements Comparable{
    private int age;
    private String name;
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + ''' +
                '}';
    }
    @Override
    public int compareTo(Object o) {//按age排序,年龄相同时按name排序
        if(o instanceof Person){
            Person p = (Person)o;
            int num = Integer.compare(this.age,p.age);
            if(num!=0){
                return num;
            }else{
                return this.name.compareTo(p.name);
            }
        }else
            throw new RuntimeException("输入的类型不匹配...");
    }
}


② 定制排序:比较两个对象是否相同的标准为: compare()返回0,不再是equals().

public class TreeSetTest01 {
    public static void main(String[] args) {
        Comparator comparator = new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof Animal && o2 instanceof Animal){
                    Animal o11 = (Animal) o1;
                    Animal o21 = (Animal) o2;
                    return Integer.compare(o11.getAge(),o21.getAge());//比较age,如果age相同,不再存储
                }
                throw new RuntimeException("传入的类型不匹配...");
            }
        };
        TreeSet treeSet = new TreeSet(comparator);//指定是定制排序
        treeSet.add(new Animal(18,"ALi"));
        treeSet.add(new Animal(18,"Jhon"));
        treeSet.add(new Animal(17,"Jack"));
        treeSet.add(new Animal(19,"Tom"));
        Iterator iterator = treeSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
class Animal {
    private int age;
    private String name;
    public Animal(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Animal{" +
                "age=" + age +
                ", name='" + name + ''' +
                '}';
    }
}

面试题:

1.ArrayList、linkedList、Vector三者有何异同?
相同:三者都实现了List接口,存储有序、可重复的元素,动态存储
不同:
ArrayList:List主要实现方式,底层使用Object[] elementData存储,线程不安全,效率高
linkedList:底层使用双向链表存储,对于频繁的插入、删除操作效率高
Vector:底层使用Object[] elementData存储,线程安全、效率低
2.输出下列程序的运行结果

@Test
public void test02(){
    ArrayList arrayList = new ArrayList();
    arrayList.add(1);
    arrayList.add(2);
    arrayList.add(3);
    updateList(arrayList);
    System.out.println(arrayList);
}
public void updateList(List list){
    //list.remove(2);//输出[1, 2]
	list.remove(new Integer(2));//输出[1, 3]
}

方式1是索引,删除的是索引位置的元素
方式2是元素,删除的是元素

3.输出下列程序的运行结果,解释原因

public class HashSetTest {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        Person p1 = new Person(1001, "AA");
        Person p2 = new Person(1002, "BB");
        hashSet.add(p1);
        hashSet.add(p2);
        System.out.println(hashSet);
        p1.setName("CC");
        hashSet.remove(p1);
        System.out.println(hashSet);
        hashSet.add(new Person(1001,"AA"));
        System.out.println(hashSet);
        hashSet.add(new Person(1001,"CC"));
        System.out.println(hashSet);
    }
}
class Person{
    private int id;
    private String name;
    public Person() {
    }
    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id &&
                Objects.equals(name, person.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + ''' +
                '}';
    }
}


原因:
hashSet存储时首先会判断hash值,当p1的属性修改后,remove时判断hash值时不再指向该元素,其他的也是如此。
4.去除集合中的重复元素

public class HashTest {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Integer(1001));
        arrayList.add(new Integer(1001));
        arrayList.add(new Integer(1002));
        arrayList.add(new Integer(1003));
        arrayList.add(new Integer(1003));
        List list = duplicate(arrayList);
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
    //集合元素去重
    public static List duplicate(List list){
        HashSet hashSet = new HashSet();
        hashSet.addAll(list);
        return new ArrayList(hashSet);
    }
}

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

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

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