Java学习笔记-基础语法Ⅶ-集合

集合

集合类特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变

这里需要回顾一下,因为数组和字符串一旦创建,就不可改变,需要区分一下

import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<>();
        c.add("Hello");
        c.add("World");
        c.add("java");
        System.out.println(c);
        // 集合常用方法
        // 长度size
        System.out.println(c.size());
        // 添加add,上文已使用
        // 移除remove
        c.remove("hello");
        boolean hello = c.remove("Hello");
        System.out.println(hello);
        System.out.println(c);
        // 包含
        boolean world = c.contains("World");
        System.out.println(world);
        // 判空
        boolean empty = c.isEmpty();
        System.out.println(empty);
        // 清空
        c.clear();
        System.out.println(c);
    }
}
[Hello, World, java]
3
true
[World, java]
true
false
[]

用完之后发现这种多态方式使用Collection并不好用,不如直接使用ArrayList,而且ArrayList常用的5个方法更好用:addgetremovesetsize

如果想对Collection进行遍历,需要使用迭代器

Iterator是集合的专用遍历方式,Collection可以用,ArrayList之类的也可以用

常用3个方法:nexthasNextremove

// Iterator的使用
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class IteratorDemo {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<>();
        c.add("Hello");
        c.add("World");
        c.add("Java");
        c.add("100");
//        c.add("101");
        Iterator<String> iterator = c.iterator();
        while(iterator.hasNext()) {
            String s = iterator.next();
//
            if(s.equals("100")){
                iterator.remove();
                System.out.println(s);
//                iterator.add("Java");
            }
//            System.out.println(iterator.next());
        }
        System.out.println(c);
    }
}

要注意,Iterator没有add方法,强行使用会导致并发修改异常

List集合特点:

有序集合,可重复

并发修改异常:迭代器遍历过程中,通过集合对象修改了集合中元素长度,造成迭代器获取元素中判断预期修改值和实际修改值不一致。解决:使用for循环

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorDemo {
    public static void main(String[] args) {
        List<String> str = new ArrayList<>();
        str.add("Hello");
        str.add("World");
        str.add("Java");
        ListIterator<String> listIterator = str.listIterator();
        /*
        while(listIterator.hasPrevious()){
//            System.out.println(listIterator.previousIndex());
//            System.out.println(listIterator.previous());
            String previous = listIterator.previous();
            System.out.println(previous);
        }
         */
        while(listIterator.hasNext()){
            String next = listIterator.next();
            if(next.equals("Java")){
                listIterator.add("JavaEE");
            }
        }
        while(listIterator.hasPrevious()){
            System.out.println(listIterator.previousIndex());
//            System.out.println(listIterator.previous());
            String previous = listIterator.previous();
            System.out.println(previous);
        }
    }
}
3
JavaEE
2
Java
1
World
0
Hello

ListIterator可以使用add方法,并且可以查看迭代器的索引

增强for循环

  • 目的:简化数组和Collection集合的遍历
  • 底层:Iterator,也就是不能使用add方法
  • 格式:for(元素数据类型变量名:数组或者Collection集合){//使用变量}
public class ForDemo {
    public static void main(String[] args) {
        int [] arr = {1,2,3,4,5};
        for(int i:arr){
            System.out.println(i);
        }
    }
}

数据进入栈模型的过程称为:压/进栈,反之为弹/出栈

栈是先进后出的模型

队列

入队/出队

队列是先进先出的模型

数组

查询数据通过索引定位,查询效率高

删除和添加效率低

链表

增删快,查询慢

ArrayList

ArrayList是List接口的可调整大小的数组实现,数组特点是查询快,增删慢

LinkList是双链表实现List和Deque接口,查询慢,增删快

常用方法:addFirstaddLastgetFirstgetLastremoveFirstremoveLast

居然还可以在指定位置插入元素

    • add(int index, E element) 在列表中指定的位置上插入指定的元素。

Set

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

HashSet

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

hashCode方法,默认情况下,不同对象的hash值不同

// Student类
public class Student {
    private int age;

    public Student() {
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
// 测试类
import java.util.HashSet;
import java.util.Set;

public class My_Hash {
    public static void main(String[] args) {
        Set<String> s1 = new HashSet<>();
        s1.add("java");
        Set<String> s2 = new HashSet<>();
        s2.add("java");
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println("--------");
        Student s3 = new Student(18);
        Student s4 = new Student(18);
        System.out.println(s3.hashCode());
        System.out.println(s4.hashCode());
    }
}
3254818
3254818
--------
1324119927
990368553

但是可以在原来的类中重写hashCode方法,这样就可以返回指定hash值

如在上述学生类中重写hashCode方法如下

@Override
public int hashCode(){
    return age;
    // return 0;
}

这样返回的hash值就都为自己创建对象的age值

HashSet

  • 底层数据结构是哈希表
  • 对集合的迭代顺序不作任何保证
  • 没有索引方法,所以不能使用普通for循环遍历
  • 不包含重复元素的集合

哈希表

LinkedHashSet

有哈希表和链表实现的Set接口,具有可预测的迭代次序

由链表保证元素有序,也就是说元素的存储和取出的顺序是一致的,这点和HashSet不同

由哈希表保证元素唯一性

TreeSet

元素按照一定的规则进行排序,无参构造方法按照自然顺序排序,带参构造方法按照指定规则排序

要进行自然排序,需Comparable或者Comparator

  • Comparable:此接口对实现它的每个类的对象进行了总排序。这个顺序被称为类的空自然排序,和类的 compareTo方法称为空自然比较方法。
  • 一个比较函数,这对一些对象的集合,对总序。比较器可以通过某种方法(如 Collections.sort或 Arrays.sort)允许在排序顺序的精确控制。比较器也可以用来控制特定的数据结构顺序(如 sorted sets或 sorted maps),或提供的对象不集合排序有 natural ordering。

首先看一下TreeSet对Integer进行自然排序

import java.util.TreeSet;

public class Demo {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(5);
        ts.add(10);
        ts.add(1);
        ts.add(7);
        ts.add(20);
        for(int i:ts){
            System.out.println(i);
        }
    }
}
1
5
7
10
20

这是因为Integer实现了Comparable接口,不能想当然认为其他类也实现了

  •   public final class Integer
      extends Number
      implements Comparable<Integer>
    

接下来对一般类实现自然排序

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

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

    public Student() {
    }

    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 +
                '}';
    }

    @Override
    public int compareTo(Object o) {
//        return 0;
        return 1;
    }
}
// 测试类
public class Demo {
    public static void main(String[] args) {
        TreeSet<Student> s = new TreeSet<>();
        Student s1 = new Student("linqingxia",18);
        Student s2 = new Student("zhangmanyu",48);
        Student s3 = new Student("wangzuxian",38);
        Student s4 = new Student("zhangmin",28);
        s.add(s1);
        s.add(s2);
        s.add(s3);
        s.add(s4);
        for(Student st:s){
            System.out.println(st);
        }
    }
}

继承Comparale,再重写CompareTo方法

      •           int compareTo(T o)
              ```
        
                  将此对象与指定的对象进行比较,以。返回一个负整数、零或一个正整数,因为这个对象小于、等于或大于指定的对象。 
        
        

如果想要按照年龄进行排序,则需要把CompareTo进行如下改写

public class Student implements Comparable<Student>{
    private String name;
    private int age;

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

    public Student() {
    }

    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 +
                '}';
    }

    @Override
    public int compareTo(Student s) {
//        return 0;
        int num1 = this.age - s.age;
        int num2 = num1 == 0?this.name.compareTo(s.name):num1;
        return num2;
    }
}
import java.util.TreeSet;

public class Demo {
    public static void main(String[] args) {
        TreeSet<Student> s = new TreeSet<>();
        Student s1 = new Student("linqingxia",18);
        Student s2 = new Student("zhangmanyu",48);
        Student s3 = new Student("wangzuxian",38);
        Student s4 = new Student("zhangmin",28);
        Student s5 = new Student("qiushuzhen",28);
        s.add(s1);
        s.add(s2);
        s.add(s3);
        s.add(s4);
        s.add(s5);
        for(Student st:s){
            System.out.println(st);
        }
    }
}

TreeSet结合存储自定义对象时,带参构造方法使用比较器排序对元素进行排序

同样,也可以让类继承Compareble,然后重写CompareTo来实现

上例中implements Compareble<Student>是因为测试类中使用的是泛型

题目:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合,要求:按照总分从高到底出现

为了简化,就不写get和set方法

// 学生类
public class Student implements Comparable<Student>{
    private String name;
    private int mathScore;
    private int chinesScore;
    private int englishScore;
    public int setTotalScore(){
        return mathScore+chinesScore+englishScore;
    }

    public Student(String name, int mathScore, int chinesScore, int englishScore) {
        this.name = name;
        this.mathScore = mathScore;
        this.chinesScore = chinesScore;
        this.englishScore = englishScore;
    }

    public Student() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", mathScore=" + mathScore +
                ", chinesScore=" + chinesScore +
                ", englishScore=" + englishScore +
                ", totalScore=" + setTotalScore() +
                '}';
    }

    @Override
    public int compareTo(Student student) {
        int num1 = student.setTotalScore() - this.setTotalScore();
        int num2 = num1 == 0?student.mathScore-this.mathScore:num1;
        int num3 = num2 == 0?student.chinesScore-this.chinesScore:num2;
        int num4 = num3 == 0?student.englishScore-this.englishScore:num3;
        int num5 = num4 == 0?student.name.compareTo(this.name):num4;
        return num5;
    }
}
// 测试类
import java.util.TreeSet;

public class Demo {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();
        Student s1 = new Student("赵",99,98,99);
        Student s2 = new Student("钱",98,99,100);
        Student s3 = new Student("孙",99,98,100);
        Student s4 = new Student("李",100,99,98);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        for(Student s:ts){
            System.out.println(s);
        }
    }
}

包装类如Integer和String是实现了Compareble的,所以可以直接使用CompareTo方法

posted on 2021-12-24 23:11  lpzju  阅读(42)  评论(0编辑  收藏  举报

导航