Trang chủHướng dẫnPhỏng vấn Java String: nhà tuyển dụng thường hỏi gì?
Java

Phỏng vấn Java String: nhà tuyển dụng thường hỏi gì?

CyStack blog 12 phút để đọc
CyStack blog05/05/2025
Reading Time: 12 minutes

Bạn đang chuẩn bị cho một buổi phỏng vấn vị trí lập trình viên Java? Nếu vậy, việc nắm rõ những câu hỏi phổ biến mà nhà tuyển dụng thường đặt ra là điều cần thiết. Dù bạn là người mới hay đã có kinh nghiệm, hiểu cách tiếp cận và trả lời chính xác những câu hỏi này sẽ giúp bạn tự tin hơn và tạo ấn tượng tốt với nhà tuyển dụng.

Một trong những chủ đề quan trọng mà hầu hết các nhà tuyển dụng đều quan tâm chính là class String – lớp được sử dụng rộng rãi trong Java. Hầu như lập trình viên Java nào cũng làm việc với nó, nhưng không phải ai cũng thực sự hiểu rõ bản chất cũng như những vấn đề bảo mật liên quan khi sử dụng.

Hãy cùng khám phá 21 câu hỏi dưới đây để kiểm tra kiến thức của bạn về lớp String và học cách áp dụng nó hiệu quả trong công việc. Bạn cũng có thể thử Java String Quiz để đánh giá trình độ của mình!

1. Lớp String là gì trong Java và nó có phải kiểu String không?

Câu hỏi đầu tiên là câu dễ gây nhầm lẫn khi mọi người nhầm tưởng String là 1 kiểu d liệu nguyên thủy int hay long nhưng thực chất, trong java String là một lớp và được định nghĩa trong gói java.lang. Lớp String đại diện cho chuỗi ký tự và được sử dụng rộng rãi trong hầu hết các ứng dụng Java. Trong Java, String là bất biến (immutable) và được khai báo là final đấy cũng là nguyên nhân khiến mọi người hiểu nhầm vì tính bất biến sẽ có trong các kiểu dữ liệu nguyên thủy. JVM sử dụng một String Pool để lưu trữ các đối tượng String, giúp tối ưu hóa bộ nhớ. Bạn có thể khởi tạo một đối tượng String bằng dấu ngoặc kép (""), và có thể sử dụng toán tử + để nối chuỗi nhờ cơ chế nạp chồng toán tử (operator overloading).

2. Có những cách khởi tạo đối tượng String nào trong Java?

Câu hỏi khá đơn giản, bạn có thể tạo một đối tượng String bằng cách sử dụng toán tử new hoặc sử dụng dấu ngoặc kép (""). Ví dụ:

String str = new String("cystack");
String str1 = "cystack";

Lớp String cung cấp nhiều phương thức đặc biệt được sử dụng để khởi tạo đối tượng (constructor) để tạo một chuỗi từ mảng ký tự (char array), mảng byte (byte array), StringBufferStringBuilder.

Khi bạn tạo một chuỗi bằng dấu ngoặc kép (""), JVM sẽ kiểm tra trong String Pool để xem có chuỗi nào có giá trị tương tự đã được lưu trữ hay chưa. Nếu chuỗi đó đã tồn tại trong pool, JVM sẽ trả về tham chiếu đến đối tượng chuỗi đó. Nếu chưa có, JVM sẽ tạo một đối tượng String mới với giá trị được cung cấp và lưu trữ nó vào String Pool.

Ngược lại, khi bạn sử dụng toán tử new, JVM sẽ tạo một đối tượng String mới trong bộ nhớ heap nhưng không lưu nó vào String Pool. Nếu muốn đưa đối tượng String này vào String Pool hoặc lấy tham chiếu đến một chuỗi có giá trị tương đương trong pool, bạn có thể sử dụng phương thức intern().

Ví dụ về việc đưa đối tượng String vào String pool

String s1 = new String("cystack");
s1 = s1.intern(); // Đưa vào String Pool hoặc lấy tham chiếu đến chuỗi trong Pool
String s2 = "cystack"; // Lấy chuỗi từ Pool

System.out.println(s1 == s2); // true (cả hai cùng trỏ đến String Pool)

3. Viết một phương thức Java để kiểm tra xem một chuỗi đầu vào có phải là palindrome hay không?

Một chuỗi được gọi là palindrome nếu giá trị của nó vẫn giữ nguyên khi đảo ngược. Ví dụ, "aba" là một chuỗi palindrome.

Lớp String không cung cấp phương thức nào để đảo ngược chuỗi, nhưng các lớp StringBufferStringBuilder có phương thức reverse() mà bạn có thể sử dụng để kiểm tra xem một chuỗi có phải là palindrome hay không. Ví dụ:

private static boolean isPalindrome(String str) {
 if (str == null)
 return false;
 StringBuilder strBuilder = new StringBuilder(str);
 strBuilder.reverse();
 return strBuilder.toString().equals(str);
}

Đôi khi, nhà tuyển dụng có thể yêu cầu bạn không sử dụng bất kỳ lớp hỗ trợ nào để kiểm tra một chuỗi có phải là palindrome hay không. Trong trường hợp đó, bạn có thể so sánh các ký tự trong chuỗi từ hai đầu để xác định xem chuỗi có đối xứng hay không. Ví dụ:

private static boolean isPalindromeString(String str) {
 if (str == null)
 return false;
 int length = str.length();
 System.out.println(length / 2);
 for (int i = 0; i < length / 2; i++) {
 if (str.charAt(i) != str.charAt(length - i - 1))
 return false;
 }
 return true;
}

4. Viết một phương thức Java để loại bỏ một ký tự nhất định khỏi một đối tượng chuỗi?

Chúng ta có thể sử dụng phương thức replaceAll() để thay thế tất cả các lần xuất hiện của một chuỗi bằng một chuỗi khác. Một điểm quan trọng cần lưu ý là replaceAll() chấp nhận một đối số kiểu String, vì vậy bạn có thể sử dụng lớp Character để tạo một chuỗi chứa ký tự cần xóa, sau đó thay thế tất cả các ký tự đó bằng một chuỗi rỗng ("").

private static String removeChar(String str, char c) {
 if (str == null)
 return null;
 return str.replaceAll(Character.toString(c), "");
}

5. Làm thế nào để chuyển một chuỗi thành chữ hoa hoặc chữ thường trong Java?

Bạn có thể sử dụng các phương thức toUpperCase()toLowerCase() của lớp String để chuyển đổi toàn bộ chuỗi thành chữ hoa hoặc chữ thường. Các phương thức này cũng có một biến thể cho phép truyền vào một đối số Locale, giúp áp dụng các quy tắc ngôn ngữ cụ thể khi chuyển đổi chuỗi sang chữ hoa hoặc chữ thường.

Ví dụ.

 System.out.println(str.toLowerCase(Locale.FRANCE));

6. Phương thức subSequence() trong String là gì?

Java 1.4 đã giới thiệu giao diện (interface) chung cho chuỗi ký tự CharSequence, các lớp triển khai interface này gồm có String, StringBuilder, StringBuffer, CharBuffer, v.v. , interface cung cấp nhiều phương thức như length(), charAt(), subSequence(), toString()… Vậy nên các đối tượng String có thể gọi phương thức subSequence() để sử dụng. Có thể bạn không biết nhưng phương thức subSequence() thực chất gọi phương thức substring() của lớp String.

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
 ...
 public CharSequence subSequence(int beginIndex, int endIndex) {
 return this.substring(beginIndex, endIndex);
 }
}

Điểm khác biệt là substring() trả về một chuỗi con, nhưng kiểu trả về của subSequence()CharSequence thay vì String. Dùng subSequence() khi bạn làm việc với API yêu cầu CharSequence, vì nó giúp bạn không cần ép kiểu thủ công.

7. Làm thế nào để so sánh hai chuỗi trong một chương trình Java?

Lớp String trong Java triển khai giao diện (interface) Comparable, trong đó có hai biến thể của phương thức compareTo().

  • 1 là compareTo(String anotherString): So sánh hai chuỗi theo thứ tự từ điển (lexicographically).
    • Nếu chuỗi gọi phương thức ít ký tự hơn chuỗi được truyền vào, phương thức trả về một số nguyên âm.
    • Nếu chuỗi gọi phương thức nhiều ký tự hơn chuỗi được truyền vào, phương thức trả về một số nguyên dương.
    • Nếu cả hai chuỗi bằng nhau, phương thức trả về 0. Trong trường hợp này, phương thức equals(String str) cũng sẽ trả về true.
  • 2 là compareToIgnoreCase(String str): Tương tự như compareTo(), nhưng bỏ qua sự phân biệt chữ hoa – chữ thường.
    • Phương thức này sử dụng Comparator với CASE_INSENSITIVE_ORDER để thực hiện so sánh không phân biệt chữ hoa/chữ thường.
    • Nếu giá trị trả về là 0, thì phương thức equalsIgnoreCase(String str) cũng sẽ trả về true.

8. Làm thế nào để chuyển một chuỗi (String) thành mảng ký tự (char[]) trong Java?

Một đối tượng String là một chuỗi các ký tự, vì vậy bạn không thể chuyển đổi nó thành một ký tự đơn lẻ.

  • Nếu bạn muốn lấy một ký tự tại một vị trí cụ thể trong chuỗi, bạn có thể sử dụng phương thức charAt(int index).
  • Nếu bạn muốn chuyển đổi toàn bộ chuỗi thành một mảng ký tự, bạn có thể sử dụng phương thức toCharArray(), phương thức này sẽ trả về một mảng char[] chứa tất cả các ký tự của chuỗi.

9. Làm thế nào để chuyển một chuỗi (String) thành mảng byte (byte[]) trong Java?

Bạn có thể sử dụng phương thức getBytes() để chuyển đổi một đối tượng String thành mảng byte (byte[]). Ngược lại, để chuyển đổi một mảng byte thành đối tượng String, bạn có thể sử dụng constructor new String(byte[] arr).

10. Trong Java, có thể sử dụng kiểu dữ liệu String trong câu lệnh switch-case không?

Java 7 đã mở rộng khả năng của switch-case để hỗ trợ chuỗi (String). Các phiên bản Java trước đó không hỗ trợ tính năng này. Nếu bạn đang triển khai luồng điều kiện cho chuỗi trong các phiên bản Java cũ hơn, bạn cần sử dụng câu lệnh if-else. Tuy nhiên, nếu bạn đang sử dụng Java 7 hoặc phiên bản mới hơn, bạn có thể sử dụng switch-case với String. https://www.digitalocean.com/community/tutorials/java-switch-case-string

11. Viết chương trình Java để in ra tất cả các hoán vị của một chuỗi

Bạn cần sử dụng đệ quy (recursion) để tìm tất cả các hoán vị của một chuỗi. Ví dụ, các hoán vị của chuỗi "AAB" là:AAB, ABA, BAA

Ngoài ra, bạn cũng cần sử dụng Set để đảm bảo không có giá trị trùng lặp trong kết quả. https://www.digitalocean.com/community/tutorials/permutation-of-string-in-java

import java.util.HashSet;
import java.util.Set;

public class StringPermutations {
 public static void main(String[] args) {
 String str = "AAB";
 System.out.println("Các hoán vị của chuỗi \\"" + str + "\\":");
 Set<String> result = new HashSet<>();
 findPermutations(str, "", result);

 // In kết quả
 for (String perm : result) {
 System.out.println(perm);
 }
 }

 public static void findPermutations(String str, String prefix, Set<String> result) {
 if (str.length() == 0) {
 result.add(prefix); // Thêm hoán vị vào Set để tránh trùng lặp
 return;
 }
 for (int i = 0; i < str.length(); i++) {
 char currentChar = str.charAt(i);
 String remaining = str.substring(0, i) + str.substring(i + 1);
 findPermutations(remaining, prefix + currentChar, result);
 }
 }
}

12. Viết một hàm Java để tìm palindrome dài nhất trong một chuỗi cho trước

Một chuỗi có thể chứa nhiều chuỗi con (substring) palindrome bên trong nó. Bạn cần tìm chuỗi con dài nhất có tính chất palindrome trong chuỗi đầu vào. 

13. Sự khác biệt giữa String, StringBufferStringBuilder trong Java

  • String:
    • bất biến (immutable) và được khai báo là final, nghĩa là mỗi khi bạn thay đổi giá trị của một đối tượng String, Java sẽ tạo một đối tượng String mới thay vì sửa đổi đối tượng cũ.
    • Việc thao tác với String tốn nhiều tài nguyên vì cần tạo nhiều đối tượng mới trong bộ nhớ.
  • StringBuffer:
    • có thể thay đổi (mutable), nghĩa là bạn có thể sửa đổi nội dung của đối tượng StringBuffer mà không cần tạo đối tượng mới.
    • Thread-safe: Các thao tác trên StringBuffer được đồng bộ (synchronized), vì vậy nó an toàn khi sử dụng trong môi trường đa luồng.
    • Nhược điểm: Do có cơ chế đồng bộ, hiệu suất của StringBuffer thấp hơn so với StringBuilder.
  • StringBuilder:
    • Giống StringBuffer, nhưng không đồng bộ (non-synchronized).
    • Không an toàn trong môi trường đa luồng, nhưng có hiệu suất cao hơn StringBuffer vì không có chi phí đồng bộ hóa (synchronization overhead).
    • Nên sử dụng StringBuilder trong môi trường đơn luồng (single-threaded) để có hiệu suất tốt nhất.

Nếu bạn cần xử lý chuỗi trong môi trường đa luồng, hãy sử dụng StringBuffer. Nếu không, hãy dùng StringBuilder để có hiệu suất cao hơn.

14. Tại sao String là bất biến (immutable) trong Java?

String trong Java là bất biến vì điều này mang lại nhiều lợi ích quan trọng:

  1. Nhờ tính bất biến, Java có thể sử dụng String Pool để tái sử dụng các đối tượng String, giúp tiết kiệm bộ nhớ.
  2. Tăng cường bảo mật:
    • Do String không thể thay đổi sau khi khởi tạo, hacker không thể chỉnh sửa giá trị của nó.
    • Điều này giúp tăng bảo mật trong một số trường hợp vì tránh được việc bị thay đổi dữ liệu không mong muốn
  3. An toàn trong đa luồng (multi-threading):
    • String là bất biến, nên nó có thể được chia sẻ giữa nhiều luồng mà không cần cơ chế đồng bộ (synchronization).
  4. Đảm bảo tính toàn vẹn của ClassLoader:
    • String được sử dụng trong Java ClassLoader để xác định và tải các lớp (class).
    • Tính bất biến đảm bảo rằng ClassLoader tải đúng lớp mà không bị thay đổi ngoài ý muốn.

15. Làm thế nào để chia một chuỗi trong Java?

Bạn có thể sử dụng split(String regex) để chia chuỗi thành một mảng chuỗi dựa trên biểu thức chính quy được cung cấp.

16. Tại sao mảng ký tự (char[]) được ưu tiên hơn String để lưu trữ mật khẩu trong Java?

Trong Java, Stringbất biến (immutable) và được lưu trong String Pool và Heap Memory. Khi một đối tượng String được tạo, nó sẽ tồn tại trong vùng nhớ cho đến khi bộ thu gom rác hoàn thành (Garbage Collector)String không thể thay đổi, mật khẩu sẽ tồn tại trong bộ nhớ dưới dạng văn bản rõ ràng (plain text) trong một khoảng thời gian dài. Nếu ai đó có quyền truy cập vào bộ nhớ dump, họ có thể tìm thấy mật khẩu một cách dễ dàng. Khi sử dụng mảng ký tự (char[]), bạn có thể xóa giá trị bằng cách gán các phần tử về rỗng ('\\0') ngay khi không cần dùng nữa. Điều này giúp bạn kiểm soát thời gian tồn tại của dữ liệu nhạy cảm trong bộ nhớ, giảm thiểu rủi ro bảo mật.

17. Làm thế nào để kiểm tra hai chuỗi (String) có bằng nhau trong Java?

Có hai cách để kiểm tra xem hai String có bằng nhau không. Bạn có thể sử dụng toán tử == hoặc phương thức equals(). Khi bạn sử dụng toán tử ==, nó sẽ kiểm tra giá trị của String cũng như tham chiếu đối tượng. Trong lập trình Java, bạn thường chỉ muốn kiểm tra xem giá trị String có bằng nhau không. Trong trường hợp này, bạn nên sử dụng phương thức equals() để kiểm tra xem hai String có bằng nhau không. Có một hàm khác gọi là equalsIgnoreCase mà bạn có thể sử dụng để bỏ qua chữ hoa chữ thường.

String s1 = "cystack";
String s2 = "cystack";
String s3 = new String("cystack");

System.out.println("s1 == s2? " + (s1 == s2)); //true
System.out.println("s1 == s3? " + (s1 == s3)); //false
System.out.println("s1 equals s3? " + (s1.equals(s3))); //true

18. String pool trong Java là gì?

String Pool là một vùng nhớ đặc biệt trong heap memory của Java, nơi lưu trữ các đối tượng String để tối ưu hóa bộ nhớ. String là một lớp đặc biệt trong Java và bạn có thể tạo một đối tượng String bằng toán tử new cũng như bằng cách cung cấp giá trị trong dấu ngoặc kép.

19. Phương thức intern() trong Java hoạt động như thế nào?

Phương thức intern() được sử dụng để lưu trữ chuỗi vào String Pool hoặc lấy về một chuỗi đã có trong pool.

  • Khi gọi intern(), nếu String Pool đã chứa một chuỗi có cùng giá trị (so sánh bằng equals()), thì phương thức sẽ trả về tham chiếu đến chuỗi đó trong pool.
  • Nếu chuỗi chưa tồn tại trong pool, nó sẽ được thêm vào pool, và phương thức trả về tham chiếu đến đối tượng chuỗi đó.
  • Bảo đảm rằng chuỗi trả về luôn là một chuỗi duy nhất trong pool.

20. String có an toàn trong luồng (thread-safe) trong Java không?

Stringbất biến (immutable), tức là giá trị của nó không thể thay đổi sau khi được tạo. Điều này có nghĩa là nhiều luồng có thể sử dụng cùng một đối tượng String mà không gây ra vấn đề đồng bộ hóa (synchronization).

21. Tại sao String là khóa (key) phổ biến trong HashMap của Java?

String là lựa chọn phổ biến làm khóa trong HashMap vì nó là bất biến (immutable). Khi một đối tượng String được tạo, hashcode của nó được tính toán và lưu trữ vĩnh viễn. Điều này giúp tăng hiệu suất khi sử dụng String làm khóa trong HashMap, vì không cần phải tính toán lại hashcode nhiều lần như các đối tượng có thể thay đổi (mutable).

Thực hành trả lời câu hỏi

Sau khi đọc xong 21 câu hỏi trên, các bạn hãy thử đưa ra nhận định đầu ra của các đoạn code sau:

Câu hỏi 1:

public class StringTest {
 
 	public static void main(String[] args) {
 		String s1 = new String("cystack");
 		String s2 = new String("CYSTACK");
 		System.out.println(s1 = s2);
 	}
 
}

Câu trả lời

CYSTACK
Đầu ra là CYSTACK do mã gán giá trị của String s2 cho String s1. = là toán tử gán giá trị của y theo x định dạng (x = y). ==là toán tử so sánh sẽ kiểm tra xem đối tượng tham chiếu có giống nhau đối với hai chuỗi hay không.

Câu hỏi 2:

public class Test {
 
 	 public void foo(String s) {
 	 System.out.println("String");
 	 }
 
 	 public void foo(StringBuffer sb) {
 	 System.out.println("StringBuffer");
 	 }
 
 	 public static void main(String[] args) {
 		new Test().foo(null);
 	}
 
}

Câu trả lời

Test.java:12: error: reference to foo is ambiguous
 		new Test().foo(null);
 		 ^
 both method foo(String) in Test and method foo(StringBuffer) in Test match
 
 Mã này dẫn đến lỗi thời gian biên dịch vì cả hai foo phương thức đều có cùng tên và lệnh gọi phương thức trong main đang truyền null. Trình biên dịch không biết nên gọi phương thức nào.
 

Câu hỏi 3:

String s1 = new String("cystack");
String s2 = new String("cystack");
System.out.println(s1 == s2);

Câu trả lời

false
Đầu ra là false do mã sử dụng new toán tử để tạo đối tượng String, do đó nó được tạo trong bộ nhớ heap và s1 và s2 sẽ có tham chiếu khác. Nếu bạn tạo chuỗi chỉ bằng dấu ngoặc kép, thì chúng sẽ nằm trong nhóm chuỗi và sẽ in ra true.

Câu hỏi 4:

String s1 = "cystack";
StringBuffer s2 = new StringBuffer(s1);
System.out.println(s1.equals(s2));

Câu trả lời

false
Đầu ra là false vì s2 không phải là kiểu String. equals() triển khai phương thức trong lớp String có một toán tử instanceof để kiểm tra xem kiểu của đối tượng được truyền có phải là kiểu String và trả về false nếu đối tượng không phải là kiểu String.

Câu hỏi 5:

String s1 = "cystack";
String s2 = new String("cystack");
s2.intern();
System.out.println(s1 == s2);

Câu trả lời

false.
Phương thức intern() trả về tham chiếu đến đối tượng String trong String Pool, nhưng giá trị này không được gán lại cho s2. Do đó, s2 vẫn giữ nguyên tham chiếu ban đầu, không thay đổi, và s1 và s2 vẫn là hai đối tượng khác nhau trong bộ nhớ.

Câu hỏi 6: Có bao nhiêu đối tượng String được tạo ra bởi đoạn mã sau?

String s1 = new String("cystack"); 
String s2 = new String("cystack");

Câu trả lời:

3 đối tượng String được tạo. Dòng 1: Tạo một đối tượng String với giá trị “Hello” trong String Pool (đối tượng thứ nhất). Sau đó, tạo một đối tượng String mới với giá trị “Hello” trong Heap Memory (đối tượng thứ hai). Dòng 2: Tạo thêm một đối tượng String mới với giá trị “Hello” trong Heap Memory (đối tượng thứ ba). Nhưng nó tái sử dụng chuỗi “Hello” từ String Pool thay vì tạo mới trong pool.

Kết luận

Nắm vững những câu hỏi phỏng vấn về class String trong Java không chỉ giúp bạn tự tin hơn mà còn thể hiện được khả năng tư duy và hiểu biết sâu về ngôn ngữ lập trình này. Việc chuẩn bị kỹ càng sẽ giúp bạn tối ưu hóa câu trả lời, tránh những lỗi sai không đáng có và tạo ấn tượng tốt với nhà tuyển dụng. Hy vọng rằng bài viết này sẽ giúp bạn củng cố kiến thức và sẵn sàng cho buổi phỏng vấn sắp tới. Chúc bạn đạt được kết quả tốt trong cuộc vấn của mình!

0 Bình luận

Đăng nhập để thảo luận

CyStack blog

Mẹo, tin tức, hướng dẫn và các best practice độc quyền của CyStack

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.