Java

Java 知识量:11 - 45 - 220

8.2 队列和数组><

队列- 8.2.1 -

Java中的队列是一种数据结构,它遵循先进先出(FIFO)的原则,即最早进入队列的元素会最先被移除。

Java的集合框架中提供了Queue接口,它定义了一些基本的队列操作,如添加元素、移除元素、检查队列是否为空等。Queue接口有很多实现类,如LinkedList、ArrayDeque、PriorityQueue等,它们提供了不同的性能和功能。

例如,LinkedList类实现了Queue接口,它可以将元素按照它们被添加到队列的顺序进行存储,同时提供了add()和remove()方法来添加和移除元素。ArrayDeque类也是一个常用的队列实现类,它使用动态数组实现,可以进行快速的随机访问,但插入和删除操作可能较慢。PriorityQueue类按照元素的自然顺序或者自定义比较器进行排序,每次移除的是最小元素或者最大元素。

除了Queue接口之外,Java还提供了其他类型的队列实现,如ConcurrentLinkedQueue和ArrayBlockingQueue等。ConcurrentLinkedQueue是一个非阻塞队列,它使用链表实现,可以进行高效的并发访问。ArrayBlockingQueue是一个基于数组实现的阻塞队列,当队列已满时,无法继续添加元素,需要等待其他线程移除元素后才能继续添加。

Queue接口- 8.2.2 -

Queue接口提供了队列的基本操作,包括添加元素、移除元素、查看队列是否为空、查看队列大小等。

Queue接口的主要特点包括:

  • FIFO(先进先出):Queue中的元素遵循先进先出的原则,即最先添加到队列的元素会最先被移除。

  • 异步操作:对于大部分Queue实现类来说,修改操作(如add、remove)不是原子的,而迭代操作是原子的。这意味着在迭代过程中修改Queue可能会导致不可预知的结果。

  • 排序:Queue接口并没有强制要求元素排序,但是它的某些实现类(如PriorityQueue)会根据元素的自然顺序或者自定义比较器进行排序。

Queue接口的一些常用实现类包括LinkedList、ArrayDeque、PriorityQueue、ArrayBlockingQueue、ConcurrentLinkedQueue等。这些实现类提供了不同的性能和功能,可以根据具体需求选择使用。

在使用Queue时,需要注意并发访问的问题,因为多个线程同时访问Queue可能会导致数据不一致或者出现其他异常情况。如果需要在多线程环境下使用Queue,可以使用线程安全的Queue实现类(如ConcurrentLinkedQueue)或者使用同步块来保证线程安全。

BlockingQueue接口- 8.2.3 -

Java的BlockingQueue接口是Queue接口的子接口,它扩展了Queue接口,添加了一些阻塞操作。BlockingQueue接口中的方法会阻塞直到有合适的条件满足,或者直到抛出异常。

BlockingQueue接口的主要特点包括:

  • 阻塞操作:BlockingQueue中的方法会阻塞直到有合适的条件满足,或者直到抛出异常。这些条件可以是队列已满,队列为空,超时等。

  • 多线程安全:BlockingQueue实现类通常都具有线程安全特性,可以在多线程环境下安全使用。

  • 优先级队列:BlockingQueue的实现类PriorityBlockingQueue是一个优先级队列,元素按照自然顺序或者比较器定义的顺序进行排序。

BlockingQueue接口的一些常用实现类包括ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue、SynchronousQueue等。这些实现类提供了不同的性能和功能,可以根据具体需求选择使用:

  • ArrayBlockingQueue:是一个基于数组的实现,它使用静态数组来存储元素,同时使用两个指针来标记队列头和队列尾的位置。它支持多线程安全,并且可以指定队列大小。

  • LinkedBlockingQueue:是一个基于链表实现的队列,它使用一个链表来存储元素,同时使用两个指针来标记队列头和队列尾的位置。它支持多线程安全,并且可以动态扩展队列大小。

  • PriorityBlockingQueue:是一个优先级队列,它使用堆来存储元素,同时根据元素的自然顺序或者自定义比较器来排序。它支持多线程安全,并且可以动态扩展队列大小。

  • DelayQueue:是一个延迟队列,它使用一个优先级队列来实现,元素只有在等待时间过后才能出队。它支持多线程安全,并且可以动态扩展队列大小。

  • SynchronousQueue:是一个同步队列,它不存储任何元素,所有尝试添加或移除元素的操作都会直接失败。它支持多线程安全,但不支持容量限制。

对象数组- 8.2.4 -

在Java中,数组可以包含任何数据类型,包括对象。当数组中包含对象时,这个数组通常被称为对象数组。以下是如何创建和初始化一个对象数组的示例:

// 定义一个类  
public class Student {  
    String name;  
    int age;  
  
    // 构造函数  
    public Student(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        // 创建一个Student对象数组  
        Student[] students = new Student[3];  
  
        // 初始化数组元素  
        students[0] = new Student("Alice", 20);  
        students[1] = new Student("Bob", 21);  
        students[2] = new Student("Charlie", 22);  
  
        // 打印学生信息  
        for (Student student : students) {  
            System.out.println("Name: " + student.name + ", Age: " + student.age);  
        }  
    }  
}

在这个例子中,首先定义了一个Student类,包含两个属性:name和age,以及一个构造函数用于初始化这两个属性。

然后在main方法中,创建了一个Student对象数组students,数组长度为3。接着,通过索引给数组的每个元素赋值新的Student对象。最后,使用增强的for循环遍历数组并打印每个学生的信息。

注意:Java中的数组长度在创建时确定,并且之后不能更改。

处理对象数组的方法- 8.2.5 -

Java的Arrays类是一个非常有用的工具,它可以用来处理各种类型的数组,包括对象数组。以下是一些使用Arrays类处理对象数组的常见方法:

1、填充(fill):可以用一个固定值填充整个数组

MyClass[] myObjects = new MyClass[10];  
Arrays.fill(myObjects, new MyClass());

2、比较(compare):可以比较两个数组是否相等

MyClass[] myObjects1 = new MyClass[10];  
MyClass[] myObjects2 = new MyClass[10];  
if (Arrays.equals(myObjects1, myObjects2)) {  
    System.out.println("两个数组相等");  
}

3、排序(sort):可以对数组进行排序

MyClass[] myObjects = new MyClass[10];  
// 填充数组元素...  
Arrays.sort(myObjects);

4、搜索(binarySearch):可以在排序后的数组中执行二分查找

MyClass[] myObjects = new MyClass[10];  
// 填充并排序数组...  
int index = Arrays.binarySearch(myObjects, new MyClass());

5、复制(copyOf):可以复制一个数组

MyClass[] myObjects1 = new MyClass[10];  
MyClass[] myObjects2 = Arrays.copyOf(myObjects1, 20); // 复制myObjects1到新的20长度的数组

6、操作(asList):可以将数组转换为List

MyClass[] myObjects = new MyClass[10];  
List<MyClass> myList = Arrays.asList(myObjects);

注意:上述所有操作并不修改原始数组,而是返回一个新的数组或列表。另外,对于非基础类型的数组,Arrays类只能进行浅比较,即比较对象引用是否相等,而不会比较对象的实际内容是否相等。如果需要深度比较,可能需要自己实现比较逻辑。