集合框架最详细知识点含例题

# 集合框架

**集合**:把具有相同数据类型的一组变量,汇聚成一个整体,就被称之为集合。

**集合框架**:为了表示和操作集合而规定的一种统一标准的体系结构。最简单的集合如数组、队列和列表等。任何集合框架一般包含:对外的接口、接口的实现和对集合运算的算法。

- 接口:即表示集合的抽象数据类型(规范)。接口提供了让我们对集合中所表示的内容进行单独操作的方式(标准)。
- 实现:也就是集合框架中接口的具体实现。实际上它们就是那些可复用的数据结构。
- 算法:在一个实现了某个集合框架中的接口对象身上完成了某种有用的计算的方法,例如查找、排序等。

## 接口的体系结构

 

## Collection接口

对单个元素进行存放的最大接口规范。针对不同的方式它有不同的实现。

### List接口

是Collection接口的子接口,主要针对于线性操作来提出的规范。

**特点**:可重复,有序的集合

#### Vector实现类

线性队列式结构的一种实现,它是线程安全的,多个线程同时对集合操作时保证了安全。

**特点**:数组结构、查询方便(只需要下标就行)、线程安全的,插入和删除的效率低下(涉及其后元素的位移)

```java
// 1.如何产生Vector类的对象
// 产生了一个Vector集合,集合中只能存放Integer类型的元素
Vector<Integer> vector = new Vector<>();
// 2.Vector类的常用方法
// 存放到集合中
vector.add(88); // 添加到集合的末尾
vector.add(64);
vector.add(1, 39); // 插入到指定位置之前
System.out.println(vector);
// 获取集合的长度
int len = vector.size();
System.out.println("集合元素个数是:" + len);
// 获取集合中的元素
int v1 = vector.get(1); // 获取指定位置的元素
System.out.println(v1);
// 修改集合指定位置的元素内容
vector.set(2, 93);
System.out.println(vector);
// 删除集合的元素
vector.remove(1); // 删除指定位置的元素
System.out.println(vector);
vector.clear(); // 清空集合
System.out.println(vector);
// 3.如何排序集合
Vector<Integer> vector = new Vector<>();
for (int i = 0; i < 10; i++) {
    int num = (int) (Math.random() * 100 + 1);
    vector.add(num);
}
System.out.println("排序之前的内容:");
System.out.println(vector);
// 通过集合框架中提供的一个算法类来完成
Collections.sort(vector); // 对集合进行升序操作
System.out.println("排序之后的内容:");
System.out.println(vector);
// 4.如何查找集合中的元素
Vector<Integer> vector = new Vector<>();
for (int i = 0; i < 10; i++) {
     int num = (int) (Math.random() * 10 + 1);
     vector.add(num);
}
System.out.println(vector);
System.out.print("Input:");
int num = scan.nextInt();
// 判断用户输入的这个元素是否存在
boolean b = vector.contains(num);
System.out.println(b ? "存在" : "不存在");
// 获取到用户输入的内容在集合中的位置 如何不存在返回-1
int index = vector.indexOf(num);
System.out.println("集合中的位置:" + index);
int index2 = vector.indexOf(num,4); // 从第五个开始查找指定元素的位置
System.out.println(index2);
```

#### Stack实现类

继承于Vector类,它有一些自身特有方法。实现了一个先进后出的堆栈。提供了5个特有的方法,基本的push和pop方法,还有获取到栈顶的peek方法,还可以通过empty方法测试堆栈是否为空,search方法检测一个元素在堆栈的位置。

**特点**:数组结构、查询方便(只需要下标就行)、线程安全的,有自身特有方法,插入和删除的效率低下(涉及其后元素的位移)

java
// 1.如何产生集合对象
Stack<String> stack = new Stack<>();
// 2.集合的常用方法  这里只讨论特有方法,继承下来的方法不再重复讲解
// 等同于add(e);操作添加到集合的末尾
stack.push("aa");
stack.push("bb");
stack.push("cc");
stack.push("dd");
System.out.println(stack);
// 获取集合的元素
// 获取到集合中最后位置的元素
String v3 = stack.peek();
String v4 = stack.peek();
System.out.println(v3);
System.out.println(v4);
System.out.println(stack);
// 获取到集合中最后位置的元素 并会删除这个元素
String v1 = stack.pop();
String v2 = stack.pop();
System.out.println(v1);
System.out.println(v2);
System.out.println(stack);
// 检测堆栈是否为空
boolean b = stack.empty();
System.out.println(b);
// 检测堆栈是否存在某个元素
int index = stack.search("aa");
System.out.println("返回的位置是:" + index);
```

#### ArrayList实现类🌟🌟🌟🌟

就是传说中的**动态数组**,也是我们最常用的集合。它允许任何符合规则的元素插入。每一个ArrayList初始容量都是0,当第一次向集合中添加元素时,系统会**自动**扩充集合的长度,以后每一次添加元素时如果容量不够仍会自动扩容。和Vector类是基本一致的,除过它不是线程安全的。目前的规范标准都推荐使用ArrayList。

**特点**:数组结构、查询方便(只需要下标就行)、线程不安全的,插入和删除的效率低下(涉及其后元素的位移)

##### 基本数据类型操作

```java
public static void a() {
    // 1.如何产生对象
    // ArrayList<String> list = new ArrayList<>();
    // 一般推荐写法
    List<String> list = new ArrayList<>();
    // 2.集合的常用方法
    list.add("aa");
    list.add("bb");
    list.add("cc");
    list.add(2, "dd");
    System.out.println(list);
    String v1 = list.get(1);
    System.out.println(v1);
    list.set(2, "ee");
    System.out.println(list);
    list.remove(1); // 删除指定位置的元素
    list.remove("aa"); // 删除指定内容的元素
    System.out.println(list);
    list.clear();
    System.out.println(list);
    int len = list.size();
    System.out.println("集合的长度:" + len);
    boolean b = list.isEmpty();
    System.out.println("是否是空:" + b);
}

// 如何排序常见数据类型的集合
public static void b() {
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        int num = (int) (Math.random() * 100 + 1);
        list.add(num);
    }
    System.out.println("排序之前的内容:");
    System.out.println(list);
    // 通过集合框架中提供的一个算法类来完成
    Collections.sort(list); // 对集合进行升序操作
    System.out.println("排序之后的内容:");
    System.out.println(list);
}

private static Scanner scan = new Scanner(System.in);

// 查找元素在集合中的位置
public static void c() {
    System.out.println("Input:");
    int num = scan.nextInt();
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        int num1 = (int) (Math.random() * 10 + 1);
        list.add(num1);
    }
    System.out.println(list);
    boolean b = list.contains(num);
    System.out.println("是否存在:" + b);
    int index1 = list.indexOf(num); // 找出第一次出现的位置 不存在返回-1
    int index2 = list.lastIndexOf(num); // 找出最后一次出现的位置 不存在返回-1
    System.out.println(index1);
    System.out.println(index2);
}
```

##### 复杂数据类型操作

```java
// ArrayList对复杂类型的操作
public class DemoD {
    // 基本的创建对象,CRUD(增删改查)的方法
    public static void a() {
        // 产生了一个集合,这个集合只能存放Person类型的数据
        List<Person> list = new ArrayList<>();
        // 产生了四个对象
        Person p1 = new Person(1, "张三", '男', 23);
        Person p2 = new Person(2, "李四", '女', 21);
        Person p3 = new Person(3, "王武", '男', 28);
        Person p4 = new Person(4, "马六", '男', 25);
        // 将这四个对象存放到集合中
        list.add(p1);
        list.add(p2);
        list.add(1, p3);
        list.add(p4);
        System.out.println(list);
        // 获取到指定位置的元素
        Person p5 = list.get(3);
        System.out.println(p5);
        // 修改指定位置的元素
        Person p6 = new Person(5, "大白", '男', 19);
        list.set(1, p6);
        System.out.println(list);
        // 删除元素
        list.remove(1);
        list.remove(p1);
        System.out.println(list);
        // 清空
        list.clear();
        // 获取长度
        int len = list.size();
        System.out.println(len);
    }


    // 讲解了复杂(自定义)数据类型的排序问题
    /*
        1.泛型类必须实现Comparable接口
        2.泛型类重写compareTo方法,自定义规则
        3.调用Collections.sort(list);来进行排序
     */
    public static void b() {
        List<Person> list = new ArrayList<>();
        Person p1 = new Person(1, "张三", '男', 23);
        Person p2 = new Person(2, "李四", '女', 21);
        Person p3 = new Person(3, "王武", '男', 28);
        Person p4 = new Person(4, "马六", '男', 25);
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        list.add(p2);
        System.out.println("排序之前的集合:");
        for (int i = 0; i < list.size(); i++) {
            Person p = list.get(i);
            System.out.println(p);
        }
        // 如何对集合排序 要求泛型必须实现一个接口Comparable
        Collections.sort(list);
        System.out.println("排序之后的集合:");
        for (int i = 0; i < list.size(); i++) {
            Person p = list.get(i);
            System.out.println(p);
        }
    }

    /*
        讲解了复杂数据类型的查找问题
        1.重写equals方法 自定义规则
        2.调用contains或者indexOf方法
     */
    public static void c() {
        List<Person> list = new ArrayList();
        Person p1 = new Person(1, "张三", '男', 26);
        Person p2 = new Person(2, "李四", '女', 22);
        Person p3 = new Person(3, "王武", '男', 21);
        Person p4 = new Person(4, "马六", '男', 27);
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        int len = list.size();
        System.out.println("集合长度是:" + len);
        boolean b1 = list.contains(p1);
        System.out.println(b1 ? "存在" : "不存在");
        int index1 = list.indexOf(p1);
        System.out.println("位置是:" + index1);
        System.out.println("----------------------------------------------");
        // 只关心对象的值在集合中的元素是否有重复
        // 产生了一个新对象
        Person p5 = new Person(3, "王武", '男', 21);
        System.out.println("p3和p5的内存地址是否相等?" + (p3 == p5));
        System.out.println("p3和p5的equals方法返回结果是否相等?" + p3.equals(p5));
        boolean b2 = list.contains(p5);
        System.out.println(b2 ? "存在" : "不存在");
        int index2 = list.indexOf(p5);
        System.out.println("位置是:" + index2);
        System.out.println("----------------------------------------------");
        Person p6 = p3;
        System.out.println("p3和p6是否相等?" + (p3 == p6));
        boolean b3 = list.contains(p6);
        System.out.println(b3 ? "存在" : "不存在");
        int index3 = list.indexOf(p6);
        System.out.println("位置是:" + index3);
    }
    public static void main(String[] args) {
        c();
    }

}
```

#### LinkedList实现类

是List接口的一种实现,它是一种**双向链表**结构,在执行查询时效率比较低下,但是插入和删除效率比较高。

```java
/*
    1.如何产生集合对象
    2.集合的常用方法
    3.如何查找和排序
    4.其他的注意事项
 */
public class DemoB {

    public static void a() {
        // 产生LinkedList集合对象
        LinkedList<String> list = new LinkedList<>();
        // 常用方法
        list.add("aa");
        list.add("bb");
        list.add(1, "cc");
        // 特有方法
        list.addFirst("dd"); // 添加到第一个位置
        list.addLast("ee"); // 就是list.add("ee");
        System.out.println(list);
        String v1 = list.get(1);
        // 特有方法
        String v2 = list.getFirst();
        String v3 = list.getLast();
        System.out.println("获取指定位置元素:" + v1);
        System.out.println("获取第一个元素:" + v2);
        System.out.println("获取最后一个元素:" + v3);
        list.set(2, "ff");
        System.out.println(list);
        list.remove(1);
        list.remove("ff");
        // 特有方法
        list.removeFirst();
        list.removeLast();
        System.out.println(list);
        int len = list.size();
        System.out.println("长度是:" + len);
        list.clear();
        boolean b = list.isEmpty();
        System.out.println(b ? "空的" : "非空的");
    }

    private static Scanner scan = new Scanner(System.in);

    // 基本类型的排序和查找
    public static void b() {
        LinkedList<Integer> list = new LinkedList<>();
        for (int i = 0; i < 10; i++) {
            int num = (int) (Math.random() * 100 + 1);
            list.add(num);
        }
        System.out.println(list);
        Collections.sort(list); // List中的四个实现类它们的排序是一样的
        System.out.println(list);
        // List中的四个实现类它们的查找也是一样的
        System.out.println("请输入:");
        int num = scan.nextInt();
        boolean b = list.contains(num);
        int index1 = list.indexOf(num);
        int index2 = list.lastIndexOf(num);
        System.out.println("是否存在?" + b);
        System.out.println("第一次出现的位置:" + index1);
        System.out.println("最后一次出现的位置:" + index2);
    }

    // 自定义类型的排序和查找
    public static void c() {
        LinkedList<Person> list = new LinkedList<>();
        Person p1 = new Person(1, "张三", '男', 21);
        Person p2 = new Person(2, "李四", '女', 27);
        Person p3 = new Person(3, "王武", '男', 23);
        Person p4 = new Person(4, "马六", '男', 25);
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        // 排序之前:
        for (Person p : list) {
            System.out.println(p);
        }
        System.out.println("------------------------------------------------");
        Collections.sort(list); // 同ArrayList的写法
        // 排序之后:
        for (Person p : list) {
            System.out.println(p);
        }
        // 查找 和ArrayList写法完全一致
        System.out.println("------------------------------------------------");
        Person p5 = new Person(3, "王五", '男', 26);
        boolean b = list.contains(p5);
        int index = list.indexOf(p5);
        System.out.println("是否存在?" + b);
        System.out.println("第一次出现的位置:" + index);
    }

    public static void main(String[] args) {
        c();
    }
}
```

#### List集合实现类的分析

- ArrayList、Vector和Stack都是动态数组,它们查询速度很快,但是插入删除速度慢。
- LinkedList是双向链表结构,插入删除块,查询速度慢,
- Vector是线程安全的集合,Stack是Vector的子类,它是一个先进后出的结构。
- 一般情况下,我们推荐使用ArrayList。

### Set接口

是Collection接口的子接口,它主要针对于散列式接口来提出的规范。

**特点**:不可重复(不允许存放重复的元素),无序(没有索引下标)。

#### HashSet实现类🌟🌟🌟

HashSet是Set集合最常用的实现类,经典表现。是按照Hash算法来存储元素的,因此具有很好的存放功能。

**特点**:

1. 不保证元素的顺序
2. HashSet不是线程安全的
3. 可以存放null值
4. 值的内容不允许重复

##### 产生HashSet集合

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

##### 常见的方法

```java
//添加元素
set.add(99);
set.add(23);
set.add(56);
set.add(78);
/*
    // 不能存放重复内容,存放时要判断元素在集合中是否存在
    首先通过循环来和集合中的每一个元素进行比较
      1.获取到当前元素的hash值(通过调用hashCode()来获取) 和集合中元素的hash值比较相等时
      2.当前元素和集合中元素的equals()进行比较
      3.如果都相等 则代表这个元素在集合中存在,否则 不存在
*/
set.add(56); 
set.add(null);
System.out.println(set);
// 删除元素
set.remove(23); // 只能删除指定元素  不能删除索引
System.out.println(set);
// 获取元素 没有 无法获取
// 只能通过迭代器来遍历
for (Integer i : set) {
    System.out.print(i + "\t");
}
System.out.println();
// 修改元素 无法修改

int len = set.size();
System.out.println(len);
```

##### 查找集合中是否存在内容

```java
public static void c() {
    // 产生了一个集合
    HashSet<School> set = new HashSet<>();
    // 产生了四个对象
    School s1 = new School(1, "清华大学");
    School s2 = new School(2, "北京大学");
    School s3 = new School(3, "西安交通大学");
    School s4 = new School(4, "长安大学");
    // 存放到了集合中
    set.add(s1);
    set.add(s4);
    set.add(s3);
    set.add(s2);
    // 通过迭代器遍历集合
    for (School s : set) {
        System.out.println(s);
    }
    School s5 = new School(3, "西安交通大学");
    /*
        首先通过循环来和集合中的每一个元素进行比较
        1.获取到当前元素的hash值(通过调用hashCode()来获取) 和集合中元素的hash值比较相等时
        2.当前元素和集合中元素的equals()进行比较
        3.如果都相等 则代表这个元素在集合中存在,否则 不存在
     */
    boolean b = set.contains(s5);
    System.out.println(b ? "存在" : "不存在");
    set.add(s5); // HashSet集合在存放内容时 会判断这个内容是否在集合中存在 存放不进去
    System.out.println(set.size());
}
// 学校类
public class School {
    private Integer id;
    private String name;
    /*
        还需要重写hashCode方法
     */
    public int hashCode(){
        return id; // 返回的hash值设置为id
    }
    /*
        重写equals方法 设置自己的规则
        自定义规则为:只要id一致就行
     */
    public boolean equals(Object o) {
        int myId = this.getId();
        School s = (School) o;
        int itId = s.getId();
        return myId == itId;
    }
}
```

#### TreeSet实现类

TreeSet是一个红黑树的结构,录入数据后能够进行排序,如果是自定义数据类型必须实现Comparable接口。

- **无序**:它不是一个线性结构,不知道在队列中的位置
- **有序**:在存放时会比较大的在右子节点,小的在左子节点

⚠️ 注意

1. TreeSet不能存放null值。
2. TreeSet强制排序,泛型类必须实现Comparable接口。

##### 产生对象和常见方法

```java
TreeSet<Integer> set = new TreeSet<>();
set.add(28);
set.add(99);
set.add(19);
set.add(33);
set.add(61);
set.add(33); // Set集合中不能存放重复数据
// set.add(null); ❌ TreeSet集合不能存放null
System.out.println(set);
set.remove(19);
System.out.println(set);
int len = set.size();
System.out.println(len);
boolean b = set.contains(19);
System.out.println(b);
int first = set.first(); // 获取到根结点
System.out.println(first);
// 通过迭代器来进行遍历
for (Integer i : set) {
    System.out.print(i + "\t");
}
```

##### 复杂类型在TreeSet的使用

```java
TreeSet<Lover> set = new TreeSet<>();
Lover l1 = new Lover(1, "杨超越", "💃");
Lover l2 = new Lover(2, "羽生结弦", "⛸️");
Lover l3 = new Lover(3, "谷爱凌", "🎿");
// 也需要判断元素在集合中是否存在
set.add(l1);
set.add(l2);
set.add(l3);
System.out.println(set);
// 产生了一个新对象
Lover l4 = new Lover(3, "谷爱凌", "🎿");
// TreeSet在判断是否存在时 通过compareTo方法来进行 如果返回的是0 则认为是一个对象
boolean b = set.contains(l4);
System.out.println(b ? "存在" : "不存在");
```

#### LinkedHashSet实现类

LinkedHashSet是HashSet的子类,具有HashSet的特性,也是根据元素的HashCode值来判断元素。但它使用链表维护元素的次序,**元素的顺序与添加顺序一致**。由于LinkedHashSet需要维护元素的插入顺序,因此性能上要低于HashSet。

#### Set集合实现类的分析

- HashSet的性能是最好的,因为TreeSet要排序,LinkedHashSet需要维护次序。大部分情况下我们都应使用HashSet。
- LinkedHashSet是HashSet的子类,具有HashSet的特性,又维护了插入顺序。
- 如果我们需要对Set集合进行排序,那么推荐使用TreeSet。

### Queue接口

是Collection接口的子接口,**先进先出**的一种规范体现。在实际应用中使用较少。就是队列结构,它只允许在队列的前端进行删除操作,而在队列的后端进行插入操作。

```java
// LinkedList也实现了队列接口Queue<String> queue = new LinkedList<>();queue.offer("aa"); // 同add(e);queue.offer("bb");queue.offer("cc");System.out.println(queue);String v1 = queue.poll(); // 获取到队首的内容 取出来System.out.println(v1);System.out.println(queue);String v2 = queue.element(); // 获取到队首的内容System.out.println(v2);System.out.println(queue);
```

## Map接口

Map接口采用键值对的方式来存储数据,将一个值(Value)存放到集合中,给它又起了一个别名(Key),保存具有映射关系的数据,因此,Map集合中存放两组数据,一组用于存放值,另一组用于存放键,其中值允许重复,键不允许重复。

### HashMap实现类🌟🌟🌟

HashMap是基于Hash算法实现的一个集合,是map中最常用的一个实现类。值可以重复,健不能重复,如果重复会覆盖掉原有内容。HashMap的键和值都允许存放null。键是Hash结构的。

#### 产生HashMap集合

```java
// 产生HashMap对象 存放的内容只能是int类型,起的名字(Key)是String类型Map<String, Integer> map = new HashMap<>();
```

#### HashMap的常用方法

```java
// 常用方法// 添加和修改map.put("a", 87); // 将87存放到map集合中起了一个名字amap.put("b", 97);map.put("c", 97);map.put("d", 91);map.put("d", 33); // 修改 Key重复会覆盖原有内容map.put("e", null);map.put(null, 87);System.out.println(map);// 获取int v1 = map.get("a"); // 通过键获取到值//int v2 = map.get("m"); // 不存在报错System.out.println(v1);//System.out.println(v2);// 删除map.remove("d"); // 根据Key删除指定元素System.out.println(map);// 获取长度int len = map.size();System.out.println("长度:" + len);
```

#### 排序和查找

```java
// HashMap集合和HashSet集合一致都不能排序// HashMap集合和HashSet集合查找方式一致public static void b(){    Map<String,Integer> map = new HashMap<>();    map.put("a",33);    map.put("b",46);    boolean b1 = map.containsValue(46); // 判断46是否在值集合中    boolean b2 = map.containsKey("a");// 判断a是否在键集合中    System.out.println(b1);    System.out.println(b2);}
```

#### 特有的几个方法

```java
Map<String, Integer> map = new HashMap<>();map.put("a", 87); // 将87存放到map集合中起了一个名字amap.put("b", 97);map.put("c", 97);map.put("d", 91);// 获取到键集合Set<String> keys = map.keySet(); // 获取到所有的键// 获取到值集合Collection<Integer> values = map.values(); // 获取到所有的值System.out.println(keys);System.out.println(values);
```

### TreeMap实现类

TreeMap也是一个红黑树结构,它的Key集是红黑树结构。也就是说在存放数据时会按照Key进行排序。

### Hashtable实现类

Hashtable是基于Hash算法实现的一个集合,值可以重复,健不能重复,如果重复会覆盖掉原有内容。Key集是Hash结构的。它是一个线程安全的集合。方法和HashMap一致。

### ConcurrentHashMap实现类

ConcurrentHashMap是基于Hash算法实现的一个集合,值可以重复,健不能重复,如果重复会覆盖掉原有内容。Key集是Hash结构的。它是一个分段锁的操作,把集合中的数据分别上锁,影响的面就比较小一些。

### LinkedHashMap实现类

LinkedHashMap使用双向链表来维护键值对,维护了插入的顺序,保证了迭代顺序。仍然是以Key集来维护的。

### Map实现类对于null的操作

```java
// key和value都能存放null
HashMap<String, String> map1 = new HashMap<>();
map1.put(null, null);
System.out.println(map1);
// key不能为null,value可以是null
TreeMap<String, String> map2 = new TreeMap<>();
//map2.put(null,"a");
System.out.println(map2);
// key和value都不允许为null
Hashtable<String, String> map3 = new Hashtable<>();
//map3.put(null, "a");
System.out.println(map3);
// key和value都能存放null
LinkedHashMap<String, String> map4 = new LinkedHashMap<>();
map4.put(null, null);
System.out.println(map4);
// key和value都不允许为null
ConcurrentHashMap<String, String> map5 = new ConcurrentHashMap<>();
map5.put(null, "a");
System.out.println(map5);
```

## 值传递和引用传递问题

````java
public class DemoC {

    // 原始类型 存放的是值
    public static void a() {
        int a = 1;
        List<Integer> list = new ArrayList<>();
        list.add(a); // 理解成集合中存放的是1 相当于 list.add(1);
        System.out.println(list);
        a = 4; // 重新创建了一个变量 也起了一个名字叫a
        System.out.println(list);
    }

    // 集合中存放的是对象的内存地址
    public static void b() {
        Person p = new Person(1, "张三", '男', 23);
        List<Person> list = new ArrayList<>();
        list.add(p); // 存放的是内存地址(引用)
        System.out.println(list);
        p.setName("李四"); // 修改了p 集合也会发生改变
        System.out.println(list);
    }

    // 集合中存放常量问题(String问题)
    public static void c() {
        String s = "aaa"; // 常量字符串 值不能发生改变的
        List<String> list = new ArrayList<>();
        list.add(s);
        System.out.println(list);
        s = "abc"; // 重新创建一个变量(对象)
        System.out.println(list);
    }

    // 重新创建对象问题
    public static void d() {
        Person p = new Person(1, "张三", '男', 24);
        List<Person> list = new ArrayList<>();
        list.add(p);
        System.out.println(list);
        // 新创建一个对象 还起了一个名字 另一内存地址
        p = new Person(2, "王五", '女', 22);
        System.out.println(list);
    }

    public static void main(String[] args) {
        d();
    }
}# 集合框架

**集合**:把具有相同数据类型的一组变量,汇聚成一个整体,就被称之为集合。

**集合框架**:为了表示和操作集合而规定的一种统一标准的体系结构。最简单的集合如数组、队列和列表等。任何集合框架一般包含:对外的接口、接口的实现和对集合运算的算法。

- 接口:即表示集合的抽象数据类型(规范)。接口提供了让我们对集合中所表示的内容进行单独操作的方式(标准)。
- 实现:也就是集合框架中接口的具体实现。实际上它们就是那些可复用的数据结构。
- 算法:在一个实现了某个集合框架中的接口对象身上完成了某种有用的计算的方法,例如查找、排序等。

## 接口的体系结构

![img](https://www.runoob.com/wp-content/uploads/2014/01/2243690-9cd9c896e0d512ed.gif)

## Collection接口

对单个元素进行存放的最大接口规范。针对不同的方式它有不同的实现。

### List接口

是Collection接口的子接口,主要针对于线性操作来提出的规范。

**特点**:可重复,有序的集合

#### Vector实现类

线性队列式结构的一种实现,它是线程安全的,多个线程同时对集合操作时保证了安全。

**特点**:数组结构、查询方便(只需要下标就行)、线程安全的,插入和删除的效率低下(涉及其后元素的位移)

```java
// 1.如何产生Vector类的对象
// 产生了一个Vector集合,集合中只能存放Integer类型的元素
Vector<Integer> vector = new Vector<>();
// 2.Vector类的常用方法
// 存放到集合中
vector.add(88); // 添加到集合的末尾
vector.add(64);
vector.add(1, 39); // 插入到指定位置之前
System.out.println(vector);
// 获取集合的长度
int len = vector.size();
System.out.println("集合元素个数是:" + len);
// 获取集合中的元素
int v1 = vector.get(1); // 获取指定位置的元素
System.out.println(v1);
// 修改集合指定位置的元素内容
vector.set(2, 93);
System.out.println(vector);
// 删除集合的元素
vector.remove(1); // 删除指定位置的元素
System.out.println(vector);
vector.clear(); // 清空集合
System.out.println(vector);
// 3.如何排序集合
Vector<Integer> vector = new Vector<>();
for (int i = 0; i < 10; i++) {
    int num = (int) (Math.random() * 100 + 1);
    vector.add(num);
}
System.out.println("排序之前的内容:");
System.out.println(vector);
// 通过集合框架中提供的一个算法类来完成
Collections.sort(vector); // 对集合进行升序操作
System.out.println("排序之后的内容:");
System.out.println(vector);
// 4.如何查找集合中的元素
Vector<Integer> vector = new Vector<>();
for (int i = 0; i < 10; i++) {
     int num = (int) (Math.random() * 10 + 1);
     vector.add(num);
}
System.out.println(vector);
System.out.print("Input:");
int num = scan.nextInt();
// 判断用户输入的这个元素是否存在
boolean b = vector.contains(num);
System.out.println(b ? "存在" : "不存在");
// 获取到用户输入的内容在集合中的位置 如何不存在返回-1
int index = vector.indexOf(num);
System.out.println("集合中的位置:" + index);
int index2 = vector.indexOf(num,4); // 从第五个开始查找指定元素的位置
System.out.println(index2);
```

#### Stack实现类

继承于Vector类,它有一些自身特有方法。实现了一个先进后出的堆栈。提供了5个特有的方法,基本的push和pop方法,还有获取到栈顶的peek方法,还可以通过empty方法测试堆栈是否为空,search方法检测一个元素在堆栈的位置。

**特点**:数组结构、查询方便(只需要下标就行)、线程安全的,有自身特有方法,插入和删除的效率低下(涉及其后元素的位移)

```java
// 1.如何产生集合对象
Stack<String> stack = new Stack<>();
// 2.集合的常用方法  这里只讨论特有方法,继承下来的方法不再重复讲解
// 等同于add(e);操作添加到集合的末尾
stack.push("aa");
stack.push("bb");
stack.push("cc");
stack.push("dd");
System.out.println(stack);
// 获取集合的元素
// 获取到集合中最后位置的元素
String v3 = stack.peek();
String v4 = stack.peek();
System.out.println(v3);
System.out.println(v4);
System.out.println(stack);
// 获取到集合中最后位置的元素 并会删除这个元素
String v1 = stack.pop();
String v2 = stack.pop();
System.out.println(v1);
System.out.println(v2);
System.out.println(stack);
// 检测堆栈是否为空
boolean b = stack.empty();
System.out.println(b);
// 检测堆栈是否存在某个元素
int index = stack.search("aa");
System.out.println("返回的位置是:" + index);
```

#### ArrayList实现类🌟🌟🌟🌟

就是传说中的**动态数组**,也是我们最常用的集合。它允许任何符合规则的元素插入。每一个ArrayList初始容量都是0,当第一次向集合中添加元素时,系统会**自动**扩充集合的长度,以后每一次添加元素时如果容量不够仍会自动扩容。和Vector类是基本一致的,除过它不是线程安全的。目前的规范标准都推荐使用ArrayList。

**特点**:数组结构、查询方便(只需要下标就行)、线程不安全的,插入和删除的效率低下(涉及其后元素的位移)

##### 基本数据类型操作

```java
public static void a() {
    // 1.如何产生对象
    // ArrayList<String> list = new ArrayList<>();
    // 一般推荐写法
    List<String> list = new ArrayList<>();
    // 2.集合的常用方法
    list.add("aa");
    list.add("bb");
    list.add("cc");
    list.add(2, "dd");
    System.out.println(list);
    String v1 = list.get(1);
    System.out.println(v1);
    list.set(2, "ee");
    System.out.println(list);
    list.remove(1); // 删除指定位置的元素
    list.remove("aa"); // 删除指定内容的元素
    System.out.println(list);
    list.clear();
    System.out.println(list);
    int len = list.size();
    System.out.println("集合的长度:" + len);
    boolean b = list.isEmpty();
    System.out.println("是否是空:" + b);
}

// 如何排序常见数据类型的集合
public static void b() {
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        int num = (int) (Math.random() * 100 + 1);
        list.add(num);
    }
    System.out.println("排序之前的内容:");
    System.out.println(list);
    // 通过集合框架中提供的一个算法类来完成
    Collections.sort(list); // 对集合进行升序操作
    System.out.println("排序之后的内容:");
    System.out.println(list);
}

private static Scanner scan = new Scanner(System.in);

// 查找元素在集合中的位置
public static void c() {
    System.out.println("Input:");
    int num = scan.nextInt();
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        int num1 = (int) (Math.random() * 10 + 1);
        list.add(num1);
    }
    System.out.println(list);
    boolean b = list.contains(num);
    System.out.println("是否存在:" + b);
    int index1 = list.indexOf(num); // 找出第一次出现的位置 不存在返回-1
    int index2 = list.lastIndexOf(num); // 找出最后一次出现的位置 不存在返回-1
    System.out.println(index1);
    System.out.println(index2);
}
```

##### 复杂数据类型操作

```java
// ArrayList对复杂类型的操作
public class DemoD {
    // 基本的创建对象,CRUD(增删改查)的方法
    public static void a() {
        // 产生了一个集合,这个集合只能存放Person类型的数据
        List<Person> list = new ArrayList<>();
        // 产生了四个对象
        Person p1 = new Person(1, "张三", '男', 23);
        Person p2 = new Person(2, "李四", '女', 21);
        Person p3 = new Person(3, "王武", '男', 28);
        Person p4 = new Person(4, "马六", '男', 25);
        // 将这四个对象存放到集合中
        list.add(p1);
        list.add(p2);
        list.add(1, p3);
        list.add(p4);
        System.out.println(list);
        // 获取到指定位置的元素
        Person p5 = list.get(3);
        System.out.println(p5);
        // 修改指定位置的元素
        Person p6 = new Person(5, "大白", '男', 19);
        list.set(1, p6);
        System.out.println(list);
        // 删除元素
        list.remove(1);
        list.remove(p1);
        System.out.println(list);
        // 清空
        list.clear();
        // 获取长度
        int len = list.size();
        System.out.println(len);
    }


    // 讲解了复杂(自定义)数据类型的排序问题
    /*
        1.泛型类必须实现Comparable接口
        2.泛型类重写compareTo方法,自定义规则
        3.调用Collections.sort(list);来进行排序
     */
    public static void b() {
        List<Person> list = new ArrayList<>();
        Person p1 = new Person(1, "张三", '男', 23);
        Person p2 = new Person(2, "李四", '女', 21);
        Person p3 = new Person(3, "王武", '男', 28);
        Person p4 = new Person(4, "马六", '男', 25);
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        list.add(p2);
        System.out.println("排序之前的集合:");
        for (int i = 0; i < list.size(); i++) {
            Person p = list.get(i);
            System.out.println(p);
        }
        // 如何对集合排序 要求泛型必须实现一个接口Comparable
        Collections.sort(list);
        System.out.println("排序之后的集合:");
        for (int i = 0; i < list.size(); i++) {
            Person p = list.get(i);
            System.out.println(p);
        }
    }

    /*
        讲解了复杂数据类型的查找问题
        1.重写equals方法 自定义规则
        2.调用contains或者indexOf方法
     */
    public static void c() {
        List<Person> list = new ArrayList();
        Person p1 = new Person(1, "张三", '男', 26);
        Person p2 = new Person(2, "李四", '女', 22);
        Person p3 = new Person(3, "王武", '男', 21);
        Person p4 = new Person(4, "马六", '男', 27);
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        int len = list.size();
        System.out.println("集合长度是:" + len);
        boolean b1 = list.contains(p1);
        System.out.println(b1 ? "存在" : "不存在");
        int index1 = list.indexOf(p1);
        System.out.println("位置是:" + index1);
        System.out.println("----------------------------------------------");
        // 只关心对象的值在集合中的元素是否有重复
        // 产生了一个新对象
        Person p5 = new Person(3, "王武", '男', 21);
        System.out.println("p3和p5的内存地址是否相等?" + (p3 == p5));
        System.out.println("p3和p5的equals方法返回结果是否相等?" + p3.equals(p5));
        boolean b2 = list.contains(p5);
        System.out.println(b2 ? "存在" : "不存在");
        int index2 = list.indexOf(p5);
        System.out.println("位置是:" + index2);
        System.out.println("----------------------------------------------");
        Person p6 = p3;
        System.out.println("p3和p6是否相等?" + (p3 == p6));
        boolean b3 = list.contains(p6);
        System.out.println(b3 ? "存在" : "不存在");
        int index3 = list.indexOf(p6);
        System.out.println("位置是:" + index3);
    }
    public static void main(String[] args) {
        c();
    }

}
```

#### LinkedList实现类

是List接口的一种实现,它是一种**双向链表**结构,在执行查询时效率比较低下,但是插入和删除效率比较高。

```java
/*
    1.如何产生集合对象
    2.集合的常用方法
    3.如何查找和排序
    4.其他的注意事项
 */
public class DemoB {

    public static void a() {
        // 产生LinkedList集合对象
        LinkedList<String> list = new LinkedList<>();
        // 常用方法
        list.add("aa");
        list.add("bb");
        list.add(1, "cc");
        // 特有方法
        list.addFirst("dd"); // 添加到第一个位置
        list.addLast("ee"); // 就是list.add("ee");
        System.out.println(list);
        String v1 = list.get(1);
        // 特有方法
        String v2 = list.getFirst();
        String v3 = list.getLast();
        System.out.println("获取指定位置元素:" + v1);
        System.out.println("获取第一个元素:" + v2);
        System.out.println("获取最后一个元素:" + v3);
        list.set(2, "ff");
        System.out.println(list);
        list.remove(1);
        list.remove("ff");
        // 特有方法
        list.removeFirst();
        list.removeLast();
        System.out.println(list);
        int len = list.size();
        System.out.println("长度是:" + len);
        list.clear();
        boolean b = list.isEmpty();
        System.out.println(b ? "空的" : "非空的");
    }

    private static Scanner scan = new Scanner(System.in);

    // 基本类型的排序和查找
    public static void b() {
        LinkedList<Integer> list = new LinkedList<>();
        for (int i = 0; i < 10; i++) {
            int num = (int) (Math.random() * 100 + 1);
            list.add(num);
        }
        System.out.println(list);
        Collections.sort(list); // List中的四个实现类它们的排序是一样的
        System.out.println(list);
        // List中的四个实现类它们的查找也是一样的
        System.out.println("请输入:");
        int num = scan.nextInt();
        boolean b = list.contains(num);
        int index1 = list.indexOf(num);
        int index2 = list.lastIndexOf(num);
        System.out.println("是否存在?" + b);
        System.out.println("第一次出现的位置:" + index1);
        System.out.println("最后一次出现的位置:" + index2);
    }

    // 自定义类型的排序和查找
    public static void c() {
        LinkedList<Person> list = new LinkedList<>();
        Person p1 = new Person(1, "张三", '男', 21);
        Person p2 = new Person(2, "李四", '女', 27);
        Person p3 = new Person(3, "王武", '男', 23);
        Person p4 = new Person(4, "马六", '男', 25);
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);
        // 排序之前:
        for (Person p : list) {
            System.out.println(p);
        }
        System.out.println("------------------------------------------------");
        Collections.sort(list); // 同ArrayList的写法
        // 排序之后:
        for (Person p : list) {
            System.out.println(p);
        }
        // 查找 和ArrayList写法完全一致
        System.out.println("------------------------------------------------");
        Person p5 = new Person(3, "王五", '男', 26);
        boolean b = list.contains(p5);
        int index = list.indexOf(p5);
        System.out.println("是否存在?" + b);
        System.out.println("第一次出现的位置:" + index);
    }

    public static void main(String[] args) {
        c();
    }
}
```

#### List集合实现类的分析

- ArrayList、Vector和Stack都是动态数组,它们查询速度很快,但是插入删除速度慢。
- LinkedList是双向链表结构,插入删除块,查询速度慢,
- Vector是线程安全的集合,Stack是Vector的子类,它是一个先进后出的结构。
- 一般情况下,我们推荐使用ArrayList。

### Set接口

是Collection接口的子接口,它主要针对于散列式接口来提出的规范。

**特点**:不可重复(不允许存放重复的元素),无序(没有索引下标)。

#### HashSet实现类🌟🌟🌟

HashSet是Set集合最常用的实现类,经典表现。是按照Hash算法来存储元素的,因此具有很好的存放功能。

**特点**:

1. 不保证元素的顺序
2. HashSet不是线程安全的
3. 可以存放null值
4. 值的内容不允许重复

##### 产生HashSet集合

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

##### 常见的方法

```java
//添加元素
set.add(99);
set.add(23);
set.add(56);
set.add(78);
/*
    // 不能存放重复内容,存放时要判断元素在集合中是否存在
    首先通过循环来和集合中的每一个元素进行比较
      1.获取到当前元素的hash值(通过调用hashCode()来获取) 和集合中元素的hash值比较相等时
      2.当前元素和集合中元素的equals()进行比较
      3.如果都相等 则代表这个元素在集合中存在,否则 不存在
*/
set.add(56); 
set.add(null);
System.out.println(set);
// 删除元素
set.remove(23); // 只能删除指定元素  不能删除索引
System.out.println(set);
// 获取元素 没有 无法获取
// 只能通过迭代器来遍历
for (Integer i : set) {
    System.out.print(i + "\t");
}
System.out.println();
// 修改元素 无法修改

int len = set.size();
System.out.println(len);
```

##### 查找集合中是否存在内容

```java
public static void c() {
    // 产生了一个集合
    HashSet<School> set = new HashSet<>();
    // 产生了四个对象
    School s1 = new School(1, "清华大学");
    School s2 = new School(2, "北京大学");
    School s3 = new School(3, "西安交通大学");
    School s4 = new School(4, "长安大学");
    // 存放到了集合中
    set.add(s1);
    set.add(s4);
    set.add(s3);
    set.add(s2);
    // 通过迭代器遍历集合
    for (School s : set) {
        System.out.println(s);
    }
    School s5 = new School(3, "西安交通大学");
    /*
        首先通过循环来和集合中的每一个元素进行比较
        1.获取到当前元素的hash值(通过调用hashCode()来获取) 和集合中元素的hash值比较相等时
        2.当前元素和集合中元素的equals()进行比较
        3.如果都相等 则代表这个元素在集合中存在,否则 不存在
     */
    boolean b = set.contains(s5);
    System.out.println(b ? "存在" : "不存在");
    set.add(s5); // HashSet集合在存放内容时 会判断这个内容是否在集合中存在 存放不进去
    System.out.println(set.size());
}
// 学校类
public class School {
    private Integer id;
    private String name;
    /*
        还需要重写hashCode方法
     */
    public int hashCode(){
        return id; // 返回的hash值设置为id
    }
    /*
        重写equals方法 设置自己的规则
        自定义规则为:只要id一致就行
     */
    public boolean equals(Object o) {
        int myId = this.getId();
        School s = (School) o;
        int itId = s.getId();
        return myId == itId;
    }
}
```

#### TreeSet实现类

TreeSet是一个红黑树的结构,录入数据后能够进行排序,如果是自定义数据类型必须实现Comparable接口。

- **无序**:它不是一个线性结构,不知道在队列中的位置
- **有序**:在存放时会比较大的在右子节点,小的在左子节点

⚠️ 注意

1. TreeSet不能存放null值。
2. TreeSet强制排序,泛型类必须实现Comparable接口。

##### 产生对象和常见方法

```java
TreeSet<Integer> set = new TreeSet<>();
set.add(28);
set.add(99);
set.add(19);
set.add(33);
set.add(61);
set.add(33); // Set集合中不能存放重复数据
// set.add(null); ❌ TreeSet集合不能存放null
System.out.println(set);
set.remove(19);
System.out.println(set);
int len = set.size();
System.out.println(len);
boolean b = set.contains(19);
System.out.println(b);
int first = set.first(); // 获取到根结点
System.out.println(first);
// 通过迭代器来进行遍历
for (Integer i : set) {
    System.out.print(i + "\t");
}
```

##### 复杂类型在TreeSet的使用

```java
TreeSet<Lover> set = new TreeSet<>();
Lover l1 = new Lover(1, "杨超越", "💃");
Lover l2 = new Lover(2, "羽生结弦", "⛸️");
Lover l3 = new Lover(3, "谷爱凌", "🎿");
// 也需要判断元素在集合中是否存在
set.add(l1);
set.add(l2);
set.add(l3);
System.out.println(set);
// 产生了一个新对象
Lover l4 = new Lover(3, "谷爱凌", "🎿");
// TreeSet在判断是否存在时 通过compareTo方法来进行 如果返回的是0 则认为是一个对象
boolean b = set.contains(l4);
System.out.println(b ? "存在" : "不存在");
```

#### LinkedHashSet实现类

LinkedHashSet是HashSet的子类,具有HashSet的特性,也是根据元素的HashCode值来判断元素。但它使用链表维护元素的次序,**元素的顺序与添加顺序一致**。由于LinkedHashSet需要维护元素的插入顺序,因此性能上要低于HashSet。

#### Set集合实现类的分析

- HashSet的性能是最好的,因为TreeSet要排序,LinkedHashSet需要维护次序。大部分情况下我们都应使用HashSet。
- LinkedHashSet是HashSet的子类,具有HashSet的特性,又维护了插入顺序。
- 如果我们需要对Set集合进行排序,那么推荐使用TreeSet。

### Queue接口

是Collection接口的子接口,**先进先出**的一种规范体现。在实际应用中使用较少。就是队列结构,它只允许在队列的前端进行删除操作,而在队列的后端进行插入操作。

```java
// LinkedList也实现了队列接口
Queue<String> queue = new LinkedList<>();
queue.offer("aa"); // 同add(e);
queue.offer("bb");
queue.offer("cc");
System.out.println(queue);
String v1 = queue.poll(); // 获取到队首的内容 取出来
System.out.println(v1);
System.out.println(queue);
String v2 = queue.element(); // 获取到队首的内容
System.out.println(v2);
System.out.println(queue);
```

## Map接口

Map接口采用键值对的方式来存储数据,将一个值(Value)存放到集合中,给它又起了一个别名(Key),保存具有映射关系的数据,因此,Map集合中存放两组数据,一组用于存放值,另一组用于存放键,其中值允许重复,键不允许重复。

### HashMap实现类🌟🌟🌟

HashMap是基于Hash算法实现的一个集合,是map中最常用的一个实现类。值可以重复,健不能重复,如果重复会覆盖掉原有内容。HashMap的键和值都允许存放null。键是Hash结构的。

#### 产生HashMap集合

```java
// 产生HashMap对象 存放的内容只能是int类型,起的名字(Key)是String类型
Map<String, Integer> map = new HashMap<>();
```

#### HashMap的常用方法

```java
// 常用方法
// 添加和修改
map.put("a", 87); // 将87存放到map集合中起了一个名字a
map.put("b", 97);
map.put("c", 97);
map.put("d", 91);
map.put("d", 33); // 修改 Key重复会覆盖原有内容
map.put("e", null);
map.put(null, 87);
System.out.println(map);
// 获取
int v1 = map.get("a"); // 通过键获取到值
//int v2 = map.get("m"); // 不存在报错
System.out.println(v1);
//System.out.println(v2);
// 删除
map.remove("d"); // 根据Key删除指定元素
System.out.println(map);
// 获取长度
int len = map.size();
System.out.println("长度:" + len);
```

#### 排序和查找

```java
// HashMap集合和HashSet集合一致都不能排序
// HashMap集合和HashSet集合查找方式一致
public static void b(){
    Map<String,Integer> map = new HashMap<>();
    map.put("a",33);
    map.put("b",46);
    boolean b1 = map.containsValue(46); // 判断46是否在值集合中
    boolean b2 = map.containsKey("a");// 判断a是否在键集合中
    System.out.println(b1);
    System.out.println(b2);
}
```

#### 特有的几个方法

```java
Map<String, Integer> map = new HashMap<>();
map.put("a", 87); // 将87存放到map集合中起了一个名字a
map.put("b", 97);
map.put("c", 97);
map.put("d", 91);
// 获取到键集合
Set<String> keys = map.keySet(); // 获取到所有的键
// 获取到值集合
Collection<Integer> values = map.values(); // 获取到所有的值
System.out.println(keys);
System.out.println(values);
```

### TreeMap实现类

TreeMap也是一个红黑树结构,它的Key集是红黑树结构。也就是说在存放数据时会按照Key进行排序。

### Hashtable实现类

Hashtable是基于Hash算法实现的一个集合,值可以重复,健不能重复,如果重复会覆盖掉原有内容。Key集是Hash结构的。它是一个线程安全的集合。方法和HashMap一致。

### ConcurrentHashMap实现类

ConcurrentHashMap是基于Hash算法实现的一个集合,值可以重复,健不能重复,如果重复会覆盖掉原有内容。Key集是Hash结构的。它是一个分段锁的操作,把集合中的数据分别上锁,影响的面就比较小一些。

### LinkedHashMap实现类

LinkedHashMap使用双向链表来维护键值对,维护了插入的顺序,保证了迭代顺序。仍然是以Key集来维护的。

### Map实现类对于null的操作

```java
// key和value都能存放null
HashMap<String, String> map1 = new HashMap<>();
map1.put(null, null);
System.out.println(map1);
// key不能为null,value可以是null
TreeMap<String, String> map2 = new TreeMap<>();
//map2.put(null,"a");
System.out.println(map2);
// key和value都不允许为null
Hashtable<String, String> map3 = new Hashtable<>();
//map3.put(null, "a");
System.out.println(map3);
// key和value都能存放null
LinkedHashMap<String, String> map4 = new LinkedHashMap<>();
map4.put(null, null);
System.out.println(map4);
// key和value都不允许为null
ConcurrentHashMap<String, String> map5 = new ConcurrentHashMap<>();
map5.put(null, "a");
System.out.println(map5);
```

## 值传递和引用传递问题

```java
public class DemoC {

    // 原始类型 存放的是值
    public static void a() {
        int a = 1;
        List<Integer> list = new ArrayList<>();
        list.add(a); // 理解成集合中存放的是1 相当于 list.add(1);
        System.out.println(list);
        a = 4; // 重新创建了一个变量 也起了一个名字叫a
        System.out.println(list);
    }

    // 集合中存放的是对象的内存地址
    public static void b() {
        Person p = new Person(1, "张三", '男', 23);
        List<Person> list = new ArrayList<>();
        list.add(p); // 存放的是内存地址(引用)
        System.out.println(list);
        p.setName("李四"); // 修改了p 集合也会发生改变
        System.out.println(list);
    }

    // 集合中存放常量问题(String问题)
    public static void c() {
        String s = "aaa"; // 常量字符串 值不能发生改变的
        List<String> list = new ArrayList<>();
        list.add(s);
        System.out.println(list);
        s = "abc"; // 重新创建一个变量(对象)
        System.out.println(list);
    }

    // 重新创建对象问题
    public static void d() {
        Person p = new Person(1, "张三", '男', 24);
        List<Person> list = new ArrayList<>();
        list.add(p);
        System.out.println(list);
        // 新创建一个对象 还起了一个名字 另一内存地址
        p = new Person(2, "王五", '女', 22);
        System.out.println(list);
    }

    public static void main(String[] args) {
        d();
    }
}
```
````

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/70713.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI赋能花样滑冰,景联文科技提供3D数据标注业务

在本届北京冬奥会花样滑冰男子单人自由滑中&#xff0c;日本选手羽生结弦如约挑战公认难度极高花滑动作4A&#xff08;阿克塞尔4周跳&#xff09;&#xff0c;虽然结局有些遗憾&#xff0c;在落地时不慎摔倒&#xff0c;并未挑战成功&#xff0c;最终以排名第四的总成绩无缘领奖…

一文读懂MySQL常用语法

MySQL查询语句链接地址 MySQL是什么&#xff1f; 成为MySQL大神的基础~ 数据类型 数值&#xff1a;整数&#xff0c;浮点数(小数) 日期&#xff1a;年&#xff0c;年月日&#xff0c;时分秒&#xff0c;年月日时分秒 字符串&#xff1a;文本类型字符串&#xff0c;二进制类型…

冬奥幕后故事:从低碳火炬到AI裁判,十四年后中国科技再上场

北京冬奥会开幕后&#xff0c;一个段子在社交媒体上流传甚广&#xff1a;“夏奥开幕式和冬奥开幕式就差半年&#xff0c;这半年人类科技进步真大啊。” 冬奥季终于到来。 2月4日晚&#xff0c;北京冬奥会开幕式来到了万众瞩目的主火炬点燃时刻&#xff0c;两名运动员共同点燃…

python实现图片切九宫格拼图

上一篇文章写道照片切成正方形&#xff0c;这篇文章将介绍&#xff0c;正方形怎么切割成九宫格&#xff0c;自己实现的九宫格发朋友很炫的。 先上代码&#xff1a; # -*- coding: utf-8 -*-from PIL import Image import sys# 将图片填充为正方形 def fill_image(image):width…

python实现图片切正方形

想做个照片切规则的正方形用来做九宫图&#xff0c;一般真实照片都是长方形那种&#xff0c;我见过别人把找照片填充成正方形&#xff0c;然后九宫格实在是太丑了&#xff0c;我喜欢整张图全是照片的。 不多赘述&#xff0c;上代码&#xff1a; import os from random import…

python深度学习基于pytorch——tensor中逐元素计算addcdiv()、clamp()

对tensor中的元素按个计算操作&#xff0c;方法如下图所示&#xff1a; 主要就是tensor之间的运算&#xff0c;已经附加代码输出部分&#xff0c;很容易理解。 import torch #coco #逐元素操作 torch.manual_seed(0) t torch.randn(1, 3) print(t) #tensor([[ 1.5410, -0.293…

如何有效追热点打造爆款作品,教你快速创作

追热点是小编必备的使命&#xff0c;没有热点的文章&#xff0c;就像没有珍珠的奶茶&#xff01;没有灵魂&#xff01;“拆解、模仿、反馈、总结、反复”&#xff0c;是助我们在任何领域从菜鸟到高手的秘密武器。今天就给大家介绍一下&#xff0c;追热点有什么必备姿势&#xf…

java集合框架

java集合框架 集合&#xff1a;把具有相同数据类型的一组变量&#xff0c;汇聚成一个整体&#xff0c;就被称之为集合。 集合框架&#xff1a;为了表示和操作集合而规定的一种统一标准的体系结构。最简单的集合如数组、队列和列表等。任何集合框架一般包含&#xff1a;对外的…

python实现 pdf转png格式

转换的图片要实现给固定像素坐标生成RGB值&#xff0c;找了好几段代码只能转换不能进行第二步 不说了&#xff0c;发出来就是解决了&#xff0c;先上代码&#xff1a; #!/usr/bin/env python # -*- coding:utf-8 -*- # Time : 2022/6/27 14:45 # Author : coco # File : tes…

css3学习(01认知,选择器,样式)

文章目录 一 基础认知1.1 CSS的介绍1.2 CSS语法规则1.3 CSS引入方式1.4 CSS常见三种引入方式的特点区别&#xff08;书写位置、作用范围、使用场景&#xff09; 二 基础选择器2.1 标签选择器2.2 类选择器2.3 id选择器2.4 通配符选择器 三 字体和文本样式【1】字体样式3.1.1 字体…

【CSS】——cascading stylesheets层叠式样式表

目录 0、CSS介绍 1、CSS语句组成 2、CSS选择器的选择方式 1&#xff09;CSS选择器的方式和选择器大全&#xff1a; 2&#xff09;常见的三种方式&#xff1a; 3、添加CSS方式 1&#xff09;外部样式表 html调用css代码 css文件 html文件 展示 2&#xff09;内部样式表…

汇佳学校|肖紫兮:花滑冠军+学科全优,背后有何秘诀?

隋文静、韩聪、申雪、赵宏博、羽生结弦、庞清、佟健……一连串热门花滑运动员/教练的名字闪耀了北京2022冬奥会&#xff0c;也让这项兼具优美与力量的冰上运动项目在大众之间火爆起来。 在汇佳&#xff0c;就有一名这样的冰上花滑运动员&#xff1a;默默苦练9年时间&#xff0…

从撞“新秀墙”到带团队,XTransfer海归码农升级之路

近来&#xff0c;互联网大厂纷纷被爆裁员&#xff0c;有些公司整个部门都被裁掉&#xff0c;有的应届生刚办理入职就被裁。几年前毕业进大厂是年轻人的首选&#xff0c;而如今大厂光芒正在逐渐褪去。 刚毕业不久的年轻人&#xff0c;应该是什么状态&#xff1f;很多人懵懵懂懂&…

HTML常用标签-1

1、标题标签 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width…

HTML简单介绍及你的第一个设计

一、HTML是啥&#xff1f; HTML的全称为超文本标记语言&#xff0c;英文名&#xff08;Hyper Text Markup Language&#xff09;是一种标记语言。它包括一系列标签&#xff0e;通过这些标签可以将网络上的文档格式统一&#xff0c;使分散的Internet资源连接为一个逻辑整体。HT…

数据处理Pandas学习笔记(一)

import pandas as pdpandas值series创建 t pd.Series([1, 2, 31, 12, 3, 4]) t0 1 1 2 2 31 3 12 4 3 5 4 dtype: int64type(t)pandas.core.series.Seriesseries指定索引 t2 pd.Series([1,23,3,2,3],indexlist(abcde)) t2a 1 b 23 c 3 d …

Vue学习笔记

点击查看视频 一、如何使用Vue 1.定义vue作用域 2.创建Vue对象 二、Vue重要的属性 el:指定绑定的容器 data:数据代理绑定数据 methods:写方法 在methods里不传参数默认传event参数&#xff0c;this是vm(即Vue创建的对象)&#xff0c;如果写箭头函数的时候会传windows&#x…

为了偶像羽生结弦学习日语,花6k报的网课,有继承资料的嘛~

先说一下是我的情况我是之前在电视上面看到羽生结弦才决定开始学日语的&#xff0c;是先自学的&#xff0c;然后报的网课过了n1。日语自学——狗都不学&#xff01; 自学的时候五十音想起来就练一下&#xff0c;跟着音频读一下。花了蛮长时间才真的记住。还有促音也不知…

如何检查手机上的 App 是不是正版?

作者 | Aditi Bhatnagar 译者 | 苏本如&#xff0c;责编 | 郭芮 头图 | CSDN 下载自视觉中国 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 以下为译文&#xff1a; 仔细看看你的安卓手机上的应用程序&#xff0c;你如何确保它们都是正版的&#xff1f;也就是说…

平面图

一 平面图概念 可以看成可平面图和平面图是同构的。 二 平面图性质 平面图的所有面的次数之和等于边数的两倍。 三 图的嵌入性问题 暂略