Java 基础篇:第十三章:List集合和Set集合

 

目录

一、List接口:

1.1 List集合特有功能:

1.2 ArrayList类:

1.3 LinkedList:

1.4 Vector类:

1.5 List接口的三个实现类:

二、泛型:

2.1 泛型的概述:

2.2 泛型的专业术语:

2.3 泛型擦除:

2.4 泛型写法:

2.5 泛型方法/类/接口:

2.6 泛型关键字:

三、HashSet类:

3.1 HashSet概述:

3.2 HashSet保证元素唯一性的原理:

3.3 HashSet面试题:

四、TreeSet类:

4.1 TreeSet概述:

4.2 面试题:


 

主要内容:

1、Collection接口

2、List接口

3、ArraList

4、Vector

5、LinkedList

6、Set接口

 

一、List接口:

1.1 List集合特有功能:

void add(E e)

void add(int index,E e) 向指定位置插入元素

E remove(int index)移除列表中指定位置的元素(可选操作)。将所有的后续元素向左移动(将其索引减 1)。返回从列表中移除的元素。

E get(int index):返回列表中指定位置的元素。

E set(int index,E element)用指定元素替换列表中指定位置的元素(可选操作)。

public class ListDemo01 {

    public static void main(String[] args) {

       List list = new ArrayList();

       list.add("AAA");

       list.add("BBB");

       list.add("CCC");

       list.add("DDD");

       print(list);

       list.add(2, "EEE");

       print(list);

       // list.remove(2);

       list.set(2, "eee");

       print2(list);

    }

 

    public static void print(List list) {

       Iterator iterator = list.iterator();

       while (iterator.hasNext()) {

           System.out.println(iterator.next());

       }

    }

 

    public static void print2(List list) {

       for (int i = 0; i < list.size(); i++) {

           System.out.println(list.get(i));

       }

    }

}

 

1.2 ArrayList类:

数组实现。长度可变。

1.3 LinkedList:

数组:存储是连续的0,查询、修改快。增加删除慢。

链表集合。在内存中每个元素存储不连续,查询慢、修改慢。增加快、删除快。

 

 

1.4 Vector类:

Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。

特有功能(与ArrayList和LinkedList不同)

public void addElement(E obj):将指定的组件添加到此向量的末尾,将其大小增加 1。如果向量的大小比容量大,则增大其容量。

public E elementAt(int index):返回指定索引处的组件

public Enumeration<E> elements():返回此向量的组件的枚举。返回的 Enumeration 对象将生成此向量中的所有项。生成的第一项为索引 0 处的项,然后是索引 1 处的项,依此类推。

Enumeration:枚举。

public class VectorDemo {

    public static void main(String[] args) {

       Vector vector = new Vector();

       vector.addElement("A");

       vector.addElement("B");

       // System.out.println(vector.elementAt(0));

 

       // 遍历(迭代)

       Enumeration enumeration = vector.elements(); // 枚举

       while (enumeration.hasMoreElements()) {

           System.out.println(enumeration.nextElement());

       }

    }

}

1.5 List接口的三个实现类:

1、三个实现类的特点:

ArrayList:底层数据结构是数组,查改快,增删慢。

线程不安全,效率高。

Vector:底层数据结构是数组,查改快,增删慢。

线程安全,效率低。

Vector相对ArrayList查询慢。增删慢。

LinkedList:底层数据结构是链表,查改慢,增删快。

线程不安全,效率高。

2、ArrayList和Vector底层数据结构都是数组。

3、三个实现类的选择:

查改操作比较多,推荐使用ArrayList

增删操作比较多,推荐LinkedList

如果增删查改都多,推荐使用ArrayList

二、泛型:

2.1 泛型的概述:

JDK1.5,允许在编写集合代码时,先限制集合的处理类型,把原来程序运行时可能发生的问题,转变成编译时问题,可以有效及时解决问题,提高程序的可读性和稳定性。

public class GenericDemo01 {

    public static void main(String[] args) {

       List list = new ArrayList();

       list.add(100);

       list.add("Hello");

       list.add(250);

 

       String[] arr = new String[list.size()];

       for (int i = 0; i < list.size(); i++) {

           // arr[i] = list.get(i);

       }

       System.out.println(list.get(1));

    }

}

public class GenericDemo02 {

    public static void main(String[] args) {

       List<String> list = new ArrayList<String>();

       // list.add(100);

       list.add("Hello");

       // list.add(250);

 

       String[] arr = new String[list.size()];

       for (int i = 0; i < list.size(); i++) {

           arr[i] = list.get(i);

       }

       System.out.println(list.get(1));

    }

}

2.2 泛型的专业术语:

以ArrayList<E>为例:

<>念为typeof,实际上就是集合的元素类型

E称为参数类型(元素类型)

ArrayList<String>中String就是元素类型

整个ArrayList<E>被称为泛型类型。

2.3 泛型擦除:

泛型只在编译时期有效,编译后字节码文件中会把泛型类型中元素类型去掉,不存在有效的泛型信息。

public class GenericDemo03 {

    public static void main(String[] args) {

 

    }

 

    // 泛型擦除

    public void save(List<Employee> employees) {

 

    }

 

    public void save(List<Dept> depts) {

 

    }

}

2.4 泛型写法:

public class GenericDemo04 {

    public static void main(String[] args) {

       // 声明泛型集合,集合两边类型必须保持一致

       List<Object> list1 = new ArrayList<Object>();

       List<Integer> list2 = new ArrayList<Integer>();

 

       List<String> list3 = new ArrayList();

       List list4 = new ArrayList<String>();

      

       //错误:泛型的类型必须是引用类型,不能是基本类型。

       List<char> list5 = new ArrayList<char>();

    }

}

2.5 泛型方法//接口:

作用:设计公用的类和方法,对各种业务提取公共部分取实现,使程序更加灵活。

1、泛型方法:

public class GenericDemo05 {

    public <T> T save(List<T> list) {

       System.out.println("批量保存对象集合!");

       return null;

    }

 

    public static void main(String[] args) {

       // 使用泛型方法,由具体调用的时候,才正式确定泛型的类型

       // 批量保存Employee

       List<Employee> list = new ArrayList<Employee>();

       new GenericDemo05().save(list);

 

       // 批量保存部门:

       List<Dept> depts = new ArrayList<Dept>();

       new GenericDemo05().save(depts);

    }

}

2、泛型类:

public class GenericDemo06Test {

    public static void main(String[] args) {

       GenericDemo06<Employee> demo = new GenericDemo06<Employee>();

       demo.save(new Employee());

    }

}

public class GenericDemo06<T> {

    // 定义泛型方法

    public void save(T t) {

       System.out.println("保存对象t");

    }

}

3、泛型接口:

public interface BaseDao<T> {

    // 增删改查C-create,R-read,U-update,D-delete

    void create(T t);

 

    void delete(int id);

 

    void update(T t);

 

    void get(int id);

 

    List<T> listAll();

}

泛型接口类型的确定:在调用具体的实现类中方法时确定。

2.6 泛型关键字:

?   指定只是接受值

extends   元素的类型必须是继承自指定的类,本身也可以。【上限】

super    元素的类型必须是指定类的父类(或超类),本身也可以。【下限】

1、关键字?

public class GenericDemo07 {

    public void save(List<?> depts) {

       // 传入的list集合只能读取、迭代,不能修改里面元素值。

       depts.set(1, "XXX");

       for (int i = 0; i < depts.size(); i++) {

           System.out.println(depts.get(i));

       }

    }

 

    public static void main(String[] args) {

       List<String> depts = new ArrayList<String>();

       depts.add("测试部");

       depts.add("研发部");

       new GenericDemo07().save(depts);

    }

}

2、关键字extends:

public class GenericDemo08 {

    public static void main(String[] args) {

        List<Double> list1 = new ArrayList<Double>();

        List<String> list2 = new ArrayList<String>(); // 不能作为save方法的参数

 

        new GenericDemo08().save(list1);

    }

 

    public void save(List<? extends Number> list) {

 

    }

}

3、关键字super:

public class GenericDemo09 {

    public void save(List<? super String> list) {

 

    }

 

    public static void main(String[] args) {

       List<Object> list1 = new ArrayList<Object>();

       new GenericDemo09().save(list1);

 

       List<String> list2 = new ArrayList<String>();

       new GenericDemo09().save(list2);

    }

}

三、HashSet类:

3.1 HashSet概述:

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。

public boolean add(E e)

如果此 set 中尚未包含指定元素,则添加指定元素。更确切地讲,如果此 set 没有包含满足 (e==null ? e2==null : e.equals(e2)) 的元素 e2,则向此 set 添加指定的元素 e。如果此 set 已包含该元素,则该调用不更改 set 并返回 false。

public class HashSetDemo01 {

    public static void main(String[] args) {

       Set<String> set = new HashSet<String>();

       boolean b1 = set.add("A");

       boolean b2 = set.add("A");

       System.out.println(b1);

       System.out.println(b2);

       // 遍历

       for (String s : set) { // 增强for循环

           System.out.println(s);

       }

 

       Set<Person> persons = new HashSet<Person>();

       persons.add(new Person("发生"));

       persons.add(new Person("有根"));

       persons.add(new Person("有根")); // 没有重写equals方法

       for (Person person : persons) {

           System.out.println(person);

       }

    }

}

 

HashSet存储自定义对象如何保证元素的唯一性——必须要重写equals方法和hashCode方法。

3.2 HashSet保证元素唯一性的原理:

1、HashSet原理:

我们使用Set集合都是需要去掉重复元素,如果在存储的时候逐个使用equals方法比较,效率低,哈希算法提高去重的效率,降低使用equals方法的次数。

当HashSet调add方法存储对象时,先调用对象的hashCode方法得到一个hash值,然后在集合中查找是否有相同哈希值的对象:

如果没有hash值相同的对象,就直接存入集合;

如果有hash值相同的对象,就和hash值相同的对象逐个进行equals比较,比较结果是false就存入集合,如果是true就不存。

2、将自定义类型的对象存入HashSet去重:

类中必须重写hashCode和equals方法。

hashCode方法:属性值相同的对象返回值必须相同。

equals方法:属性值相同返回true,属性值不相同返回false。返回false时应该存储。

3.3 HashSet面试题:

  1. 需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并且把随机数打印到控制台。

public class HashSetDemo02 {

    // 需求:编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复,并且把随机数打印到控制台。

    public static void main(String[] args) {

       Set<Integer> set = new HashSet<Integer>();

       Random random = new Random();

       // Math.random() double:[0.0,1.0)

       // Random nextInt(int seed)

       while (set.size() < 10) {

           // 1,2,3,....,20

           set.add(random.nextInt(20) + 1);

       }

 

       for (Integer n : set) {

           System.out.println(n);

       }

    }

}

2、使用Scanner从键盘读取一行输入字符串,去掉中间的重复字符,打印出最终的结果。

比如:输入aabbcccccdddd,则输出abcd

public class HashSetDemo03 {

    // 使用Scanner从键盘读取一行输入字符串,去掉中间的重复字符,打印出最终的结果。

    // 比如:输入aabbaaacccccdddd,则输出abcd

    public static void main(String[] args) {

       Scanner scanner = new Scanner(System.in);

       System.out.println("请输入一行字符串:");

       String str = scanner.next();

       char[] arr = str.toCharArray();

       Set<Character> set = new HashSet<Character>();

       for (char ch : arr) {

           set.add(ch);

       }

 

       // 输入set集合

       for (Character ch : set) {

           System.out.print(ch);

       }

    }

}

四、TreeSet类:

4.1 TreeSet概述:

使用元素的自然顺序(升序)对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

public class TreeSetDemo01 {

    public static void main(String[] args) {

       // TreeSet存储类库提供的引用类型的元素。

       Set<Integer> set = new TreeSet<Integer>();

       set.add(1);

       set.add(4);

       set.add(1);

       set.add(2);

 

       System.out.println(set.toString());

    }

}

自定义引用类型当做集合的元素类型:

public class PersonComparator implements Comparator<Person> {

 

    @Override

    public int compare(Person person1, Person person2) {

       String name1 = person1.getName();

       String name2 = person2.getName();

       int name1Len = name1.length(); // 张三、张三

       int name2Len = name2.length();

 

       if (name1Len > name2Len) {

           return 1;

       } else if (name1Len < name2Len) {

           return -1;

       } else { // name1Len == name2Len

           for (int i = 0; i < name1Len; i++) {

              if (name1.charAt(i) > name2.charAt(i)) {

                  return 1;

              } else if (name1.charAt(i) < name2.charAt(i)) {

                  return -1;

              } else { // name1.charAt(i) == name2.charAt(i)

 

              }

           }

       }

       return 0;

    }

}

 

public class TreeSetDemo02 {

    public static void main(String[] args) {

       // Comparator接口,必须由类来实现

       // TreeSet(Comparator<? super E> comparator)

       // 构造一个新的空 TreeSet,它根据指定比较器进行排序。

       Set<Person> persons = new TreeSet<Person>(new PersonComparator());

       persons.add(new Person("张三"));

       persons.add(new Person("李四"));

       persons.add(new Person("旺旺"));

       persons.add(new Person("张三"));

 

       System.out.println(persons);

    }

}

4.2 TreeSet的原理:

1、特点:

用来排序的,可以指定一个顺序,对象存入之后会按照指定的顺序排列。

2、使用方式:

A、自然排序:

TreeSet类的add方法中会把存入的对象提升为Comparable类型。

调用对象的compareTo方法和集合中的对象比较。

根据compareTo方法返回值进行存储。

B、比较器排序(Comparator)

创建TreeSet时制定一个Comparator的一个实现类

add方法会调用比较器的compare方法进行比较,返回一个值。

根据compare方法的返回值进行存储。

4.2 面试题:

需求:控制台输入5个学生信息(姓名、语文成绩、数学成绩、英语成绩),按照总分从高到低输出到控制台。

public class StudentComparator implements Comparator<Student> {

    // 按照总分降序排列

    @Override

    public int compare(Student stu1, Student stu2) {

       double total1 = stu1.getChinese() + stu1.getEnglish() + stu1.getMath();

       double total2 = stu2.getChinese() + stu2.getEnglish() + stu2.getMath();

       if (total1 > total2) {

           return -10;

       } else if (total1 < total2) {

           return 1;

       }

       return 0;

    }

}

public class Student {

    private String name;

    private double chinese;

    private double math;

    private double english;

 

    public Student() {

       super();

       // TODO Auto-generated constructor stub

    }

 

    public Student(String name, double chinese, double math, double english) {

       super();

       this.name = name;

       this.chinese = chinese;

       this.math = math;

       this.english = english;

    }

 

    public String getName() {

       return name;

    }

 

    public void setName(String name) {

       this.name = name;

    }

 

    public double getChinese() {

       return chinese;

    }

 

    public void setChinese(double chinese) {

       this.chinese = chinese;

    }

 

    public double getMath() {

       return math;

    }

 

    public void setMath(double math) {

       this.math = math;

    }

 

    public double getEnglish() {

       return english;

    }

 

    public void setEnglish(double english) {

       this.english = english;

    }

 

    @Override

    public String toString() {

       StringBuilder builder = new StringBuilder();

       builder.append("Student [name=");

       builder.append(name);

       builder.append(", chinese=");

       builder.append(chinese);

       builder.append(", math=");

       builder.append(math);

       builder.append(", english=");

       builder.append(english);

       double total = this.chinese + this.english + this.math;

       builder.append(", total=").append(total);

       builder.append("]");

       return builder.toString();

    }

}

 

public class TreeSetDemo03 {

    // 需求:控制台输入5个学生信息(姓名、语文成绩、数学成绩、英语成绩),按照总分从高到低输出到控制台。

    public static void main(String[] args) {

       Set<Student> students = new TreeSet<Student>(new StudentComparator());

       // 假设是从控制台输入

       students.add(new Student("张", 87.9, 90.0, 76.8));

       students.add(new Student("王", 83.7, 92.0, 73.0));

       students.add(new Student("李", 82.9, 94.0, 72.5));

       students.add(new Student("郑", 84.9, 90.5, 76.0));

       students.add(new Student("赵", 87.5, 86.0, 90.8));

       for (Student student : students) {

           System.out.println(student);

       }

    }

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逼哥很疯狂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值