Khác Biệt Giữa List và Set Trong Java (Câu Hỏi Phỏng Vấn)

Phân Tích List và Set Trong Java

Khi được hỏi về sự khác biệt giữa hai thành phần nào đó trong công nghệ, cách tiếp cận chuyên nghiệp là trước hết chỉ ra những điểm tương đồng giữa chúng, thể hiện sự hiểu biết sâu sắc về kỹ thuật.

Điểm Tương Đồng:

Cả ListSet đều là các interface con của Collection. Do đó, chúng kế thừa tất cả các phương thức được định nghĩa trong interface Collection, chẳng hạn như các phương thức thêm và loại bỏ phần tử.

Điểm Khác Biệt:

List là một cấu trúc tuần tự, thể hiện ở chỗ các phần tử được lưu trữ trong bộ nhớ theo một thứ tự nhất định. Ngoài ra, List cho phép trùng lặp các phần tử, nghĩa là bạn có thể thêm nhiều lần cùng một giá trị vào cùng một danh sách.

Trong khi đó, Set là một cấu trúc không trật tự (hash-based), thể hiện ở chỗ vị trí của các phần tử trong bộ nhớ được phân tán. Tùy vào lớp triển khai cụ thể, kết quả hiển thị các phần tử trong Set có thể không có thứ tự (HashSet), hoặc được sắp xếp (TreeSet), hoặc được hiển thị theo thứ tự thêm vào (LinkedHashSet). Lưu ý rằng không nên khẳng định Set luôn không có thứ tự.

Ngoài ra, Set không cho phép trùng lặp các phần tử. Việc xác định hai phần tử có giống nhau hay không phụ thuộc vào kết quả so sánh của phương thức equals() và giá trị của . Nếu hai đối tượng có kết quả equals() trả về true giá trị hashCode() của chúng bằng nhau, chúng được coi là giống nhau.

Quy trình so sánh là: trước tiên so sánh hashCode(), chỉ so sánh equals() nếu hashCode() giống nhau.

Lưu Ý Quan Trọng:

Đừng dùng các thuật ngữ "có thứ tự" và "không có thứ tự" để mô tả List và Set một cách tuyệt đối.

Đối với Set, thứ tự hiển thị phụ thuộc vào lớp triển khai cụ thể:

  1. Sử dụng HashSet: kết quả không có thứ tự
  2. Sử dụng TreeSet: kết quả được sắp xếp theo quy tắc
  3. Sử dụng LinkedHashSet: kết quả theo thứ tự thêm vào

Vì vậy, việc khẳng định "Set luôn không có thứ tự" là không chính xác.

Ví Dụ Minh Họa:

1. Sử dụng HashSet (kết quả không có thứ tự)


package demo.java.collection;

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

public class SetDemo {
    public static void main(String[] args) {
        Set<String> chuoi = new HashSet<>();
        chuoi.add("item-1");
        chuoi.add("item-5");
        chuoi.add("item-3");
        chuoi.add("item-2");
        chuoi.add("item-4");
        System.out.println(chuoi);
        // Kết quả: [item-4, item-5, item-2, item-3, item-1]
    }
}

2. Sử dụng TreeSet (kết quả được sắp xếp)


package demo.java.collection;

import java.util.Set;
import java.util.TreeSet;

public class SetDemo {
    public static void main(String[] args) {
        Set<String> chuoi = new TreeSet<>();
        chuoi.add("item-1");
        chuoi.add("item-5");
        chuoi.add("item-3");
        chuoi.add("item-2");
        chuoi.add("item-4");
        System.out.println(chuoi);
        // Kết quả: [item-1, item-2, item-3, item-4, item-5]
    }
}

3. Sử dụng LinkedHashSet (kết quả theo thứ tự thêm vào)


package demo.java.collection;

import java.util.LinkedHashSet;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        Set<String> chuoi = new LinkedHashSet<>();
        chuoi.add("item-1");
        chuoi.add("item-5");
        chuoi.add("item-3");
        chuoi.add("item-2");
        chuoi.add("item-4");
        System.out.println(chuoi);
        // Kết quả: [item-1, item-5, item-3, item-2, item-4]
    }
}

Đặc Điểm Không Trùng Lặp trong Set:


package demo.java.collection;

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

public class SetDemo {
    public static void main(String[] args) {
        Set<String> chuoi = new LinkedHashSet<>();
        chuoi.add("item-1");
        chuoi.add("item-5");
        chuoi.add("item-3");
        chuoi.add("item-2");
        chuoi.add("item-2");
        chuoi.add("item-2");
        chuoi.add("item-4");
        System.out.println(chuoi);
        
        // Tập hợp sinh viên
        Set<SinhVien> sinhVien = new HashSet<>();
        sinhVien.add(new SinhVien("Mike", 18));
        sinhVien.add(new SinhVien("Frank", 20));
        sinhVien.add(new SinhVien("Frank", 20));
        // Dòng sao chép trên
        
        sinhVien.add(new SinhVien("Frank", 25));
        sinhVien.add(new SinhVien("Joe", 25));
        
        // In ra danh sách sinh viên
        for (SinhVien sv : sinhVien) {
            System.out.println(sv);
        }
    }
}

class SinhVien {
    public String ten;
    public int tuoi;
    
    public SinhVien(String ten, int tuoi) {
        this.ten = ten;
        this.tuoi = tuoi;
    }
    
    @Override
    public int hashCode() {
        final int soNguyenTo = 31;
        int ketQua = 1;
        ketQua = soNguyenTo * ketQua + tuoi;
        ketQua = soNguyenTo * ketQua + ((ten == null) ? 0 : ten.hashCode());
        return ketQua;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SinhVien other = (SinhVien) obj;
        if (tuoi != other.tuoi)
            return false;
        if (ten == null) {
            if (other.ten != null)
                return false;
        } else if (!ten.equals(other.ten))
            return false;
        return true;
    }
    
    @Override
    public String toString() {
        return "SinhVien [ten=" + ten + ", tuoi=" + tuoi + "]";
    }
}

Truy Xuất Phần Tử Đơn Giọng Trong Set:

Thông thường, chúng ta duyệt và xuất tất cả các phần tử trong Set. Chỉ có một trường hợp đặc biệt là khi Set được triển khai bằng LinkedHashSet, vì cấu trúc lưu trữ dạng chuỗi của nó cho phép truy cập theo chỉ mục. Do đó, chỉ trong loại Set này chúng ta mới có thể lấy phần tử thứ 3 hoặc thứ 5. Với HashSet hoặc TreeSet thông thường, không nên cân nhắc việc lấy một phần tử riêng lẻ.

Thẻ: Java list set Collection HashSet

Đăng vào ngày 16 tháng 6 lúc 00:15