java集合

集合

集合分类

集合分为Collection和Map(接口)
Collection:单列集合,每次添加一个元素
Map:键值对集合,每次添加一对元素(key–>value)

Colection分为List和Set(类)
List:[有序,不唯一]
Set:[无序,唯一]

List集合分为
      ArrayList
      LinkedList(链表结构)
Set集合分为
      HashSet(哈希表结构)
         LinkedHashSet(链表、哈希表结构)
      TreeSet(树结构)

Map集合分为HashMap和TreeMap(类)
      HashMap(哈希表结构)
         LinkedHashMap(链表、哈希表结构)
      TreeMap(树结构)

Collection

Collection是最基本集合接口,它定义了一组允许重复的对象。Collection接口派生了两个子接口Set和List
Collection接口中的方法是集合中所有实现类必须拥有的方法

  • boolean add(Object e):向集合中添加一个元素
  • boolean remove(Object o):删除该集合中指定的元素元素
  • void clear():清空集合
  • boolean contains(Object o):判断集合中是否包含某个元素
  • boolean isEmpty():判断集合是否为空
  • int size():获取集合内元素的数量
boolean add(Object e):向集合中添加一个元素
public class Test {
    public static void main(String[] args) {
        //因为Collection是接口,所以调用其具体实现类
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("c");
        c.add("d");
        System.out.println(c);
        //输出:[a, b, c, d]
    }
}
boolean remove(Object o):删除该集合中指定的元素元素
public class Test {
    public static void main(String[] args) {
        //因为Collection是接口,所以调用其具体实现类
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("c");
        c.add("d");

        c.remove("c");
        c.remove("d");
        System.out.println(c);
        //输出:[a, b]
    }
}
void clear():清空集合
public class Test {
    public static void main(String[] args) {
        //因为Collection是接口,所以调用其具体实现类
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("c");
        c.add("d");

        c.clear();
        System.out.println(c);
        //输出:[]
    }
}
boolean contains(Object o):判断集合中是否包含某个元素
    public static void main(String[] args) {
        //因为Collection是接口,所以调用其具体实现类
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("c");
        c.add("d");
        
        System.out.println(c.contains("c"));
        //输出:true
    }
}
boolean isEmpty():判断集合是否为空
public class Test {
    public static void main(String[] args) {
        //因为Collection是接口,所以调用其具体实现类
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("c");
        c.add("d");

        System.out.println(c.isEmpty());
        //输出:false
    }
}
int size():获取集合内元素的数量
    public static void main(String[] args) {
        //因为Collection是接口,所以调用其具体实现类
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("c");
        c.add("d");

        System.out.println(c.size());
        //输出:4
    }
}
Collection遍历方式

Collection遍历方式
1.将结合转成数组
2.使用迭代器
3.增强for

使用数组toArray():返回包含此Collection中所有元素的数组

使用toArray()方法,将集合转成数组,之后使用for循环遍历数组取值即可

public class Test {
    public static void main(String[] args) {
        Collection list = new ArrayList();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("赵六");
        list.add(10);// 自动装箱int-->Integer
        list.add(3.14);// 自动装箱double-->Double

        // 获取Object[]数组
        Object[] objArray = list.toArray();
        for (int i = 0; i < objArray.length; i++) {
            System.out.println(objArray[i]);
        }
    }
}

结果:

张三
李四
王五
赵六
10
3.14
迭代器Iterator

在Java中,有很多的数据容器,对于这些的操作有很多的共性。Java采用了迭代器来为各种容器提供了公共的操作接口。这样使得对容器的遍历操作与其具体的底层实现相隔离,达到解耦的效果。

迭代器中的方法:

  • hasNext():如果任有元素可以迭代,则返回true
  • next():返回迭代的下一个元素
  • remove():从迭代器指向的collection中移除迭代器返回的最后一个元素

Collection获取迭代器方法

iterator():返回在此collection的元素上进行迭代的迭代器

public class Test {
    public static void main(String[] args) {
        Collection list = new ArrayList();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("赵六");
        list.add(10);// 自动装箱int-->Integer
        list.add(3.14);// 自动装箱double-->Double

        //使用迭代器
        Iterator it = list.iterator();

        while (it.hasNext()) {//如果有下一个元素,那么继续取值
            System.out.println(it.next());
        }
    }
}

结果:

张三
李四
王五
赵六
10
3.14
增强for

foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本
foreach的语句格式:

for(元素类型 元素变量名 : 遍历对象){
      使用元素变量进行操作
}

优点:
1.简化编程操作
2.提高代码安全性(越界异常)
缺点:
1.无法对索引进行操作

public class Test {
    public static void main(String[] args) {

        Collection list = new ArrayList();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("赵六");

        // 增强for
        for (Object o : list) {
            System.out.println(o);
        }
    }
}

结果:

张三
李四
王五
赵六

List

List所代表的是有序的Collection,即它用某种特定的插入顺序来"维护元素顺序"。
List是有序集合(序列),用户可以精准控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
与Set不同,列表通常允许重复的元素
继承至Collection< E >

List集合特点
有序:存储和取出的元素顺序一致
可重复:存储的元素可以重复

List功能

继承自Collection的功能

List特有功能
  • void add(int index, E element):在列表的指定位置插入指定的元素
  • E get(int index):返回列表中指定位置的元素
  • E remove(int index):移除列表中指定位置的元素
  • E set(int index, E element):用指定元素替换列表中指定位置的元素
void add(int index, E element):在列表的指定位置插入指定的元素
public class Test {
    public static void main(String[] args) {
        // 实例化一个List
        List list = new ArrayList();
        // 填充集合
        list.add("aaa");// Collection
        list.add("bbb");// Collection
        list.add("ccc");// Collection
        System.out.println(list);
        //输出:[aaa, bbb, ccc]
    }
}
E get(int index):返回列表中指定位置的元素
public class Test {
    public static void main(String[] args) {
        // 实例化一个List
        List list = new ArrayList();
        // 填充集合
        list.add("aaa");// Collection
        list.add("bbb");// Collection
        list.add("ccc");// Collection

        System.out.println(list.get(2));
        //输出:ccc
    }
}
E remove(int index):移除列表中指定位置的元素
public class Test {
    public static void main(String[] args) {
        // 实例化一个List
        List list = new ArrayList();
        // 填充集合
        list.add("aaa");// Collection
        list.add("bbb");// Collection
        list.add("ccc");// Collection

        list.remove(2);

        System.out.println(list);
        //输出:[aaa, bbb]
    }
}
E set(int index, E element):用指定元素替换列表中指定位置的元素
public class Test {
    public static void main(String[] args) {
        // 实例化一个List
        List list = new ArrayList();
        // 填充集合
        list.add("aaa");// Collection
        list.add("bbb");// Collection
        list.add("ccc");// Collection

        list.set(2,"ddd");

        System.out.println(list);
        //输出:[aaa, bbb, ddd]
    }
}
List的特有遍历功能

List基础自Collection接口,所以也继承了父接口的两个变量方式

1.toArray() 转数组
2.iterator() 迭代器

除此之外,List还新增了一种迭代器方式

ListIterator listIterator()
ListIterator是Iterator的子接口;它继承了Iterator的所有方法;

另外还新增了几个方法:

1.E previous():返回列表中的前一个元素;
2.boolean hasPrevious():判断是否有前一个元素;

特点

1.Iterator:单项的,只能向下遍历;
2.ListIterator:双向的;可以向下遍历,也可以向上遍历;

注意:ListIterator只适用于List集合
演示:

public class Test {
    public static void main(String[] args) {
        // 1.实例化一个集合
        List list = new ArrayList();
        // 2.填充集合
        list.add(new Student("张三", 20));
        list.add(new Student("李四", 22));
        list.add(new Student("王五", 24));
        list.add(new Student("赵六", 26));

        // 3.遍历集合
        // 遍历方式一:ListIterator()
        System.out.println("向后遍历:");
        ListIterator listIt = list.listIterator();
        while (listIt.hasNext()) {
            System.out.println(listIt.next());
        }

        System.out.println("向前遍历:");
        while (listIt.hasPrevious()) {
            System.out.println(listIt.previous());
        }

        System.out.println("-----------------------");

        // 遍历方式二:结合Collection的size(),和本接口的get(int index)方法,可以使用for循环遍历;
        System.out.println("size()、get() 配合for循环");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

class Student {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

结果:

向后遍历:
Student{name='张三', age=20}
Student{name='李四', age=22}
Student{name='王五', age=24}
Student{name='赵六', age=26}
向前遍历:
Student{name='赵六', age=26}
Student{name='王五', age=24}
Student{name='李四', age=22}
Student{name='张三', age=20}
-----------------------
size()get() 配合for循环
Student{name='张三', age=20}
Student{name='李四', age=22}
Student{name='王五', age=24}
Student{name='赵六', age=26}
ArrayList

ArrayList是List接口的一个实现类,它是程序中最常见的一种集合,内部封装了一个长度可变的数组对象,当存入的元素超过数组长度时,ArrayList会在内存中分配一个更大的数组来存储这些元素。因此ArrayList集合看做一个长度可变的数组

特点:
1.底层数据结构是数组,随机访问速度快(根据索引访问),插入和移除较慢。
2.插入的数据有顺序,元素可以重复
3.线程不安全,效率高。

为什么效率低?
1.数组结构的优点是便于对集合进行快速的随机访问,如果经常需要根据索引位置访问集合中的对象,使用由ArrayList类实现的List集合的效率较好。
2.数组结构的缺点:在向指定索引位置插入、删除指定对象效率较慢,如果经常需要向List集合的指定索引位置插入或删除对象,那么使用由ArrayList类实现的List集合的效率则较低,并且插入、删除对象的索引位置越小效率越低,原因是当向指定的索引位置插入对象时,会同时将指定索引位置及之后的所有对象相应的向后移动一位。

ArrayList创建集合

1.ArrayList list = new ArrayList();
2.ArrayList<泛型> list = new ArrayList<>();

泛型在后

ArrayList list = new ArrayList(int 数组容量);
默认开辟10块空间
集合无论底层开辟多少块空间 都可以装无数个元素
集合会自动的扩容

ArrayList用法

与List用法一样

LinkedList

ArrayList 集合在查询元素时速度很快,但在删除时效率较低,为了克服这种局限性,可以使用LinkedList。
LinkedList内部维护了一个双向循环链表,链表中的每一个元素彼此相连起来。插入和删除元素只需要修改元素之间的应用关系即可。
特点:

1.增删效率很高
2.查询效率低

LinkedList特有功能

因为是链表结构,所以LinkedList提供了一些首尾操作的方法

  • public void addFirst(E e) 在该列表开头插入指定的元素
  • public void addLast(E e) 将指定的元素追加到此列表的末尾
  • public E getFirst() 返回此列表中的第一个元素
  • public E getLast() 返回此列表中的最后一个元素
  • public int lastIndexOf(Object o)返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回-1
  • public ListIterator< E > listIterator(int index)返回此列表中的元素的列表迭代器(按适当顺序),从列表中指定位置开始
  • public E removeFirst 从列表中删除并返回第一个元素
  • public E removeLast 从此列表中删除并返回最后一个元素
public void addFirst(E e) 在该列表开头插入指定的元素
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //[a, b, c, d]

        list.addFirst("5");
        System.out.println(list);
        //输出:[5, a, b, c, d]
    }
}
public void addLast(E e) 将指定的元素追加到此列表的末尾
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //[a, b, c, d]

        list.addLast("5");
        System.out.println(list);
        //输出:[a, b, c, d, 5]
    }
}
public E getFirst() 返回此列表中的第一个元素
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //[a, b, c, d]

        System.out.println(list.getFirst());
        //输出:a
    }
}
public E getLast() 返回此列表中的最后一个元素
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //[a, b, c, d]

        System.out.println(list.getLast());
        //输出:d
    }
}
public int lastIndexOf(Object o)返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回-1
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("d");
        list.add("c");
        list.add("b");
        list.add("a");
        //[a, b, c, d, d , c , b , a]

        System.out.println(list.lastIndexOf("c"));
        System.out.println(list.lastIndexOf("e"));
        //输出:5
        //    -1
    }
}
public ListIterator< E > listIterator(int index)返回此列表中的元素的列表迭代器(按适当顺序),从列表中指定位置开始
public ListIterator<E> listIterator() {
        return new ListItr(0);
    }
public E removeFirst 从列表中删除并返回第一个元素
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //[a, b, c, d]

        System.out.println(list.removeFirst());
        System.out.println(list);
        //输出:a
        //输出:[b, c, d]
    }
}
public E removeLast 从此列表中删除并返回最后一个元素
public class Test {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //[a, b, c, d]

        System.out.println(list.removeLast());
        System.out.println(list);
        //输出:d
        //输出:[a, b, c]
    }
}

Set

Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素,而且Set接口中元素无序。

Set集合特点

不包含重复元素的集合
没有带索引的方法,所以不能使用普通for循环遍历

public class Test {
    public static void main(String[] args) {
        // 实例化一个Set对象
        Collection<String> set = new HashSet<>();
        // 填充元素
        set.add("aaa");
        set.add("bbb");
        set.add("ccc");
        set.add("ddd");
        // 存储重复元素
        String s1 = new String("ccc");
        String s2 = new String("ddd");
        set.add(s1);// 添加失败
        set.add(s2);// 添加失败
        set.add("eee");

        // 遍历
        // 1.toArray()
        // 2.iterator();
        // 3.增强for;
        for (String s : set) {
            System.out.println(s);// 取出时,跟存入的顺序不同;
        }
    }
}

结果:

aaa
ccc
bbb
eee
ddd
HashSet

对集合的迭代顺序不作任何保证

HashSet存储自定义对象

当向HashSet集合中添加一个对象时,首先会调用该对象的hashCode() 方法来确定元素的存储位置,然后再调用对象的equals() 方法来确定该位置有没有重复元素。

特点:不包含重复元素,自定义的类必须重写hashCode、equals方法
IDEA可以用快捷键Alt + insert 快速生成

public class Test {
    public static void main(String[] args) {
        HashSet<String> hs = new HashSet<String>();
        hs.add("hello");
        hs.add("world");
        hs.add("java");
        //添加重复项
        hs.add("java");
        //遍历取出,会和存放顺序不同
        for (String s : hs) {
            System.out.println(s);
        }
    }
}

结果:

world
java
hello
public class Test {
    public static void main(String[] args) {
        // 实例化一个Set
        Set<Student> stuSet = new HashSet<>();
        // 填充元素
        stuSet.add(new Student("张三", 20));
        stuSet.add(new Student("李四", 22));
        stuSet.add(new Student("王五", 24));
        stuSet.add(new Student("赵六", 26));
        // 添加重复元素
        stuSet.add(new Student("赵六", 26));

        // 遍历
        for (Student stu : stuSet) {
            System.out.println(stu.name + "  " + stu.age);// 取出时,跟存入的顺序不同;
        }
    }
}

class Student {
    String name;
    int age;

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

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

结果:

李四  22
王五  24
张三  20
赵六  26
LinkedHashSet

LinkedHashSet是一个特例集合,元素存取有序,使用链表维护元素的顺序,这样使得元素看起来是以插入的顺序保存的,取出时会按照元素的添加顺序来访问集合里的元素。

public class Test {
    public static void main(String[] args) {
        // 实例化一个LinkedHashSet
        LinkedHashSet<String> strSet = new LinkedHashSet<>();
        // 填充集合
        strSet.add("张三");
        strSet.add("李四");
        strSet.add("王五");
        strSet.add("赵六");
        // 遍历
        for (String s : strSet) {
            System.out.println(s);// 存取有序的;
        }
    }
}

结果:

张三
李四
王五
赵六
TreeSet

TreeSet因为实现了Set接口,所以其集合特点是:元素不重复。TreeSet 里面存放的元素是按照元素的自然顺序来排列的

public class Test {
    public static void main(String[] args) {
        // 实例化一个TreeSet
        TreeSet<String> strSet = new TreeSet<>();
        // 填充集合
        strSet.add("ddd");
        strSet.add("aaa");
        strSet.add("xxx");
        strSet.add("ccc");
        strSet.add("bbb");
        strSet.add("yyy");
        strSet.add("fff");

        // 遍历
        for(String s : strSet){
            System.out.println(s);
        }
    }
}

结果:

aaa
bbb
ccc
ddd
fff
xxx
yyy

自然排序原因:
TreeSet内部采用平衡二叉树来存储元素,这样的结构可以保证TreeSet集合中没有重复的元素,并且可以对元素进行排序,其保证元素唯一性是通过元素的compareTo方法的返回值来确定

自然排序(Comparable)接口

TreeSet在进行数据存储时,都会对该对象进行排序,但是集合不知道该以什么样的方式进行排序,所以自定义类中需要实现Comparable接口,并在compareTo方法内实现排序比较。该方法用来比较元素的大小关系,然后将集合元素按照升序排列。

compareTo(T o) 方法
将此对象与指定的对象进行比较,以返回一个负整数、零或一个正整数,因为这个对象小于、等于或大于指定的对象。
参数 : o要比较的对象。
结果 : 一个负整数,零,或一个正整数,因为这个对象小于,等于,或大于指定的对象。

注意:只要放在TreeSet中的元素对象,在该对象的类中必须实现Comparable接口,必须覆盖该接口中的compareTo()方法,并在该方法中编写比较规则。

public class Test {
    public static void main(String[] args) {
        TreeSet<Student> stuSet = new TreeSet<>();
        stuSet.add(new Student("张三", 20));// TreeSet的add()方法中,自动调用元素的compareTo()方法
        stuSet.add(new Student("李四", 22));
        stuSet.add(new Student("王五", 24));
        stuSet.add(new Student("赵六", 22));
        stuSet.add(new Student("赵六", 25));
        // 遍历
        for (Student stu : stuSet) {
            System.out.println(stu.name + "," + stu.age);
        }
    }
}

//学生类
class Student implements Comparable<Student> {
    String name;
    int age;

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

    @Override
    public int compareTo(Student o) {
//        System.out.println("this.name = " + this.name + " o.name = " + o.name);
        //1.先按姓名排序
        int n1 = this.name.compareTo(o.name);
        //2.如果姓名相同,按年龄排序
        int n2 = (n1 == 0 ? this.age - o.age : n1);
        return n2;
    }
}

结果:

张三,20
李四,22
王五,24
赵六,22
赵六,25
Comparator通过构造方法传入排序比较器

比较器排序,也叫定制排序通过使用该比较器,比较时需要创建第三方类,实现Comparator接口,并且覆盖其中的compare()方法,编写比较规则和排序方式。

方法int compare(T o1, T o2)
比较其两个顺序的参数。返回一个负整数、零或一个正整数作为第一个参数小于、等于或大于第二个参数。

比较器通过构造方法传入

public class Test {
    public static void main(String[] args) {
        // 实例化一个TreeSet
        TreeSet<Student> stuSet = new TreeSet<>(new MyComparator());
        stuSet.add(new Student("李四", 20));
        stuSet.add(new Student("张三", 22));
        stuSet.add(new Student("张三", 26));
        stuSet.add(new Student("王五", 24));

        for (Student stu : stuSet) {
            System.out.println(stu.name + "," + stu.age);
        }
    }
}

//排序比较器
class MyComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
//        System.out.println("o1.name = " + o1.name + " o2.name = " + o2.name);
        // 先按姓名比
        int n1 = o1.name.compareTo(o2.name);
        // 如果姓名相同,比较年龄
        int n2 = (n1 == 0 ? o1.age - o2.age : n1);
        return n2;
    }
}

//学生类
class Student {
    String name;
    int age;

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

结果:

张三,22
张三,26
李四,20
王五,24

总结

1.当向TreeSet里面添加不是自定义对象时,元素会默认使用自然排序输出从小到大序列。(因为Java提供的对象实现了比较的接口)
2.当向TreeSet里面添加自定义的对象时,可以使用这2种比较方式进行比较,效果上没有区别。

Map

Map接口概述

Map接口是双列集合,它的每个元素都包含一个键对象(key)和一个值对象(value),对象之间存在一种对应关系,称为映射。
访问元素时,只要指定了key就能找到对应的value。
将键映射到值的对象,一个映射不能包含重复的键,每个键最多指引映射到一个值
取出顺序和存储顺序相反
Map 子类

HashMap:哈希表结构
LinkedHashMap:链表、哈希表结构
TreeMap:树结构

以上Map接口的各种"数据结构"全部是针对"键"有效,跟"值"无关;

HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

TreeMap<K,V>:二叉树原理保证键唯一,键是可按照指定顺序排序的

注意:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。

Map基本功能
  • V put(K Key,V value) 添加元素
  • V remove(Object key) 根据键删除键值对元素
  • void clear() 移除所有的键值对元素
  • boolean containsKey(Object key) 判断集合是否包含指定的键
  • boolean containsValue(Object value) 判断集合是否包含指定的值
  • boolean isEmpty() 判断集合是否为空
  • int size() 集合的长度,也就是集合中键值对的个数
V put(K Key,V value) 添加元素
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map);
    }
}

结果:

{杨过=小龙女, 郭靖=黄蓉, 张无忌=赵敏}
V remove(Object key) 根据键删除键值对元素
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map.remove("郭靖"));
        System.out.println(map.remove("郭襄"));//null
        System.out.println(map);
    }
}

结果:

黄蓉
null
{杨过=小龙女, 张无忌=赵敏}
void clear() 移除所有的键值对元素
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        map.clear();
        System.out.println(map);
    }
}

结果:

{}
boolean containsKey(Object key) 判断集合是否包含指定的键
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map.containsKey("杨过"));
        System.out.println(map.containsKey("杨康"));//false
    }
}

结果:

true
false
boolean containsValue(Object value) 判断集合是否包含指定的值
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map.containsValue("小龙女"));
        System.out.println(map.containsValue("周芷若"));//false
    }
}

结果:

true
false
boolean isEmpty() 判断集合是否为空
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map.isEmpty());
    }
}

结果:

false
nt size() 集合的长度,也就是集合中键值对的个数
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map.size());;
    }
}

结果:

3
Map集合获取功能
  • V get(Object key) 根据键获取值
  • Set < K > keySet() 获取所有键的集合
  • Collection < V > values 获取所有值的集合
V get(Object key) 根据键获取值
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");
        
        System.out.println(map.get("张无忌"));
        System.out.println(map.get("张三丰"));//null
    }
}

结果:

赵敏
null
SetkeySet() 获取所有键的集合
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");

		Set<String> keySet = map.keySet();
//        System.out.println(keySet);
        for (String key:keySet){
            System.out.println(key);
        }
    }
}

结果:

杨过
郭靖
张无忌
Collectionvalues 获取所有值的集合
public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new HashMap<String, String>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");

		Collection<String> values = map.values();
        for (String s : values) {
            System.out.println(s);
        }
    }
}

结果:

小龙女
黄蓉
赵敏
Entry键值对对象

在Map类设计时,提供了一个嵌套接口:Entry。
Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。
Entry是Map接口中提供的一个静态内部嵌套接口。

getKey()方法:获取Entry对象中的键
              K getKey() :返回与此项对应的键

getValue()方法:获取Entry对象中的值
               V getValue() :返回与此项对应的值

entrySet()方法:用于返回Map集合中所有的键值对(Entry)对象,以Set集合形式返回。
               (Set<Map.Entry<K.V>> entrySet() :返回此映射中包含此映射关系的set视图

Entry应用:Map集合遍历键值对方式
键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

操作步骤:
1.获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。
2.遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象
3.通过键值对(Entry)对象,获取Entry对象中的键与值。

案例:

public class Test {
    public static void main(String[] args) {
        // 创建Map对象
        Map<String, String> map = new HashMap<String, String>();
        // 给map中添加元素
        map.put("111", "王五");
        map.put("112", "李四");
        map.put("113", "赵六");
        map.put("114", "田七");
        //获取Map中的所有key与value的对应关系
        Set<Map.Entry<String,String>> entrySet = map.entrySet();
        //遍历Set集合
        Iterator<Map.Entry<String,String>> it =entrySet.iterator();
        while(it.hasNext()){
            //得到每一对对应关系
            Map.Entry<String,String> entry = it.next();
            //通过每一对对应关系获取对应的key
            String key = entry.getKey();
            //通过每一对对应关系获取对应的value
            String value = entry.getValue();
            System.out.println(key+"="+value);
        }
        //获取键值对集合
        //Set<Entry<String, String>> entrySet = map.entrySet();

        //增强for循环输出键值对
        //for (Entry<String, String> entry : entrySet) {
        //	System.out.println(entry.getKey() + " = " + entry.getValue());
        //}
    }
}

结果:

111=王五
112=李四
113=赵六
114=田七

注意:Map集合不能直接使用迭代器或者foreach进行遍历。但是转成Set之后就可以使用了。

HashMap

HashMap方法

参上Map方法

HashMap存储自定义类型键值

案例:

/**
 * 练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。
 * 注意,学生姓名相同并且年龄相同视为同一名学生。
 */
public class Test {
    public static void main(String[] args) {
        // 1. 创建hashmap集合对象。
        Map<Student, String> map = new HashMap<Student, String>();
        // 2. 添加元素。
        map.put(new Student("李四", 28), "上海");
        map.put(new Student("王五", 22), "北京");
        map.put(new Student("赵六", 24), "成都");
        map.put(new Student("田七", 25), "广州");
        map.put(new Student("张三", 22), "南京");

        // 3. 取出元素。键找值方式
        Set<Student> keySet = map.keySet();
        for (Student key : keySet) {
            String value = map.get(key);
            System.out.println(key.toString() + "....." + value);
        }
        System.out.println("---------------------------");
        // 3. 取出元素。键值对方式
        Set<Map.Entry<Student, String>> entrySet = map.entrySet();
        for (Map.Entry<Student, String> entry : entrySet) {
            Student key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key.toString() + "....." + value);
        }
    }
}

class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

结果:

Student{name='赵六', age=24}.....成都
Student{name='李四', age=28}.....上海
Student{name='田七', age=25}.....广州
Student{name='王五', age=22}.....北京
Student{name='张三', age=22}.....南京
---------------------------
Student{name='赵六', age=24}.....成都
Student{name='李四', age=28}.....上海
Student{name='田七', age=25}.....广州
Student{name='王五', age=22}.....北京
Student{name='张三', age=22}.....南京

当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。

如果要保证map中存放的key和取出的顺序一致,可以使用LinkedHashMap集合来存放。

LinkedHashMap

保证map中存放的key和取出的顺序一致

public class Test {
    public static void main(String[] args) {
        //创建集合对象
        Map<String, String> map = new LinkedHashMap<>();
        //添加元素
        map.put("张无忌", "赵敏");
        map.put("郭靖", "黄蓉");
        map.put("杨过", "小龙女");

        System.out.println(map);
    }
}

结果:

{张无忌=赵敏, 郭靖=黄蓉, 杨过=小龙女}

TreeMap

二叉树原理保证键唯一,键是可按照指定顺序排序的

1.使用TreeMap会对"键"进行排序;
2.所以,作为"键"的对象,必须实现两种比较的方式之一

public class Test {
    public static void main(String[] args) {
        //1.实例化一个TreeMap
        TreeMap<String,String> map = new TreeMap<>();
        //2.填充集合
        map.put("004", "张三");
        map.put("002", "李四");
        map.put("001", "王五");
        map.put("003", "赵六");

        //3.遍历
        Set<String> keys = map.keySet();
        for(String key : keys){
            System.out.println(key + "," + map.get(key));
        }
    }
}

结果:

001,王五
002,李四
003,赵六
004,张三

补充

泛型

泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数类型。

泛型类

定义泛型类在"类名"后添加一对<>,里面定义"泛型名称";
格式:如ArrayList集合

class ArrayList< E > {
     public boolean add(E e) { }
     public E get(int index) { }
}

使用泛型类:创建对象时,确定泛型的类型
例如:ArrayList< String > list = new ArrayList< String >(); 此时相当于将E的类型替换为String类型。
例如:ArrayList< Integer > list = new ArrayList< Integer >(); 此时相当于将E的类型替换为Integer类型。

/*
   泛型类定义格式
             格式:修饰符 class 类名<类型> {}
             范例:public class Generic<T>{}
                  此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
 */
public class Test {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("张三");
        System.out.println(s.getName());
        Teacher t = new Teacher();
        t.setAge(30);
//        t.setAge("30");
        System.out.println(t.getAge());

        System.out.println("--------------");

        Generic<String>g1=new Generic<String>();
        g1.setT("张三");
        System.out.println(g1.getT());
        Generic<Integer>g2=new Generic<Integer>();
        g2.setT(18);
        System.out.println(g2.getT());

    }
}

class Student {
    private String name;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class Teacher {
    private Integer age;

    public Teacher() {
    }

    public Teacher(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
class Generic<T>{
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

结果:

张三
30
--------------
赵四
18
泛型方法
方法格式:
/**
	 * <T> 声明此方法持有一个类型T,也可以理解此方法为泛型方法
	 * T 返回值类型(入参类型是什么类型此返回值就是什么类型)
	 * @param t1 泛型参数
	 * @param t2 泛型参数
	 */
	public static <T> T m1(T t1) {
		return t1;
	}
详细介绍
/**
 * 泛型方法的详细介绍
 * @param value 传入的泛型实参
 * @return T 返回值为T类型
 * 说明:
 *     1. public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
 *     2. 只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
 *     3. <T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
 *     4. 与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
 */
public <T> T genericMethod(T value)throws InstantiationException ,
        IllegalAccessException{
    return value;
}

示例:

/*
    泛型方法定义格式:
           格式:修饰符 <类型> 返回值类型 方法名(类型 变量名){}
           范例:public <T> void show(T t){}
 */
public class Test {
    public static void main(String[] args) {
        //        Generic g = new Generic();
//        g.show("张三");
//        g.show(18);
//        g.show(true);
//        g.show(13.14);

//        Generic<String> g1 = new Generic<String>();
//        g1.show("赵四");
//        Generic<Integer> g2 = new Generic<Integer>();
//        g2.show(18);
//        Generic<Boolean> g3 = new Generic<Boolean>();
//        g3.show(true);

        Generic g=new Generic();
        g.show("张三");//String
        g.show(18);//int
        g.show(true);//boolean
        g.show(13.14);//double

    }
}

//class Generic {
//    public void show(String s) {
//        System.out.println(s);
//    }
//
//    public void show(Integer i) {
//        System.out.println(i);
//    }
//
//    public void show(Boolean b) {
//        System.out.println(b);
//    }
//}

//泛型类改进
//class Generic<T> {
//    public void show(T t) {
//        System.out.println(t);
//    }
//}

//泛型方法改进
class Generic {
    public <T> void show(T t) {
        System.out.println(t);
    }
}

结果:

张三
18
true
13.14
泛型接口
接口格式

泛型不仅可以声明泛型类,也可以声明泛型接口,声明泛型接口和声明泛型类的语法相似,也是在接口名称后面加< T >

格式:权限修饰符 interface 接口名<泛型标示符>{}

/*
    泛型接口定义格式:
         格式:修饰符 interface 接口名<类型>{}
         范例:public interface Generic<T>{}
 */
public class Test {
    public static void main(String[] args) {
        Generic<String> g1 = new GenericTmpl<String>();
        g1.show("张三");
        Generic<Integer> g2 = new GenericTmpl<Integer>();
        g2.show(18);
        Generic<Boolean> g3 = new GenericTmpl<Boolean>();
        g3.show(true);

    }
}

interface Generic<T> {
    public void show(T t);
}

class GenericTmpl<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
泛型接口实现方式

方式一:

子类继续定义泛型类型,通过使用者来确定具体类型
然后使用泛型接口

public class Test {
    public static void main(String[] args) {
        Fan<String> i = null; // 声明接口对象
        i = new Zi<String>("李四"); // 通过子类实例化对象
        System.out.println("内容:" + i.getVal());
    }

}

interface Fan<T> { // 在接口上定义泛型
    public T getVal(); // 定义抽象方法,抽象方法的返回值就是泛型类型
}

//子类继续定义泛型类型,有使用者来确定
class Zi<T> implements Fan<T> { // 定义泛型接口的子类
    private T val; // 定义属性

    public Zi(T val) { // 通过构造方法设置属性内容
        this.setVal(val);
    }

    public void setVal(T val) {//通过方法参数确定
        this.val = val;
    }

    public T getVal() {
        return this.val;
    }
}

方式二:

子类确定泛型类型

interface Info<T> { // 在接口上定义泛型
	public T getVar(); // 定义抽象方法,抽象方法的返回值就是泛型类型
}
class InfoImpl implements Info<String> { // 子类确定泛型类型
	@Override
	public String getVar() {//因为在类里面已经确定了泛型类型,所以约束了方法的泛型
		return null;
	}
}
泛型通配符

类型通配符一般是使用?代替具体的类型参数
例如 List<?> 在逻辑上是List< String >,List< Integer > 等所有List<具体类型实参>的类

通配符的使用

public void show( List < ? > list ){ }:表示可以接收具有"任何泛型"的"List类型"的集合

泛型上限指定

< ? extends E >:只能指向具有E,或者其子类的泛型的对象
public void show( List < ? extends Student > list ){ }:表示只能接收具有"Student"或者"其子类"泛型的集合对象;
泛型下限指定
< ? super E >:只能指向具有E,或者其父类的泛型的对象
还可以看到
public void show( List < ? super Student > stuList ){ } :表示只能接受Student类和其父类的集合对象

public class Test {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<Student>();
        List<Teacher> teachers = new ArrayList<Teacher>();
        List<Person> persons = new ArrayList<Person>();
        List<String> strings = new ArrayList<String>();

        // 可以调用
        m1(strings);
        m1(strings);

        // 因为m2()方法中的参数已经限定了参数泛型上限为Person,
        // String类型不在这个范围之内,所以会报错
        // m2(strings);

        // 类型通配符下限通过形如 List<? super Student>来定义,
        // 表示类型只能接受Student及其三层父类类型,如Objec类型的实例。
        //m3(teachers);
        m3(persons);// 可以通过
    }

    public static void m1(List<?> data) {
    }

    public static void m2(List<? extends Person> data) {
    }

    public static void m3(List<? super Student> stuList) {
    }

    class Person {
    }

    class Student extends Person {
    }

    class Teacher extends Person {
    }
}
泛型好处

可以消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

1.类型安全
2.消除强制类型转换

Collections

Collections概述

Collections是一个集合工具类

Collections方法

public static < T > void sort(List< T > list) // 使用,默认随机源对指定列表进行置换
public static void shuffle(List< ? > list) // 根据元素的自然顺序,对指定列表按升序排序

public static void sort(List list) // 集合元素排序
//排序前元素list集合元素 [33,11,77,55]
Collections.sort( list );
//排序后元素list集合元素 [11,33,55,77]
Collections_sort()方法排序
Collections.sort(objects, new Comparator<TestEntry>() {
    @Override
    public int compare(TestEntry t1, TestEntry t2) {
        //当返回0的时候排序方式是 	t1,t2
        //当返回1的时候排序方式是 	t2,t1
        //当返回-1的时候排序方式是	t1,t2
        //注意
        //返回值大于1效果等同于1
        //返回值小于1 效果等同于0,-1
        return 0;
    }
});
Set集合中使用Comparator
public class Test {
    public static void main(String[] args) {
        // 实例化一个TreeSet
        TreeSet<Student> stuSet = new TreeSet<>(new MyComparator());
        stuSet.add(new Student("李四", 20));
        stuSet.add(new Student("张三", 22));
        stuSet.add(new Student("王五", 24));
        System.out.println("-------------------------------");
        for (Student stu : stuSet) {
            System.out.println(stu.name + "," + stu.age);
        }
    }
}

//排序比较器
class MyComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        System.out.println("o1.name = " + o1.name + " o2.name = " + o2.name);
        // 先按姓名比
        int n1 = o1.name.compareTo(o2.name);
        // 如果姓名相同,比较年龄
        int n2 = (n1 == 0 ? o1.age - o2.age : n1);
        return n2;
    }
}

//学生类
class Student {
    String name;
    int age;

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

结果:

o1.name = 李四 o2.name = 李四
o1.name = 张三 o2.name = 李四
o1.name = 王五 o2.name = 李四
-------------------------------
张三,22
李四,20
王五,24
public static void shuffle(List<?> list) // 集合元素存储位置打乱
//list集合元素 [11,33,55,77]
Collections.shuffle( list );
//使用shuffle方法后,集合中的元素为[77,33,11,55],每次执行该方法,集合中存储的元素位置都会随机打乱

图片示例

集合:

请添加图片描述
请添加图片描述

链表:

请添加图片描述

键值对

请添加图片描述

HashSet存储自定义对象流程

请添加图片描述

二叉树原理

如存入: 22 20 25 24 19 20 26
1.把第一个数据看成是根节点,从第二个数据开始,每个数据都从根节点开始比较
大于0: 就往右放
小于0: 就往左放
等于0: 说明是重复的元素
2.遍历从根节点开始看,按照左中右方式遍历

二叉树图解:每个节点最多两个子节点
请添加图片描述
排序二叉树:存储元素会按照大小排序,并能够去除重复元素
请添加图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值