JavaRush /Blog Java /Random-VI /Câu chuyện một cuộc phỏng vấn: những câu hỏi thú vị
GuitarFactor
Mức độ
Санкт-Петербург

Câu chuyện một cuộc phỏng vấn: những câu hỏi thú vị

Xuất bản trong nhóm
Gần đây tôi có cơ hội tham dự buổi phỏng vấn cho vị trí thực tập sinh tại một trong những công ty CNTT lớn. Câu chuyện một cuộc phỏng vấn: những câu hỏi thú vị - 1Đây là cuộc phỏng vấn CNTT đầu tiên của tôi và theo tôi, nó rất thú vị. Tổng cộng, tôi đã bị “thẩm vấn” hơn 3 giờ (trước đó là bài tập về nhà và bài kiểm tra trên máy tính tại văn phòng). Tôi muốn tri ân người phỏng vấn, người đã không bỏ cuộc khi tôi trả lời sai câu hỏi mà với sự trợ giúp của những câu hỏi dẫn dắt của anh ấy đã buộc tôi phải suy nghĩ và đi đến câu trả lời đúng. Dưới đây tôi sẽ trình bày một số “bản phác thảo” - theo ý kiến ​​​​của tôi, những câu hỏi khá thú vị, một số câu hỏi trong số đó đã giúp tôi hiểu sâu hơn về các khía cạnh nhất định trong Java. Có lẽ những điều này có vẻ hiển nhiên đối với một số người, nhưng tôi nghĩ sẽ có những người mà điều này sẽ hữu ích. Bên dưới các cụm từ được đánh dấu bằng các phông chữ sau: Người phỏng vấn - in đậm Giải thích bằng giọng nói và suy nghĩ của tôi - in nghiêng Câu trả lời của tôi - ở phông chữ thông thường Chúng ta đã hoàn thành phần nền, hãy bắt tay vào công việc)

Phác thảo 1. “Một phương pháp tưởng chừng đơn giản”

Viết cách bạn thực hiện phương pháp trả về kết quả của phép chia số a cho số b. Người phỏng vấn viết ra một tờ giấy
int divide(int a, int b) {
}
*Tôi hoài nghi liếc nhìn mảnh giấy có chữ ký phương thức. Bí quyết là gì?* Tôi viết:
int divide(int a, int b) {
    return a/b;
}
Có bất kỳ vấn đề với phương pháp này? *Tôi đang bắt được một tên ngu ngốc* Rõ ràng là không.. Tiếp theo là một câu hỏi chính đáng: Nếu b=0 thì sao? *Ồ, tôi sắp bị đuổi khỏi văn phòng này nếu cứ tiếp tục thế này!* Ồ vâng, tất nhiên rồi. Ở đây chúng ta có các đối số kiểu int, do đó, Ngoại lệ số học sẽ được đưa ra. Nếu các đối số thuộc loại float hoặc double thì kết quả sẽ là Vô cực. Chúng ta sẽ làm gì về điều này? Tôi đang bắt đầu viết thử/bắt
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*Tôi có thể quay lại và đóng băng: cần phải trả lại thứ gì đó trong trường hợp có lỗi. Nhưng làm sao có thể phân biệt được “thứ gì đó” này với kết quả phép tính?* Chúng ta sẽ trả về cái gì? Hừm... Tôi sẽ thay đổi kiểu của biến trả về thành Số nguyên và trong trường hợp có ngoại lệ, tôi sẽ trả về null. Hãy tưởng tượng rằng chúng ta không thể thay đổi loại. Bằng cách nào đó chúng ta có thể thoát ra được không? Có lẽ chúng ta có thể làm điều gì khác với ngoại lệ? *Đến rồi* Chúng ta cũng có thể chuyển tiếp nó đến phương thức gọi điện! Phải. Nó sẽ trông giống thứ gì?
int divide(int a, int b) throws ArithmeticException{
    return a/b;
}

void callDivide(int a, int b) {
    try {
        divide(a, b);
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }
}
Có cần thiết phải xử lý ngoại lệ không? Có, bởi vì chúng tôi chuyển tiếp nó một cách rõ ràng từ phương thức chia. (*Tôi đã sai ở đây! Sau đây là những câu hỏi dẫn dắt người phỏng vấn đi đến câu trả lời đúng*) Và Ngoại lệ số học - đó là loại ngoại lệ nào - được chọn hay không được chọn? Đây là một ngoại lệ trong Runtime, có nghĩa là không được chọn. *Đây là câu hỏi quan trọng* Vậy hóa ra, theo cách nói của bạn, nếu chúng tôi chỉ định ném Ngoại lệ số học trong chữ ký phương thức, thì nó trở thành một ngoại lệ được kiểm tra? *Ugh!* Có lẽ... không. Vâng, nó đã biến mất. Nếu chúng tôi chỉ ra các lần ném /ngoại lệ không được kiểm tra/ trong chữ ký, chúng tôi chỉ cảnh báo rằng phương thức này có thể đưa ra một ngoại lệ, nhưng không cần thiết phải xử lý nó trong phương thức gọi. Thế là xong. Chúng ta có thể làm gì khác để tránh sai lầm? *Sau khi suy nghĩ* Có, chúng ta cũng có thể kiểm tra xem (b==0). Và thực hiện một số logic. Phải. Vì vậy chúng ta có thể đi theo 3 cách:
  • cố gắng bắt
  • ném - chuyển tiếp đến phương thức gọi
  • kiểm tra đối số
Trong trường hợp này, dividebạn nghĩ phương pháp nào thích hợp hơn?
Tôi sẽ chọn chuyển tiếp ngoại lệ sang phương thức gọi điện, bởi vì... trong phương thức chia không rõ cách xử lý ngoại lệ này và loại kết quả nào intsẽ trả về trong trường hợp có lỗi. Và trong phương thức gọi, tôi sẽ sử dụng đối số b để kiểm tra xem nó có bằng 0 hay không. Có vẻ như câu trả lời này đã làm hài lòng người được phỏng vấn, nhưng thành thật mà nói, tôi không chắc rằng câu trả lời này rõ ràng))

Phác thảo 2. “Ai nhanh hơn?”

Sau câu hỏi tiêu chuẩn, ArrayList khác với LinkedList như thế nào, đến câu hỏi sau: Điều gì sẽ xảy ra nhanh hơn - chèn một phần tử vào giữa ArrayListhoặc vào giữa LinkedList? *Đến đây tôi chợt nhớ ra rằng ở đâu tôi cũng đọc được những câu như “dùng LinkedListđể chèn hoặc xóa các phần tử ở giữa danh sách”. Ở nhà, tôi thậm chí còn kiểm tra kỹ các bài giảng JavaRush, có một cụm từ: “nếu bạn định chèn (hoặc xóa) nhiều phần tử vào giữa một bộ sưu tập thì tốt hơn bạn nên sử dụng LinkedList. Trong tất cả các trường hợp khác - ArrayList.” Trả lời tự động* Sẽ nhanh hơn với LinkedList. Làm rõ xin vui lòng
  1. Để chèn một phần tử vào giữa ArrayList, chúng ta tìm phần tử trong danh sách theo thời gian không đổi, sau đó tính toán lại chỉ số của các phần tử ở bên phải phần tử được chèn, theo thời gian tuyến tính.
  2. Đối với LinkedList.. Trước tiên, chúng tôi đến giữa theo thời gian tuyến tính và sau đó chèn một phần tử theo thời gian không đổi, thay đổi liên kết cho các phần tử lân cận.
Vậy hóa ra cái nào nhanh hơn? Ừm... Hoá ra cũng vậy. Nhưng khi nào nó LinkedListnhanh hơn? Hóa ra là khi chúng ta chèn nó vào nửa đầu danh sách. Ví dụ: nếu bạn chèn nó ngay từ đầu, bạn ArrayListsẽ phải tính toán lại tất cả các chỉ số cho đến tận đuôi, nhưng bạn LinkedListsẽ chỉ phải thay đổi tham chiếu của phần tử đầu tiên. Đạo đức: đừng tin theo nghĩa đen mọi thứ được viết ra, ngay cả trong JavaRush!)

Phác thảo 3. “Chúng ta sẽ ở đâu nếu không có giá trị bằng và mã băm!”

Cuộc trò chuyện về bằng và mã băm đã rất dài - cách ghi đè nó, cách triển khai trong Object, điều gì xảy ra bên trong, khi một phần tử được chèn vào HashMap, v.v. Theo quan điểm của tôi, tôi sẽ chỉ đưa ra một số điểm thú vị* Hãy tưởng tượng rằng chúng ta đã tạo một lớp
public class A {
    int id;

    public A(int id) {
        this.id = id;
    }
}
Và họ đã không ghi đè equalshashcode. Mô tả điều gì sẽ xảy ra khi mã được thực thi
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*Thật tốt là trước cuộc phỏng vấn, tôi đã đặc biệt dành vài ngày để tìm hiểu các thuật toán cơ bản, độ phức tạp và cấu trúc dữ liệu của chúng - điều đó đã giúp ích rất nhiều, cảm ơn CS50!*
  1. Tạo hai thể hiện của lớp A

  2. Chúng tôi tạo một bản đồ trống, theo mặc định có 16 giỏ. Khóa là một đối tượng của lớp A, trong đó các phương thức equalsvà không bị ghi đè hashcode.

  3. Đặt nó a1trong bản đồ. Để làm điều này, trước tiên chúng tôi tính toán hàm băm a1.

    Hàm băm sẽ bằng bao nhiêu?

    Địa chỉ của một ô trong bộ nhớ là sự triển khai của một phương thức từ một lớpObject

  4. Dựa trên hàm băm, chúng tôi tính toán chỉ số giỏ.

    Làm thế nào chúng ta có thể tính toán nó?

    *Thật không may, tôi đã không đưa ra câu trả lời rõ ràng ở đây. Bạn có một số dài - một hàm băm và có 16 nhóm - làm cách nào để xác định chỉ mục sao cho các đối tượng có các hàm băm khác nhau được phân bổ đều trên các nhóm? Tôi có thể tưởng tượng rằng chỉ số này được tính như thế này:

    int index = hash % buckets.length

    Ở nhà, tôi thấy rằng cách triển khai ban đầu trong mã nguồn hơi khác một chút:

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. Chúng tôi kiểm tra rằng không có xung đột và chèn a1.

  6. Hãy chuyển sang phương pháp get. Các trường hợp a1 và a2 được đảm bảo có một địa chỉ khác hash(địa chỉ khác trong bộ nhớ), vì vậy chúng tôi sẽ không tìm thấy bất cứ điều gì cho khóa này

    Điều gì sẽ xảy ra nếu chúng ta chỉ xác định lại nó hashcodetrong lớp A và cố gắng chèn vào bản đồ băm trước một cặp có khóa a1, sau đó là a2?

    Sau đó, trước tiên chúng ta sẽ tìm thấy giỏ mong muốn hashcode- thao tác này sẽ được thực hiện chính xác. Tiếp theo, chúng ta hãy bắt đầu xem qua các đối tượng Entrytrong LinkedList được đính kèm với giỏ hàng và so sánh các khóa theo equals. Bởi vì equalskhông bị ghi đè thì việc triển khai cơ sở sẽ được lấy từ lớp Object- so sánh theo tham chiếu. a1 và a2 đảm bảo có các liên kết khác nhau nên chúng ta sẽ “bỏ sót” phần tử a1 được chèn vào, còn a2 sẽ được đặt vào LinkedList dưới dạng một nút mới.

    Kết luận là gì? Có thể sử dụng làm khóa trong HashMapmột đối tượng không bị ghi đè không equalshashcode?

    Không, bạn không thể.

Phác thảo 4. “Hãy cố tình phá vỡ nó!”

Sau các câu hỏi về Lỗi và Ngoại lệ, tiếp theo là câu hỏi sau: Viết một ví dụ đơn giản trong đó một hàm sẽ ném StackOverflow. *Sau đó, tôi nhớ lại lỗi này đã cản trở tôi như thế nào khi tôi đang cố gắng viết một hàm đệ quy nào đó* Điều này có thể sẽ xảy ra trong trường hợp một lệnh gọi đệ quy, nếu điều kiện để thoát khỏi đệ quy được chỉ định không chính xác. *Sau đó, tôi bắt đầu thử một điều gì đó thông minh, cuối cùng người phỏng vấn đã giúp đỡ, mọi thứ trở nên đơn giản*
void sof() {
    sof();
}
Lỗi này khác với lỗi như thế nào OutOfMemory? *Tôi không trả lời ở đây, mãi sau này tôi mới nhận ra rằng đây là câu hỏi về kiến ​​thức Stackvề Heapbộ nhớ Java (các lệnh gọi và tham chiếu đến các đối tượng được lưu trữ trong Ngăn xếp và bản thân các đối tượng được lưu trữ trong bộ nhớ Heap). Theo đó, StackOverflow bị loại bỏ khi không còn dung lượng bộ Stacknhớ cho lệnh gọi phương thức tiếp theo và OutOfMemorydung lượng cho các đối tượng đã hết trong Heapbộ nhớ*
Đây là những khoảnh khắc tôi nhớ trong cuộc phỏng vấn. Cuối cùng, tôi được nhận vào thực tập nên tôi còn 2,5 tháng đào tạo trước mắt và nếu mọi việc suôn sẻ, tôi sẽ có một công việc ở công ty) Nếu có hứng thú, tôi có thể viết một bài báo khác, lần này nhỏ hơn, với phân tích một vấn đề đơn giản nhưng mang tính minh họa mà tôi được phỏng vấn ở một công ty khác. Đối với tôi đó là tất cả, tôi hy vọng bài viết này sẽ giúp ai đó đào sâu hoặc sắp xếp kiến ​​​​thức của họ. Chúc mọi người học tập vui vẻ!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION