1、char[]、String、StringBuffer、StringBuilder
1.1、char[]和String
在 Java 中,String 和 char[] 都用来表示字符串,但它们有一些重要的区别。
String:
- 特点:- String是一个不可变的类,一旦创建,其内容就不能被修改。
- String对象的值在创建后不能被修改,任何对- String类的操作都会返回一个新的- String对象。
- String对象是线程安全的,可以安全地被多个线程共享。
 
- 常用方法:- int length(): 返回- String的长度。
- char charAt(int index): 返回指定索引处的字符。
- String substring(int beginIndex, int endIndex): 返回一个新的字符串,它是此字符串的一个子字符串。
- boolean equals(Object anObject): 将此字符串与指定对象进行比较,如果是字符串且内容相同,则返回- true。
- boolean contains(CharSequence s): 判断此字符串中是否包含指定的字符序列。
- String toLowerCase(): 将字符串转换为小写形式。
- String toUpperCase(): 将字符串转换为大写形式。
- String trim(): 返回字符串的副本,删除了前导空白和尾部空白。
- String replace(CharSequence target, CharSequence replacement): 将此字符串中的指定字符序列替换为另一个字符序列。
 
char[]:
- 特点:- char[]是一个可变的字符数组,可以通过修改数组元素来修改字符串的内容。
- char[]的长度可以根据需要进行调整。
- char[]是一个原始类型的数组,因此在底层的实现上更接近硬件层。
 
- 常用方法:- 由于 char[]是一个原始类型的数组,因此它没有定义像String类那样的常用方法。通常,对char[]进行操作时,需要使用循环、索引访问等方法来实现。
 
- 由于 
示例代码:
public class Main {
    public static void main(String[] args) {
        // 使用 String 类的常用方法
        String str = "Hello, World!";
        System.out.println("Length: " + str.length());
        System.out.println("Character at index 7: " + str.charAt(7));
        System.out.println("Substring from index 1 to 5: " + str.substring(1, 6));
        System.out.println("Is 'World' contained: " + str.contains("World"));
        System.out.println("Lowercase: " + str.toLowerCase());
        System.out.println("Uppercase: " + str.toUpperCase());
        System.out.println("Trimmed: " + str.trim());
        System.out.println("Replaced: " + str.replace("World", "Java"));
        // 使用 char[] 类型的数组
        char[] charArray = {'H', 'e', 'l', 'l', 'o'};
        System.out.println("Length of charArray: " + charArray.length);
        for (char c : charArray) {
            System.out.print(c);
        }
        System.out.println();
    }
}
1.2、String、StringBuffer和StringBuilder
在Java中,String、StringBuffer 和 StringBuilder 都用于处理字符串,但它们之间有一些重要的区别:
String:
- 不可变性:- String类是不可变的,一旦创建了字符串对象,其内容就不能被修改。对- String的任何修改操作都会返回一个新的- String对象。
 
- 线程安全性:- String是线程安全的,可以安全地被多个线程共享。
 
- 性能:- 由于 String是不可变的,对String进行频繁的修改操作会产生大量的临时对象,导致内存开销较大。
 
- 由于 
- 适用场景:- 适用于字符串常量或者少量修改的情况,例如配置、属性文件和少量的字符串操作。
 
StringBuffer:
- 可变性:- StringBuffer是可变的字符串序列,它允许对字符串进行修改操作,而不会创建新的对象。
 
- 线程安全性:- StringBuffer是线程安全的,它的所有公共方法都是同步的,可以安全地被多个线程共享。
 
- 性能:- StringBuffer的性能比- String要好,特别是在需要频繁修改字符串内容的情况下,因为它避免了创建大量的临时对象。
 
- 适用场景:- 适用于多线程环境下的字符串操作,或者需要频繁进行字符串修改操作的情况。
 
StringBuilder:
- 可变性:- StringBuilder也是可变的字符串序列,与- StringBuffer类似,它允许对字符串进行修改操作。
 
- 线程安全性:- StringBuilder是非线程安全的,它的所有方法都不是同步的,不适合在多线程环境中使用。
 
- 性能:- StringBuilder的性能比- StringBuffer更高,因为它省略了同步操作,但是不适合在多线程环境下使用。
 
- 适用场景:- 适用于单线程环境下的字符串操作,或者不需要考虑线程安全性的情况。
 
总结:
- 如果需要频繁进行字符串操作,并且在多线程环境中使用,应该优先选择 StringBuffer。
- 如果在单线程环境下进行字符串操作,并且不需要考虑线程安全性,可以选择 StringBuilder。
- 如果字符串是不可变的,或者只是做少量的字符串操作,应该使用 String。
1.3、StringBuffer和StringBuilder常用方法
StringBuffer 和 StringBuilder 类都提供了一系列用于字符串操作的方法。它们之间的主要区别在于线程安全性,StringBuffer 是线程安全的,而 StringBuilder 则不是。以下是它们常用的方法:
共同方法:
- append(String str):将指定的字符串追加到此字符序列。
- append(int i):将指定的整数追加到此字符序列。
- append(char c):将指定的字符追加到此字符序列。
- insert(int offset, String str):将指定的字符串插入此字符序列中。
- insert(int offset, char c):将指定的字符插入此字符序列中。
- delete(int start, int end):删除此字符序列的子字符串。
- deleteCharAt(int index):删除指定位置的字符。
- reverse():反转此字符序列。
仅 `StringBuffer` 的方法:
- setCharAt(int index, char ch):将指定索引处的字符设置为指定的字符。
- charAt(int index):返回指定索引处的字符。
- setLength(int newLength):设置此字符序列的长度。
- substring(int start, int end):返回一个新的字符串,它包含此字符序列当前所包含的字符子序列。
仅 `StringBuilder` 的方法:
StringBuilder 类不提供额外的方法,除了上面提到的共同方法外,它和 StringBuffer 的用法是一样的。
示例代码:
public class Main {
    public static void main(String[] args) {
        // 使用 StringBuffer
        StringBuffer stringBuffer = new StringBuffer("Hello");
        stringBuffer.append(" World"); // 追加字符串
        stringBuffer.insert(5, " Java"); // 在指定位置插入字符串
        stringBuffer.delete(5, 10); // 删除指定位置的子字符串
        stringBuffer.reverse(); // 反转字符串
        System.out.println("StringBuffer: " + stringBuffer);
        // 使用 StringBuilder
        StringBuilder stringBuilder = new StringBuilder("Hello");
        stringBuilder.append(" World"); // 追加字符串
        stringBuilder.insert(5, " Java"); // 在指定位置插入字符串
        stringBuilder.delete(5, 10); // 删除指定位置的子字符串
        stringBuilder.reverse(); // 反转字符串
        System.out.println("StringBuilder: " + stringBuilder);
    }
}
2、数组 和 ArrayList
在 Java 中,
ArrayList和数组(Array)是两种不同的数据结构,它们有一些区别:
- 大小可变性:
- 数组的长度是固定的,在创建数组时需要指定长度,且长度不能动态改变。
ArrayList的大小是动态可变的,可以根据需要动态增加或减少元素。
- 类型灵活性:
- 数组可以存储基本数据类型(如 int、double、char 等)和对象类型(如自定义的类对象等)。
ArrayList只能存储对象类型,不能存储基本数据类型,但可以通过自动装箱和拆箱来存储基本数据类型的值。
- 功能和方法:
- 数组是一个简单的数据结构,提供了一些基本的方法来操作数组元素,如访问、修改、遍历等。
ArrayList是java.util包中的一个类,提供了丰富的方法和功能,如添加元素、删除元素、获取元素、搜索、排序等,使得操作更加方便和灵活。
- 性能:
- 在访问元素时,数组的性能比
ArrayList更好,因为数组是连续存储的,可以通过索引直接访问元素。- 在增删元素时,
ArrayList的性能比数组更好,因为ArrayList内部使用了动态数组实现,可以根据需要自动扩容和收缩,并且提供了高效的添加和删除操作。 总的来说,如果需要一个固定大小的、性能更好的数据结构,可以使用数组;如果需要一个动态大小的、功能更丰富的数据结构,可以使用ArrayList。
在 Java 中,可以使用一些方法来实现数组和 ArrayList 之间的互相转换:
// 数组转换为 ArrayList:
// 使用 Arrays 类的 asList 方法
String[] array = {"A", "B", "C"};
ArrayList list = new ArrayList<>(Arrays.asList(array));
// ArrayList 转换为数组:
ArrayList<String> list = new ArrayList<>();
String[] array = list.toArray(new String[0]);
2.1、数组
2.1.1、常用语法
// 声明 首选方法
dataType[] arrayRefVar;
// 也可以这样声明,但不建议
dataType arrayRefVar[];  // 效果相同,但不是首选方法
// 创建
arrayRefVar = new dataType[arraySize];
// 也可以这样初始化
dataType[] arrayRefVar = {value0, value1, ..., valuek};
// 赋值
arrayRefVar[9] = 11123;
// 获取长度属性
arrayRefVar.length
// 遍历
for (int i = 0; i < myList.length; i++) {
    System.out.println(myList[i] + " ");
}
for(type element: array) {
    System.out.println(element);
}
// 作为参数传递
public static void printArray(int[] array) {
  for (int i = 0; i < array.length; i++) {
    System.out.print(array[i] + " ");
  }
}
// 作为返回值
public static int[] reverse(int[] list) {
  int[] result = new int[list.length];
  return result;
}
// 多维数组
String[][] str = new String[3][4];
2.1.2、Arrays工具类
| 方法名 | 说明 | 
|---|---|
| public static int binarySearch(Object[] a, Object key) | 用二分查找算法在给定数组中搜索给定值的对象调用前,传入的数组必须是已经排序好的返回索引,若查找不到,返回-1 | 
| public static boolean equals(long[] a, long[] a2) | 通过 equals 方法比较数组中元素值是否相等 | 
| public static void fill(int[] a, int val) | 给数组赋值 | 
| public static void sort(Object[] a) | 对数组排序 | 
2.2、ArrayList
// 定义
List<String> sites = new ArrayList<String>(10);
// 添加元素
sites.add("Google");
sites.set(2, "Wiki"); 
// 获取元素
sites.get(1)
// 删除
sites.remove(3); // 删除第四个元素
// 长度,注意⚠️
sites.size()
// 排序
Collections.sort(sites);
3、LinkedList
LinkedList 是 Java 中的一个类,用于实现双向链表数据结构。在 java.util 包中,它实现了 List 接口,因此可以作为列表使用。下面是一些关键的特点和方法:
特点:
- 双向链表:每个节点都包含了指向前一个节点和后一个节点的引用。
- 动态大小:可以根据需要动态地增加或删除元素,而不需要重新分配内存空间。
- 非同步:LinkedList不是线程安全的,如果多个线程同时访问一个LinkedList实例,并且至少有一个线程修改了列表的结构,则必须在外部进行同步。
主要方法:
- 添加元素:- void addFirst(E e): 在列表的开头添加指定的元素。
- void addLast(E e): 在列表的末尾添加指定的元素。
- void add(int index, E element): 在指定的位置插入指定的元素。
 
- 获取元素:- E getFirst(): 返回列表的第一个元素。
- E getLast(): 返回列表的最后一个元素。
- E get(int index): 返回列表中指定位置的元素。
 
- 移除元素:- E removeFirst(): 移除并返回列表的第一个元素。
- E removeLast(): 移除并返回列表的最后一个元素。
- E remove(int index): 移除并返回列表中指定位置的元素。
 
- 其他方法:- int size(): 返回列表中的元素数。
- boolean isEmpty(): 如果列表不包含任何元素,则返回 true。
 
示例代码:
import java.util.LinkedList;
public class Main {
    public static void main(String[] args) {
        LinkedList<String> linkedList = new LinkedList<>();
        // 添加元素
        linkedList.add("Apple");
        linkedList.add("Banana");
        linkedList.addLast("Orange");
        // 获取元素
        System.out.println("First element: " + linkedList.getFirst());
        System.out.println("Last element: " + linkedList.getLast());
        System.out.println("Element at index 1: " + linkedList.get(1));
        // 移除元素
        linkedList.removeFirst();
        linkedList.removeLast();
        System.out.println("Size after removal: " + linkedList.size());
    }
}
4、HashMap
HashMap 是 Java 中的一个类,用于实现基于哈希表的键值对存储结构。在 java.util 包中,它实现了 Map 接口,因此可以用于存储键值对。下面是一些关键的特点和方法:
特点:
- 键值对存储:HashMap存储的是一组键值对(key-value pairs),每个键对应一个值。
- 哈希表:HashMap内部使用哈希表来存储键值对,这使得对键的查找操作具有很高的效率。
- 非同步:HashMap不是线程安全的,如果多个线程同时访问一个HashMap实例,并且至少有一个线程修改了映射,则必须在外部进行同步。
主要方法:
- 添加键值对:- V put(K key, V value): 将指定的值与指定的键关联,并将其插入到- HashMap中。
 
- 获取值:- V get(Object key): 返回与指定键关联的值,如果该键不存在,则返回- null。
 
- 移除键值对:- V remove(Object key): 移除指定键的映射关系,并返回其关联的值。
 
- 其他方法:- boolean containsKey(Object key): 如果- HashMap包含指定键的映射关系,则返回- true。
- boolean containsValue(Object value): 如果- HashMap中包含一个或多个键映射到指定值,则返回- true。
- int size(): 返回- HashMap中的键值对数量。
- boolean isEmpty(): 如果- HashMap不包含键值对,则返回- true。
- void clear(): 移除- HashMap中的所有键值对。
 
示例代码:
import java.util.HashMap;
import java.util.Map;
public class Main {
    public static void main(String[] args) {
        // 创建一个 HashMap 实例
        HashMap<String, Integer> hashMap = new HashMap<>();
        // 添加键值对
        hashMap.put("apple", 10);
        hashMap.put("banana", 20);
        hashMap.put("orange", 30);
        // 获取值
        int value = hashMap.get("apple");
        System.out.println("Value for key 'apple': " + value);
        // 移除键值对
        hashMap.remove("banana");
        System.out.println("Size after removal: " + hashMap.size());
        // 遍历键值对
        for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
            System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
        }
    }
}
5、HashSet
HashSet 是 Java 中的一个类,用于实现集合数据结构,它基于哈希表实现。在 java.util 包中,它实现了 Set 接口,因此可以用于存储不重复的元素。下面是一些关键的特点和方法:
特点:
- 不重复性:HashSet中不允许存储重复的元素,如果尝试添加重复的元素,那么新的元素不会被添加到集合中。
- 无序性:HashSet中的元素没有固定的顺序,不保证存储顺序与添加顺序一致。
- 基于哈希表:HashSet内部使用哈希表来存储元素,这使得对元素的查找操作具有很高的效率。
主要方法:
- 添加元素:- boolean add(E e): 将指定的元素添加到集合中,如果元素已存在,则不会添加,并返回- false。
 
- 移除元素:- boolean remove(Object o): 从集合中移除指定的元素,如果元素存在且成功被移除,则返回- true。
 
- 检查是否包含元素:- boolean contains(Object o): 如果集合中包含指定的元素,则返回- true。
 
- 其他方法:- int size(): 返回集合中的元素个数。
- boolean isEmpty(): 如果集合不包含任何元素,则返回- true。
- void clear(): 清空集合中的所有元素。
 
示例代码:
import java.util.HashSet;
public class Main {
    public static void main(String[] args) {
        // 创建一个 HashSet 实例
        HashSet<String> hashSet = new HashSet<>();
        // 添加元素
        hashSet.add("apple");
        hashSet.add("banana");
        hashSet.add("orange");
        hashSet.add("apple"); // 重复的元素,不会被添加
        // 检查是否包含元素
        System.out.println("Contains 'apple': " + hashSet.contains("apple"));
        System.out.println("Contains 'grape': " + hashSet.contains("grape"));
        // 移除元素
        hashSet.remove("banana");
        // 打印集合大小
        System.out.println("Size: " + hashSet.size());
        // 遍历集合
        for (String element : hashSet) {
            System.out.println(element);
        }
    }
}
6、Stack
Stack(栈)是一种常见的线性数据结构,它遵循后进先出(LIFO)的原则,即最后入栈的元素将被最先弹出。Java 提供了 Stack 类来表示栈,它位于 java.util 包中,继承自 Vector 类。
Stack 类的主要方法:
- 压栈操作:- void push(E item): 将指定的元素压入栈顶。
 
- 弹栈操作:- E pop(): 移除并返回栈顶的元素。
 
- 查看栈顶元素:- E peek(): 返回栈顶的元素,但不移除。
 
- 判断栈是否为空:- boolean empty(): 判断栈是否为空。
 
- 查找元素在栈中的位置:- int search(Object o): 查找指定元素在栈中的位置,如果存在返回其距离栈顶的位置(栈顶为第一个元素,索引为1),否则返回 -1。
 
示例代码:
import java.util.Stack;
public class Main {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        // 压栈操作
        stack.push(1);
        stack.push(2);
        stack.push(3);
        // 弹栈操作
        int poppedElement = stack.pop();
        System.out.println("Popped element: " + poppedElement);
        // 查看栈顶元素
        int peekedElement = stack.peek();
        System.out.println("Peeked element: " + peekedElement);
        // 判断栈是否为空
        boolean isEmpty = stack.empty();
        System.out.println("Is stack empty? " + isEmpty);
        // 查找元素在栈中的位置
        int position = stack.search(2);
        System.out.println("Position of element 2: " + position);
        // 输出栈中的元素
        System.out.println("Stack: " + stack);
    }
}
7、Queue
在 Java 中,Queue(队列)是一种常见的线性数据结构,它遵循先进先出(FIFO)的原则,即先进入队列的元素将被最先移除。Java 提供了 Queue 接口作为队列的抽象表示,它位于 java.util 包中。
Queue 接口的主要方法:
- 添加元素:- boolean add(E e): 将指定的元素添加到队列尾部,如果队列已满则抛出异常。
- boolean offer(E e): 将指定的元素添加到队列尾部,如果队列已满则返回 false。
 
- 移除元素:- E remove(): 移除并返回队列头部的元素,如果队列为空则抛出异常。
- E poll(): 移除并返回队列头部的元素,如果队列为空则返回 null。
 
- 获取头部元素:- E element(): 返回队列头部的元素,但不移除,如果队列为空则抛出异常。
- E peek(): 返回队列头部的元素,但不移除,如果队列为空则返回 null。
 
Java 中的 Queue 实现类:
Java 提供了几个常用的 Queue 实现类,包括:
- LinkedList:java.util.LinkedList类实现了 Queue 接口,可以作为队列使用。它支持快速的插入和删除操作,但不支持并发访问。
- PriorityQueue:java.util.PriorityQueue类实现了 Queue 接口,是一个基于优先级堆的无界队列。它按照元素的优先级顺序来确定出队顺序。
- ArrayDeque:java.util.ArrayDeque类实现了 Queue 接口,是一个基于数组的双端队列。它可以作为栈、队列或双端队列使用。
示例代码:
import java.util.Queue;
import java.util.LinkedList;
public class Main {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        // 添加元素到队列
        queue.add("A");
        queue.add("B");
        queue.add("C");
        // 获取并移除队列头部的元素
        String first = queue.poll();
        System.out.println("Removed element: " + first);
        // 获取队列头部的元素(不移除)
        String peeked = queue.peek();
        System.out.println("Peeked element: " + peeked);
        // 输出队列中的元素
        System.out.println("Queue: " + queue);
    }
}
在 Java 中,Queue 是一个接口,而接口是不能被直接实例化的。所以不能直接使用 new Queue<>() 来创建一个 Queue 实例。你必须使用一个实现了 Queue 接口的类来创建一个队列实例,比如 LinkedList、ArrayDeque 或者 PriorityQueue。因此,你可以这样做:
Queue<String> queue = new LinkedList<>();
Queue<String> queue = new ArrayDeque<>();
Queue<String> queue = new PriorityQueue<>();
以上三种方式都可以创建一个 Queue<String> 的实例,分别使用了 LinkedList、ArrayDeque 和 PriorityQueue 这三个实现类。
8、PriorityQueue
在 Java 中,优先队列(PriorityQueue)是一种特殊的队列,它按照元素的优先级顺序来确定出队顺序。具体来说,优先队列中的元素必须是可比较的,并且根据它们的自然顺序或者通过提供的 Comparator 进行比较。
创建优先队列:
import java.util.PriorityQueue;
public class Main {
    public static void main(String[] args) {
        // 创建一个空的优先队列
        PriorityQueue<Integer> pq1 = new PriorityQueue<>();
        // 创建一个带有初始容量的优先队列,并使用自然排序
        PriorityQueue<Integer> pq2 = new PriorityQueue<>(10);
        // 创建一个带有初始容量和自定义比较器的优先队列
        PriorityQueue<Integer> pq3 = new PriorityQueue<>(10, (a, b) -> b - a);
        // 添加元素到优先队列中
        pq1.add(5);
        pq1.add(3);
        pq1.add(7);
        // 输出优先队列中的元素(不按顺序)
        System.out.println("PriorityQueue 1: " + pq1);
    }
}
常用操作:
- add(e)或- offer(e): 向队列中添加元素。
- peek(): 获取队列中优先级最高的元素,但不移除。
- poll(): 获取并移除队列中优先级最高的元素。
- remove(Object o): 移除队列中指定的元素。
- isEmpty(): 判断队列是否为空。
- size(): 获取队列中元素的个数。
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(5);
pq.add(3);
pq.add(7);
System.out.println("Peek: " + pq.peek()); // 输出 3,最高优先级元素
System.out.println("Poll: " + pq.poll()); // 输出 3,并移除
System.out.println("Queue size: " + pq.size()); // 输出 2,队列中剩余元素个数
注意事项:
- 优先队列中的元素必须是可比较的,如果元素类型不支持比较,添加到优先队列中时会抛出 ClassCastException异常。
- 当使用自定义对象作为元素时,确保实现了 Comparable接口或者提供了比较器(Comparator)。
- 优先队列不允许添加 null元素。
优先队列常用于实现任务调度、事件排序等场景,它可以确保按照优先级顺序处理任务或事件。



评论区
0/2048