Java学习--集合

集合

一、什么是集合

对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能

  • 和数组区别:
    • 数组长度固定,集合长度不固定
    • 数组可以存储基本类型和引用类型,集合只能存储引用类型
    • 位置:java.util.*;

Colection体系集合

在这里插入图片描述

Collection父接口

代表一组任意类型的对象,无序、无序、不能重复
在这里插入图片描述
retainAll(Collection<?> c);保留交集
第一种用法

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class asd {
    public static void main(String[] args) {
        Collection collection=new ArrayList();
        collection.add("苹果");
        collection.add("西瓜");
        System.out.println(collection);
        for (Object object:collection
             ) {
            System.out.println(object);
        }
        System.out.println(collection);
        collection.remove("苹果");
        System.out.println(collection);
        System.out.println(collection.contains("西瓜"));
        //迭代器(专门遍历集合的)

        Iterator iterator=collection.iterator();
        while(iterator.hasNext()){
            String object = (String)iterator.next();
            System.out.println(object);
            //迭代器中不能用collection的remove方法删除,会出现并发删除的错误
            //collection.remove(s);这句话是错误的
            iterator.remove();
        }
        System.out.println(collection.contains("西瓜"));
        System.out.println(collection);
        collection.clear();
        System.out.println(collection);
    }
}

第二种用法

public class asd {

    public static void main(String[] args) {
        Collection collection =new ArrayList();
        collection.add(new Student(1,"张三"));
        collection.add(new Student(2,"李四"));
        System.out.println(collection.toString());
        collection.clear()只是移出去了,并没有删除掉对象,因为集合里面存的是引用的地址。
        
    }
}

public class Student implements TestInterface {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    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 "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

List接口

有序,有下标元素可以重复
方法:
在这里插入图片描述
新的迭代器
ListIterator listIterator();比Iterator的方法多
新的remove(int index)根据下标删除
基本使用

public class asd {

    public static void main(String[] args) {
        List list=new ArrayList<>();
        list.add("苹果");
        list.add("华为");
        list.add("小米");
        System.out.println(list.size());
        System.out.println(list.toString());
        list.remove(0);
        System.out.println(list.toString());
        //遍历可以使用for ,增强for还有迭代器,还有list迭代器
        //listIterator强大的地方,它可以向前遍历或向后遍历,可以删除修改增加元素
        ListIterator listIterator=list.listIterator();
        while(listIterator.hasNext()){
            System.out.println(listIterator.nextIndex()+":"+listIterator.next());
        }
        while(listIterator.hasPrevious()){
            System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
        }
        System.out.println(list.contains("华为"));
        System.out.println(list.isEmpty());
        System.out.println(list.indexOf("华为"));
        

    }



}

输出结果
3
[苹果, 华为, 小米]
[华为, 小米]
0:华为
1:小米
1:小米
0:华为
true
false
0

第二种


public class asd {

    public static void main(String[] args) {
    List list=new ArrayList();
    //自动装箱
    list.add(20);
    list.add(30);
    list.add(40);
    list.add(50);
    list.add(60);
    list.remove(0);//或者使用list.remove((Object)20);

    System.out.println(list.toString());
        System.out.println(list.subList(1,3).toString()); ;
    }
}

List实现类
ArrayList的使用

数组结构实现,查询快,增删慢
JDK1.2 运行效率快、线程不安全。

//测试类
public class asd {

    public static void main(String[] args) {
        ArrayList arrayList=new ArrayList();
        Student s1=new Student(20,"刘德华");
        Student s2=new Student(22,"郭富城");
        Student s3=new Student(24,"大大");
        arrayList.add(s1);
        arrayList.add(s2);
        System.out.println(arrayList.size());
        System.out.println(arrayList.toString());
        arrayList.remove(s1);
        System.out.println(arrayList.size());
        arrayList.remove(new Student(20,"刘德华"));//这么写必须在Student中重写equals方法,具体方法在下面

    }
}
//学生类
public class Student implements TestInterface {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    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 "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);//返回的值的判定可以按照自己的意思来
                //改了equals之后 contains这个方法因为源码中也是用equals来比较所以改了equals的话contains也被改变了,indexOf也是,可以使用new来比较
    }

    @Override
    public int hashCode() {
        return Objects.hash(age, name);
    }
}
ArrayList源码解析

实现了list接口
静态常量:
DEFAULT_CAPACITY 默认的 容量大小,为10 ,如果没想集合中添加元素时,容量是0
elementData 存放元素的数组
size 实际的元素个数
构造方法

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//空数组
    }

add方法

  public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

add方法的解析

   private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
     private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//修改次数

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//右移一位,例如10右移一位也就是除以2等于5
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)//非常大的一个数,是Integer.MAX_VALUE-8
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

也就是每次扩容都是原来的1.5倍

Vector

数组结构实现,查询快、增删慢
JDK1.0版本,运行效率慢、线程安全
可以实现可增长的对象数组,与数组一样。
JDK1.2之后也实现了List接口
elements()枚举器

  • hasMoreElements()
  • nextElements()
public class asd {

    public static void main(String[] args) {
        Vector vector=new Vector();
        vector.add("草莓");
        vector.add("芒果");
        vector.add("西瓜");
        System.out.println(vector.size());
//        vector.remove(0);
//        vector.remove("西瓜");
//        vector.clear();
        Enumeration en=vector.elements();
        while(en.hasMoreElements()){
            String o=(String) en.nextElement();
            System.out.println(o);
        }
        System.out.println(vector.contains("西瓜"));
        System.out.println(vector.firstElement());;

    }
}

LinkedList

链表结构实现,增删快,查询慢

	transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;
st() {
    }
 public void addFirst(E e) {
        linkFirst(e);
    }

    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #add}.
     *
     * @param e the element to add
     */
    public void addLast(E e) {
        linkLast(e);
    }
     void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
    private static class Node<E> {
        E item;//当前元素,实际的数据
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
       private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
LinkList和ArrayList的区别

在这里插入图片描述

泛型

·Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作
为参数传递。

常见形式有泛型类、泛型接口、泛型方法。
语法∶
·<T,…> T称为类型占位符,表示一种引用类型。
好处∶

  • 提高代码的重用性
  • 防止类型转换异常,提高代码的安全性
//MyGeneric.java
public class MyGeneric<T> {

    //使用泛型创建变量
    T t;
    public void show(T t){
        System.out.println(t);
    }
    public T getT(){
        return t;
    }
}
//TestGeneric.java
public class TestGeneric {

    public static void main(String[] args) {
        MyGeneric<String> myGeneric =new MyGeneric<String >();
        myGeneric.t="测试";
        myGeneric.show("大家好");
        String string=myGeneric.getT();
        System.out.println(string);
    }
}

泛型接口

//MyInterfac.java
public interface MyInterface<T> {
    String name="张三";
    //不能创建的静态常量
    T service(T t);

}
//MyInterfaceImpl.java
public class MyInterfaceImpl  implements MyInterface<String> {
    @Override
    public String service(String s) {
        System.out.println(s);
        return s;
    }
}
//TestMyInterface 
public class TestMyInterface {
    public static void main(String[] args) {
        MyInterface<String> myInterface=new MyInterfaceImpl();
        myInterface.service("测试");
    }
}

泛型方法

public class MyGenericMethod {
    public <T> T show(T t) {
        System.out.println(t);
        System.out.println("泛型方法");
        return t;
    }
}

泛型的好处就是可以将重载简化了,不用写特别多的重载

泛型集合

·概念∶参数化类型、类型安全的集合,强制集合元素的类型必须一致。
·
特点∶
·编译时即可检查,而非运行时抛出异常。
访问时,不必类型转换(拆箱)。

不同泛型之间引用不能相互赋值,泛型不存在多态。

在这里插入图片描述

Set集合

特点:无序、无下标、元素不可重复
方法:全部继承自Collection继承过来的方法
不包含重复元素的Collection

  • HashSet【重点】∶
    基于HashCode实现元素不重复。
当存入元素的哈希码相同时,会调用==或equals进行确认,结果为true,拒绝后者存入。。
  • LinkedHashSet:
·链表实现的HashSet,按照链表进行存储,即可保留元素的插入顺序。
  • TreeSet:
·基于排列顺序实现元素不重复。
·实现了SortedSet接口,对集合元素自动排序。
·元素对象的类型必须实现Comparable接口,指定排序规则。·通过CompareTo方法确定是否为重复元素。

public class Demo1 {
    public static void main(String[] args) {
        Set<String> strings=new HashSet<>();
        strings.add("华为");
        strings.add("小米");
        strings.add("苹果");
        strings.add("小米");
        System.out.println(strings.size());
        System.out.println(strings.toString());
        strings.remove("小米");
        System.out.println(strings);
        //遍历 1.增强for 2.迭代器
        for (String s:strings){
            System.out.println(s);
        }
        Iterator<String> it=strings.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println(strings.contains("华为"));

    }
}

输出
3
[苹果, 华为, 小米]
[苹果, 华为]
苹果
华为
苹果
华为
true

Process finished with exit code 0

HashSet

存储结构是哈希表

  • 基于HashCode实现元素不重复。
  • 当存入元素的哈希码相同时,会调用==或equals进行确认,结果为true,拒绝后者存入。。
public class Demo1 {
    public static void main(String[] args) {
        HashSet<String> hashSet=new HashSet<String>();
        hashSet.add("天");
        hashSet.add("地");
        hashSet.add("云");
        hashSet.add("月");
        hashSet.add("月");
        System.out.println(hashSet.size());
        System.out.println(hashSet.toString());
        hashSet.remove("云");
        System.out.println(hashSet);
        //遍历1.增强for 2.Iterator
        Iterator iterator=hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

输出结果:
4
[地, 云, 月, 天]
[地, 月, 天]


HashCode的存储过程

  1. hashcode计算保存的位置,如果位置为空,则直接保存,若是不为空执行第二步
  2. 在执行equals方法,如果equals为true认为是同一个元素,否则形成链表。

可以重写equals和hashcode方法来达到对象属性的比较

TreeSet(红黑树)

特点:

  • 基于排列顺序实现元素不重复
  • 实现了SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • 通过CompareTo方法确定是否为重复元素
public class Demo1 {
    public static void main(String[] args) {
        TreeSet<String> treeSet=new TreeSet<>();
        treeSet.add("xyz");
        treeSet.add("abc");
        treeSet.add("hello");
        System.out.println(treeSet.size());
        System.out.println(treeSet.toString());
        treeSet.remove("hello");
        System.out.println(treeSet.toString());
    }
}

3
[abc, hello, xyz]
[abc, xyz]

。TreeSet比较的规则,要实现Comparable接口

package com.city.test;

public class Person implements Comparable<Person>{
    int age;
    String 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 int compareTo(Person o) {
        int n1=this.getAge()-o.getAge();
        int name=this.getName().compareTo(o.getName());
        return name==0?n1:name;
        //先按姓名后按年龄

    }
}
//如上代码写完后才可以将person放进treeset中

或者通过为TreeSet直接实现定制比较(比较器)Comparator

//运用了匿名内部类的方式实现
public class Demo1 {
    public static void main(String[] args) {
        TreeSet<Person> people=new TreeSet<>(new Comparator<Person>(){

            @Override
            public int compare(Person o1, Person o2) {
                int age=o1.getAge()-o2.getAge();
                int name=o1.getName().compareTo(o2.getName());
                return age==0?name:age;
            }
        });

    }
}

Map体系集合

在这里插入图片描述

方法

在这里插入图片描述
boolean containKey(Object Key);
boolean containValue(Object value);
Set<Map.Entry<K,V>> EntrySet()
Set keySet();

package com.city.test;

import java.util.*;

public class Demo1 {
    public static void main(String[] args) {
         //创建Map集合
        Map<String ,String> map=new HashMap<>();
        map.put("cn","中国");
        map.put("UK","英国");
        map.put("USA","美国");
        System.out.println(map.toString());
        map.remove("USA");
        System.out.println(map.toString());
        //遍历 1.keySet() 返回值是key的Set集合 2.EntrySet()方法
        Set<String> set=map.keySet();
        for (String key: set
             ) {
            System.out.println(key+map.get(key));
        }
        Set<Map.Entry<String,String>> entries=map.entrySet();
        for (Map.Entry<String,String> entry: entries
             ) {
            System.out.println(entry.getValue());
            System.out.println(entry.getKey());
        }
    }
}

Map集合的实现类

在这里插入图片描述

HashMap

构造一个具有默认初始容量(16)和默认加载因子(0.75)的空HashMap
//加载因子就是当达到最大容量的百分之75就扩容

源码分析

DEFAULT_INITIAL_CAPACITY 默认初始容量大小 1<< 4 ,是在添加第一个元素之后变大,为了节省空间
MAXIMUM_CAPACITY //最大的容量大小 1<<30
DEFAULT_LOAD_FACTOR 加载因子 0.75f,之后每次调整2倍
TREEIFY_THRESHOLD 默认为8 当链表的长度大于8的时候 并且数组的长度大于等于64,把链表编程红黑树。
UNTREEIFY_THRESHOLD 默认值为6 小于6没必要成为红黑树,就变成链表
table 哈希数组

public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
  static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)//计算位置用的,产生哈希值用的
    }
  • HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16.
  • 当元素个数大于阈值(16*0.78=12)时,会进行扩容,扩容后大小为原来的2倍,目的是减少调整元素的个数。
  • jdk1.8,当每个链表长度大于8,并且元素个数大于等于64时,会调整为红黑树,目的是为了提供执行效率
  • jdk、1.8 当链表长度小于6时调整为链表
  • jdk1.8以前,链表时头插入,jdk1.8为尾插入
  • hashset 创建的时hashmap,用Key来保存数据
binarySearch

二分查找,需要先排序才可以二分查找

copy

赋值,第一个参数是目标,第二个是数据,要求两个大小必须一样,可以先给目标集合赋值0或者对应的类型,是因为集合只有在有第一个值之后才会有大小

toArray()

list.toArray(new Integer[0]);

asList

Arrays.asList();
将数组变为集合,所转成的集合是受限的集合,不能添加和删除
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值