JavaRush /Blog Java /Random-VI /Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấ...

Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java. Phần 5

Xuất bản trong nhóm
Xin chào! Ngày nay, nhu cầu tuyển dụng các nhà phát triển Java đang rất cao. Tất nhiên, tôi không thể cung cấp cho bạn một vị trí tuyển dụng, nhưng tôi sẽ cố gắng giúp đỡ bạn một chút để bạn có được kiến ​​thức mới và thu hẹp một số lỗ hổng. Vì vậy, chúng tôi tiếp tục phân tích hơn 250 câu hỏi phỏng vấn dành cho nhà phát triển Java. Các liên kết đến các phần phân tích trước đó nằm ở cuối bài viết.Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 1

39. Công cụ sửa đổi truy cập trong Java là gì? Hãy gọi tên của chúng. Chúng nó được dùng cho cái gì?

Trước đây tôi đã mô tả các công cụ sửa đổi quyền truy cập trong câu hỏi về các phần tử đóng gói Java. Nhưng dù sao tôi cũng sẽ nhắc nhở bạn. Công cụ sửa đổi quyền truy cập trong Java là các từ khóa mô tả mức độ truy cập được cấp cho một thành phần Java cụ thể. Công cụ sửa đổi quyền truy cập có thể là:
  • công khai - một phần tử có công cụ sửa đổi này sẽ có thể truy cập công khai. Những thứ kia. các trường và phương thức, các lớp được khai báo bằng công cụ sửa đổi công khai sẽ hiển thị cho các lớp khác từ cả gói hiện tại và từ các gói bên ngoài;
  • được bảo vệ - một phần tử có công cụ sửa đổi này sẽ có thể truy cập được từ bất kỳ đâu trong lớp hiện tại của gói hiện tại hoặc trong các lớp con cháu, ngay cả khi chúng nằm trong các gói khác;
  • default hoặc công cụ sửa đổi bị thiếu - công cụ sửa đổi này được sử dụng ngầm khi công cụ sửa đổi truy cập hoàn toàn không được chỉ định. Nó tương tự như cái trước, ngoại trừ khả năng hiển thị được cho phép trong các lớp con trong các gói khác;
  • riêng tư là riêng tư nhất trong tất cả các sửa đổi, chỉ cho phép truy cập vào phần tử trong lớp hiện tại.
Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 2

40. Kể tên tính năng chính của phương thức tĩnh và biến

Một công thức rất lạ - “các phương pháp biến đổi”. Chắc chắn điều này đề cập đến các phương pháp thông thường, không tĩnh. Vì vậy, sự khác biệt chính là các phương thức tĩnh thuộc về lớp và trên thực tế, đối với chúng, bạn không cần tạo một thể hiện của lớp này: nó chỉ có thể được gọi bằng cách sử dụng kiểu lớp. Ví dụ: chúng ta có một phương thức tĩnh để vuốt ve con mèo:
public class CatService {
   public static void petTheCat(Cat cat) {
       System.out.println("Погладить кота - " + cat.getName());
   }
Chúng ta không cần một phiên bản của lớp CatService để gọi nó :
Cat cat = new Cat(7, "Bobi");
CatService.petTheCat(cat);
Trong khi các phương thức thông thường bị ràng buộc (thuộc về) một đối tượng và để gọi chúng, bạn phải có một thể hiện (đối tượng) mà phương thức đó sẽ được gọi trên đó. Ví dụ: một con mèo có phương thức không tĩnh - meo meo:
class Cat {
   public void mew() {
       System.out.println("Meow! Meow! Meow!");
   }
Để gọi phương thức này, chúng ta cần một instance cụ thể của con mèo:
Cat cat = new Cat(7, "Bobi");
cat.mew();

41. Những hạn chế chính đối với các phương pháp tĩnh và “biến” là gì?

Như tôi đã nói trước đó, hạn chế chính của một phương thức thông thường là phải luôn có một số trường hợp mà phương thức đó sẽ được gọi. Nhưng một phương thức tĩnh không yêu cầu điều này, nhưng nó không thể tham chiếu đến tham chiếu this - tới các phần tử của đối tượng hiện tại - vì đối tượng hiện tại không tồn tại cho nó.

42. Từ khóa static có nghĩa là gì? Phương thức tĩnh có thể bị ghi đè hoặc quá tải không?

Một phần tử được chỉ định bởi từ khóa tĩnh không thuộc về một đối tượng của lớp mà thuộc về lớp đó và nó được tải khi chính lớp đó được tải. Các phần tử tĩnh là phần tử duy nhất cho toàn bộ chương trình và phần tử thông thường là phần tử duy nhất cho một đối tượng cụ thể. Tĩnh có thể là:
  • trường lớp;
  • khối khởi tạo lớp;
  • phương pháp lớp;
  • các lớp bên trong của một lớp (tuy nhiên, đó vẫn là một tautology).
Một phương thức tĩnh không thể bị ghi đè: nó thuộc về lớp và không được kế thừa, nhưng đồng thời nó có thể bị quá tải.

43. Một phương thức có thể tĩnh và trừu tượng cùng một lúc không?

Tôi đã đề cập đến điều này trong bài viết trước: một phương thức không thể trừu tượng và tĩnh cùng một lúc. Tính trừu tượng của một phương thức có nghĩa là nó phải được ghi đè ở phương thức kế tiếp. Đồng thời, một phương thức tĩnh thuộc về lớp và không thể bị ghi đè: điều này sẽ gây ra mâu thuẫn, trình biên dịch sẽ nhìn thấy và bắt đầu chửi rủa. Nếu gặp phải tình huống như vậy, bạn nên suy nghĩ nghiêm túc về tính đúng đắn của kiến ​​trúc ứng dụng của mình (xét cho cùng thì rõ ràng có điều gì đó không ổn với nó).Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 3

44. Có thể sử dụng các phương thức tĩnh ở giữa các phương thức thông thường không? Ngược lại? Tại sao?

Các phương thức tĩnh có thể được sử dụng trong các phương thức thông thường vì không có gì ngăn cản được điều này. Đồng thời, tình huống ngược lại là không thể xảy ra: một phương thức tĩnh không thể sử dụng một phương thức thông thường mà không có tham chiếu đến một thể hiện cụ thể của lớp này. Và như chúng ta nhớ, tham chiếu this không có sẵn cho các thành viên lớp tĩnh: có thể có bao nhiêu đối tượng cụ thể của lớp tùy thích và mỗi đối tượng trong số chúng sẽ có một tham chiếu đến chính nó bên trong - this . Và làm thế nào để bạn biết bạn cần lấy liên kết cụ thể nào? Nhưng không thể nào. Do đó, các phần tử tĩnh không thể tham chiếu đến các phần tử không tĩnh mà không tham chiếu đến một đối tượng cụ thể. Trên thực tế, một phương thức tĩnh chỉ có thể sử dụng một phương thức không tĩnh nếu nó có tham chiếu đến một đối tượng cụ thể. Ví dụ: một trong những lý lẽ được đưa ra:
public static void petTheCat(Cat cat) {
   System.out.println("Погладить кота - " + cat.getName());
}
Ở đây chúng ta thấy rằng phương thức tĩnh petTheCat gọi phương thức bình thường, không tĩnh của đối tượng Cat - getName .

45. Giao diện là gì? Có thể có một giao diện cuối cùng?

Như chúng ta đã nhớ, không có tính đa kế thừa trong Java. Giao diện là một cái gì đó thay thế cho nó. Giao diện trông giống như một lớp rất đơn giản. Chúng xác định chức năng mà không cần triển khai cụ thể, được triển khai bởi các lớp triển khai (triển khai) các giao diện này. Ví dụ về giao diện:
public interface Animal {
    void voice();
}
Một ví dụ về việc triển khai giao diện của một lớp:
class Cat implements Animal {

   @Override
   public void voice() {
       System.out.println("Meow! Meow! Meow!");
   }
}
Điều chính bạn cần biết về việc sử dụng giao diện là:
  1. Các phương thức giao diện chỉ được chứa một tiêu đề, không có phần thân phương thức cụ thể, tức là. phải trừu tượng (nhưng không sử dụng từ khóa abstract ). Ngoại lệ cho điều này là các phương thức tĩnh và mặc định, đòi hỏi phải có nội dung phương thức.
  2. Một lớp có thể triển khai nhiều giao diện (như tôi đã nói, đây là một giải pháp thay thế cho đa kế thừa), được viết cách nhau bằng dấu phẩy: class Lion thực hiện Animal, Wild .
  3. Giao diện được tạo bằng từ khóa -interface .
  4. Khi triển khai giao diện theo một lớp, từ khóa được sử dụng - thực hiện .
  5. Một lớp triển khai một giao diện cụ thể phải triển khai tất cả các phương thức trừu tượng của nó hoặc phải khai báo chính nó là trừu tượng.
  6. Mục đích chính của việc sử dụng giao diện là thực hiện tính đa hình (khả năng của các đối tượng có nhiều dạng).
  7. Theo quy định, các công cụ sửa đổi truy cập cho các phương thức không được ghi trong giao diện: theo mặc định, chúng được công khai và các công cụ sửa đổi khác không phải là public không thể được chỉ định. Kể từ Java 9, bạn có thể sử dụng các công cụ sửa đổi riêng cho các phương thức.
  8. Các biến giao diện theo mặc định là tĩnh cuối cùng , nói cách khác là các hằng số: chúng luôn cần được khởi tạo trực tiếp trong giao diện.
  9. Bạn không thể tạo một đối tượng giao diện.
Tất nhiên, câu trả lời cho câu hỏi liệu giao diện có thể là cuối cùng hay không. Rốt cuộc, bản chất của giao diện là phải được triển khai. Và như tất cả chúng ta đều nhớ rất rõ, cuối cùng ở cấp lớp khiến nó không thể kế thừa và trong trường hợp giao diện, không thể triển khai. Tại sao chúng ta cần một giao diện không thể triển khai và sử dụng? Đúng vậy - không cần thiết! Và trình biên dịch nghĩ như vậy)) Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 4Ý nghĩa chỉ xuất hiện khi đưa ra các phương thức tĩnh trong các giao diện với Java 8, nhưng điều này không thay đổi được thực tế là giao diện không thể là cuối cùng. Tôi đã nói về giao diện, rất hời hợt, bởi vì... đây là một chủ đề rộng Đọc thêm về điều này trong các bài viết về giao diện trong Javasự khác biệt giữa các lớp trừu tượng và giao diện .

46. ​​​​Tôi có thể khởi tạo các trường tĩnh ở đâu?

Các trường tĩnh có thể được khởi tạo:
  • trực tiếp khi khai báo, thông qua dấu bằng = ;
  • trong khối khởi tạo tĩnh;
  • trong khối khởi tạo không tĩnh, nhưng bạn phải hiểu rằng mỗi khi một đối tượng được tạo, trường này sẽ bị khối khởi tạo này ghi đè;
  • trong hàm tạo của lớp. Mỗi lần hàm tạo này được gọi (nghĩa là khi một đối tượng được tạo thông qua hàm tạo này), trường này sẽ bị ghi đè;
  • trong các phương thức tĩnh;
  • trong các phương pháp không tĩnh;
  • trong các lớp tĩnh và không tĩnh, cục bộ và ẩn danh bên trong.

47. Lớp ẩn danh là gì?

Các lớp ẩn danh là các lớp không có kiểu riêng. Tôi đang nói về cái gì vậy? Khi chúng ta nói về giao diện, tôi đã đề cập rằng bạn không thể tạo đối tượng giao diện: bạn chỉ có thể tạo đối tượng của lớp thực hiện giao diện. Điều gì sẽ xảy ra nếu bạn không muốn triển khai một giao diện trong một lớp nhưng vẫn cần một đối tượng thuộc loại giao diện đó? Và rất có thể đây sẽ là một trường hợp duy nhất sử dụng đối tượng này. Và bạn không cần phải tạo một lớp triển khai chính thức. Làm thế nào bạn sẽ làm điều này? Phải! Thông qua một lớp ẩn danh! Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 5Giả sử chúng ta có một số giao diện Động vật :
public final interface Animal {
   public void voice();
}
Nếu chúng ta muốn khởi tạo giao diện này thông qua một lớp ẩn danh:
Animal cat = new Animal() {
   @Override
   public void voice() {
       System.out.println("Meow! Meow! Meow!");
   }
};
Và sau đó bạn có thể sử dụng đối tượng này và phương thức được triển khai của nó một cách an toàn - voice . Nghĩa là, một lớp ẩn danh triển khai giao diện này và tất cả các phương thức trừu tượng của nó ngay tại đây và ngay bây giờ. Nếu không, chúng ta sẽ không thể tạo một đối tượng giao diện/lớp trừu tượng vì có các phương thức chưa được triển khai/trừu tượng. Như tôi đã đề cập, các lớp ẩn danh không chỉ được sử dụng để triển khai các phương thức trừu tượng của một giao diện mà còn để triển khai các phương thức trừu tượng của một lớp trừu tượng. Cách tiếp cận này phù hợp với các tình huống khi một đối tượng được sử dụng một lần hoặc chỉ cần triển khai một phương thức nhất định một lần và không cần phải tạo một lớp riêng biệt sẽ triển khai lớp/giao diện trừu tượng được yêu cầu. Nhưng tôi cũng sẽ lưu ý rằng việc sử dụng các lớp ẩn danh là một điều hiếm khi xảy ra trong công việc: theo quy định, ưu tiên vẫn được dành cho các lớp thông thường. Bạn có thể đọc thêm về các lớp ẩn danh trong bài viết này .

48. Lớp nguyên thủy là gì?

Đối với tôi, đây là một câu hỏi rất kỳ lạ và có lẽ đây là một câu hỏi bẫy, bởi vì trong Java không có cái gọi là các lớp nguyên thủy: có lẽ ngoại trừ khái niệm về các kiểu nguyên thủy mà chúng ta đã xem xét trước đó. Như chúng ta nhớ, có 8 kiểu nguyên thủy trong Java - byte , short , int , long , float , double , char , boolean .Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 6

49. Lớp “wrapper” là gì?

Vấn đề chính khi sử dụng các kiểu nguyên thủy trong Java là chúng vẫn không phải là các lớp và Java vẫn là ngôn ngữ OOP. Nghĩa là, các chương trình được viết bằng ngôn ngữ này được giảm xuống mức tương tác giữa các đối tượng. Vâng, nguyên thủy không phải là đối tượng. Họ không có các phương thức, thậm chí không có các phương thức tiêu chuẩn từ lớp Object . Chà, điều gì sẽ xảy ra nếu chúng ta cần sử dụng một giá trị nguyên thủy làm khóa trong Map ? Sau đó, bạn cần gọi phương thức hashCode . Bạn cũng có thể gọi phương thức bằng ở đó . Vậy thì sao? Có thể có rất, rất nhiều khoảnh khắc cần có một lớp chứ không phải lớp nguyên thủy, điều này làm cho các phần tử nguyên thủy không được sử dụng và không mong muốn trong chương trình, bởi vì điều này phá hủy chính ý tưởng về OOP. Nhưng không phải mọi thứ đều tệ như nó có vẻ. Xét cho cùng, Java có khái niệm về trình bao bọc nguyên thủy. Mỗi kiểu nguyên thủy có một lớp tương tự:
  • byte -> Byte.class
  • ngắn -> Short.class
  • int -> Integer.class
  • dài -> Long.class
  • float -> Float.class
  • gấp đôi -> Double.class
  • char -> Ký tự.class
  • boolean -> Boolean.class
Đây là sự thể hiện của các kiểu đơn giản, nhưng ở dạng các lớp chính thức với một loạt các phương thức đa dạng và chức năng. Để thuận tiện cho việc sử dụng các lớp này, các khái niệm về hộp thư tự động và hộp thư mở đã được giới thiệu. Autoboxing - tự động chuyển đổi loại nguyên thủy sang lớp tương tự nếu cần thiết (ví dụ: int thành Integer ). Mở hộp là quá trình ngược lại với quá trình trước đó: tự động chuyển đổi lớp trình bao bọc nguyên thủy thành loại nguyên thủy (ví dụ: Integer thành int ). Nhờ sự ra đời của các lớp trình bao bọc nguyên thủy và các quy trình tự động đóng hộpmở hộp , các kiểu nguyên thủy đã có thể trở thành thành viên chính thức của ngôn ngữ OOP - Java. Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 7Để tìm hiểu thêm về chủ đề này, tôi thực sự khuyên bạn nên đọc bài viết này .

50. Lớp Nested là gì? Khi nào nó được sử dụng?

Lớp lồng nhau là lớp bên trong là thành viên của lớp khác. Trong Java, có 4 loại lớp bên trong như vậy: 1. Lớp bên trong Loại lớp này được khai báo trực tiếp trong phần thân của một lớp khác. Một lớp bên trong lồng nhau có thể truy cập bất kỳ trường riêng tư hoặc phương thức nào của một thể hiện của lớp bên ngoài. Ví dụ: hãy tạo một vườn thú trong đó chúng ta sẽ có một con vật - ngựa vằn:
public class Zoo {
   class Zebra {
       public void toFeed(String food) {
           System.out.println("Дать зебре - " + food);
       }
   }
}
Không có gì phức tạp phải không? Chúng ta hãy xem một ví dụ về việc tạo một đối tượng lớp bên trong:
Zoo.Zebra zebra = new Zoo().new Zebra();
zebra.toFeed("яблоко");
Như bạn đã thấy, bắt buộc phải tạo một đối tượng của lớp khung, dựa vào tham chiếu mà bạn có thể tạo một đối tượng của lớp bên trong. Tôi cũng muốn lưu ý rằng lớp bên trong lồng nhau không thể có các phương thức tĩnh hoặc trường tĩnh. Đó là bởi vì lớp bên trong được liên kết ngầm với đối tượng của lớp bên ngoài và nó không thể khai báo bất kỳ phương thức tĩnh nào bên trong chính nó. 2. Các lớp lồng nhau tĩnh Lớp này tương tự như lớp trước, chỉ khác là nó có một bộ sửa đổi truy cập tĩnh gần phần khai báo lớp. Vì loại lớp này không có quyền truy cập vào các trường không tĩnh của lớp bên ngoài, nên nó giống phần tĩnh của lớp bên ngoài hơn là lớp bên trong. Trong trường hợp này, dữ liệu lớp có quyền truy cập vào tất cả các thành viên tĩnh của lớp bên ngoài, thậm chí cả các thành viên riêng tư. Ví dụ về lớp lồng nhau tĩnh:
public class Zoo {
   static class Zebra {
       public void toFeed(String food) {
           System.out.println("Дать зебре - " + food);
       }
   }
}
Phương pháp tạo hơi khác so với phương pháp trước:
Zoo.Zebra zebra = new Zoo.Zebra();
zebra.toFeed("яблоко");
Ở đây chúng ta không cần một đối tượng của lớp bên ngoài để tạo một đối tượng của lớp tĩnh lồng nhau. Từ lớp bên ngoài, chúng ta chỉ cần loại của nó để có thể tìm thấy vị trí của lớp lồng nhau. 3. Lớp cục bộ Lớp cục bộ là các lớp được khai báo bên trong phần thân của một phương thức và việc tạo và sử dụng một đối tượng của lớp cục bộ chỉ có thể thực hiện được trong phương thức này. Ví dụ:
public class Zoo {
   public void toFeed(String animal, String food) {
       switch(animal){
           case "зебра":
               class Zebra {
                   void toFeedZebra(String food) {
                       System.out.println("Дать зебре - " + food);
                   }
               }
               Zebra zebra = new Zebra();
               zebra.toFeedZebra(food);
               ...
Ví dụ sử dụng:
Zoo zoo = new Zoo();
zoo.toFeed("зебра", "яблоко");
Nếu không nhìn thấy mã của phương thức toFeed , bạn thậm chí sẽ không nghi ngờ sự tồn tại của một lớp cục bộ, phải không? Một lớp cục bộ không thể là tĩnh hoặc thoáng qua , nhưng nó có thể được đánh dấu là trừu tượng hoặc cuối cùng (chỉ OR, vì việc sử dụng hai công cụ sửa đổi này sẽ gây ra xung đột). 4. Lớp ẩn danh Chúng ta đã nói về lớp ẩn danh ở trên và như bạn nhớ, chúng có thể được tạo từ hai nguồn - giao diện và lớp. Lý do sử dụng Các lớp tĩnh và không tĩnh nội bộ được sử dụng vì đôi khi tốt hơn là nên nhúng các lớp nhỏ vào trong các lớp lớn hơn và giữ chúng lại với nhau: cách này chúng sẽ có độ gắn kết cao hơn và có mục đích chung. Trên thực tế, việc sử dụng các lớp lồng nhau làm tăng khả năng đóng gói mã. Lý do chọn các lớp cục bộ có thể là một lớp nhất định chỉ được sử dụng trong một phương thức duy nhất. Trong trường hợp này, có cần thiết phải trải rộng mã trong toàn bộ ứng dụng không? KHÔNG. Nhưng đồng thời tôi sẽ nói thêm rằng trong thực tế của mình, tôi chưa bao giờ thấy việc sử dụng các lớp địa phương, bởi vì sự cần thiết của chúng đang gây nhiều tranh cãi. Chà, lý do sử dụng các lớp ẩn danh có thể là việc triển khai cụ thể một giao diện hoặc lớp trừu tượng sẽ chỉ cần một lần, do đó không cần phải tạo một lớp riêng biệt, đầy đủ để triển khai cho việc này. Thay vào đó, nói một cách đơn giản, chúng ta đã triển khai (các) phương thức mà chúng ta cần thông qua một lớp ẩn danh, sử dụng đối tượng này và quên mất nó (à, trình thu gom rác đã nhớ về nó). Bài viết này và bài viết nàyPhân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 8 sẽ giúp bạn nghiên cứu các lớp nội bộ một cách chi tiết hơn .

51. Một lớp có thể có những công cụ sửa đổi truy cập nào?

Như chúng ta nhớ, có nhiều loại lớp khác nhau và các công cụ sửa đổi truy cập khác nhau có thể áp dụng cho chúng:
  • một lớp bên ngoài có thể có công cụ sửa đổi truy cập công khai hoặc không có công cụ sửa đổi (công cụ sửa đổi mặc định);
  • lớp bên trong hỗ trợ tất cả 4 công cụ sửa đổi truy cập;
  • lớp tĩnh lồng nhau hỗ trợ tất cả các công cụ sửa đổi truy cập ngoại trừ protected , bởi vì công cụ sửa đổi này ngụ ý tính kế thừa, mâu thuẫn với thành viên tĩnh của lớp (các phần tử tĩnh không được kế thừa);
  • một lớp cục bộ chỉ có thể có một công cụ sửa đổi mặc định (tức là không có công cụ sửa đổi nào cả);
  • lớp ẩn danh : nếu không có khai báo loại lớp thì không có công cụ sửa đổi truy cập nào cả.
Đây là nơi chúng ta sẽ dừng lại ngày hôm nay. Hẹn sớm gặp lại!Phân tích các câu hỏi và câu trả lời từ các cuộc phỏng vấn dành cho nhà phát triển Java.  Phần 5 - 9
Các tài liệu khác trong loạt bài:
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION