Làm thế nào tôi có thể giải thích sự khác biệt giữa một lớp Giao diện và lớp Trừu tượng?


469

Trong một trong các cuộc phỏng vấn của tôi, tôi đã được yêu cầu giải thích sự khác biệt giữa Giao diệnlớp Trừu tượng .

Đây là câu trả lời của tôi:

Các phương thức của một giao diện Java hoàn toàn trừu tượng và không thể có các triển khai. Một lớp trừu tượng Java có thể có các phương thức cá thể thực hiện một hành vi mặc định.

Các biến được khai báo trong giao diện Java theo mặc định là cuối cùng. Một lớp trừu tượng có thể chứa các biến không phải là cuối cùng.

Các thành viên của giao diện Java được công khai theo mặc định. Một lớp trừu tượng Java có thể có các hương vị thông thường của các thành viên lớp như riêng tư, được bảo vệ, v.v.

Một giao diện Java nên được triển khai bằng cách sử dụng từ khóa. Một lớp trừu tượng Java nên được mở rộng bằng cách sử dụng từ khóa.

Một giao diện chỉ có thể mở rộng một giao diện Java khác, một lớp trừu tượng có thể mở rộng một lớp Java khác và thực hiện nhiều giao diện Java.

Một lớp Java có thể thực hiện nhiều giao diện nhưng nó chỉ có thể mở rộng một lớp trừu tượng.

Tuy nhiên, người phỏng vấn không hài lòng, và nói với tôi rằng mô tả này đại diện cho " kiến thức bookish ".

Ông hỏi tôi một câu trả lời thực tế hơn, giải thích khi tôi sẽ chọn một lớp trừu tượng qua một giao diện, sử dụng ví dụ thực tế .

Tôi đã đi sai ở đâu?


32
Có lẽ câu trả lời của bạn trông giống như bạn đang nói cái gì mà bạn không hiểu? Nó có thể chỉ đơn giản là bạn cần thay đổi phong cách nói với một cái giống với lời nói của bạn hơn.
Kirill Kobelev

19
Bạn đã trả lời với một danh sách (khá chính xác) sự khác biệt kỹ thuật. Người phỏng vấn đã được rất có thể tìm kiếm một câu trả lời khái niệm hơn (ví dụ, trên cơ sở những gì người ta sẽ chọn giữa việc sử dụng một giao diện và một lớp trừu tượng).
Ted Hopp

15
Bạn đã quên nói rằng các lớp trừu tượng có các hàm tạo, mặc dù bạn không thể khởi tạo một lớp trừu tượng, const. được sử dụng bởi các lớp con. Các giao diện chỉ ra "cái gì" chứ không phải "làm thế nào" bởi vì chúng xác định một hợp đồng (danh sách các phương thức) trong khi một abst. lớp cũng có thể chỉ ra "làm thế nào" (thực hiện một meth.). Sử dụng int. bạn có thể mô phỏng nhiều kế thừa (một lớp có thể thực hiện nhiều int. nhưng chỉ mở rộng một lớp). Sử dụng int. bạn có thể có một loại cơ sở cho khác nhau. gia đình: Flyer f = new Máy ​​bay (); Flyer f2 = new Bird (); Chim và Máy bay không tương ứng với cùng một familiy nhưng cả hai đều có thể bay (là những người bay).
Francisco Goldenstein

7
Vì giao diện java8 có thể chứa các phương thức .. vì vậy ngoài khái niệm OO, những cái gọi là "sự khác biệt" này có thể thay đổi bất kỳ ngày nào.
người mang nhẫn

15
Tôi không có bất kỳ vấn đề nào với câu trả lời của bạn và tôi không nghĩ người phỏng vấn có bất kỳ công việc nào để chế nhạo 'kiến thức sách'. Người phỏng vấn không phải lúc nào cũng biết câu trả lời chính xác cho câu hỏi họ hỏi và một số cuộc phỏng vấn chỉ phục vụ để cảnh báo bạn không làm việc ở đó.
Hầu tước Lorne

Câu trả lời:


513

Tôi sẽ cung cấp cho bạn một ví dụ đầu tiên:

public interface LoginAuth{
   public String encryptPassword(String pass);
   public void checkDBforUser();
}

Giả sử bạn có 3 cơ sở dữ liệu trong ứng dụng của mình. Sau đó, mỗi và mọi triển khai cho cơ sở dữ liệu đó cần xác định 2 phương thức trên:

public class DBMySQL implements LoginAuth{
          // Needs to implement both methods
}
public class DBOracle implements LoginAuth{
          // Needs to implement both methods
}
public class DBAbc implements LoginAuth{
          // Needs to implement both methods
}

Nhưng điều gì xảy ra nếu encryptPassword()không phụ thuộc vào cơ sở dữ liệu và nó giống nhau cho mỗi lớp? Sau đó, ở trên sẽ không phải là một cách tiếp cận tốt.

Thay vào đó, hãy xem xét phương pháp này:

public abstract class LoginAuth{
   public String encryptPassword(String pass){
            // Implement the same default behavior here 
            // that is shared by all subclasses.
   }

   // Each subclass needs to provide their own implementation of this only:
   public abstract void checkDBforUser();
}

Bây giờ trong mỗi lớp trẻ, chúng ta chỉ cần thực hiện một phương pháp - phương pháp đó là cơ sở dữ liệu phụ thuộc.


97
Tôi không chắc điều này thực sự giải thích cho sự khác biệt ... chắc chắn đó là một kỹ thuật hay. Tôi cho rằng cũng đáng để chỉ ra rằng Java 8 cuối cùng đã thừa nhận rằng C ++ đã đúng và có thể thực hiện nhiều kế thừa và có thể sử dụng và do đó các giao diện giờ đây có thể xác định không chỉ chữ ký hàm mà còn cung cấp các triển khai mặc định. Như vậy, sử dụng một giao diện sẽ được ưa thích hơn.
thecoshman

1
@thecoshman khác biệt gì nó sẽ làm nếu tôi tiếp cận vấn đề này như trong câu trả lời (lớp trừu tượng với một phương pháp thực hiện và trừu tượng khác) hoặc định nghĩa một giao diện với một thực hiện phương pháp mặc định? Về cơ bản, điều tôi đang cố gắng nói là bạn đã viết rằng "sử dụng giao diện sẽ thích hợp hơn" và câu hỏi của tôi là - tại sao?
Neutrino

1
Vì vậy, tôi đoán thật công bằng khi nói rằng với các giao diện, việc triển khai những gì được định nghĩa là tùy thuộc vào lớp thực sự thực hiện giao diện, trong khi những thứ trong một lớp trừu tượng là "cốt lõi" đối với các lớp mở rộng lớp; tức là, nó không thay đổi.
orrymr

4
@Neutrino Mặc dù Java cho phép bạn triển khai nhiều giao diện, mỗi giao diện cung cấp các triển khai mặc định cho các hàm, bạn vẫn chỉ có thể mở rộng một lớp duy nhất. Như vậy, sử dụng một giao diện có thể cung cấp sự linh hoạt hơn cho những người muốn sử dụng nó, cùng với các giao diện khác.
thecoshman

3
@HiradNikoo Xin lỗi vì nhận xét muộn, nhưng tôi chỉ vấp phải chủ đề này. Bạn cũng có thể coi kế thừa lớp là mối quan hệ IS-A, trong khi các giao diện biểu thị "có một chức năng nhất định".
Alexander Jank 17/12/17

206

Không có gì là hoàn hảo trong thế giới này. Họ có thể đã được mong đợi nhiều hơn một cách tiếp cận thực tế.

Nhưng sau lời giải thích của bạn, bạn có thể thêm những dòng này với một cách tiếp cận hơi khác.

  1. Các giao diện là các quy tắc (quy tắc vì bạn phải đưa ra một triển khai cho chúng mà bạn không thể bỏ qua hoặc tránh, để chúng được áp đặt như quy tắc) hoạt động như một tài liệu hiểu biết chung giữa các nhóm phát triển phần mềm.

  2. Các giao diện đưa ra ý tưởng những gì sẽ được thực hiện nhưng không phải là nó sẽ được thực hiện như thế nào. Vì vậy, việc thực hiện hoàn toàn phụ thuộc vào nhà phát triển bằng cách tuân theo các quy tắc nhất định (có nghĩa là chữ ký của các phương thức).

  3. Các lớp trừu tượng có thể chứa các khai báo trừu tượng, triển khai cụ thể hoặc cả hai.

  4. Các khai báo trừu tượng giống như các quy tắc phải tuân theo và các triển khai cụ thể giống như các hướng dẫn (bạn có thể sử dụng nó như hiện tại hoặc bạn có thể bỏ qua nó bằng cách ghi đè và đưa ra triển khai của riêng bạn cho nó).

  5. Hơn nữa, các phương thức có cùng chữ ký có thể thay đổi hành vi trong các ngữ cảnh khác nhau được cung cấp dưới dạng khai báo giao diện như các quy tắc để thực hiện theo các bối cảnh khác nhau.

Chỉnh sửa: Java 8 tạo điều kiện để xác định các phương thức mặc định và tĩnh trong giao diện.

public interface SomeInterfaceOne {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceOne defaultMethod::"+inputString);
    }
}

Bây giờ khi một lớp sẽ thực hiện SomeInterface, nó không phải là bắt buộc để cung cấp thực hiện các phương pháp mặc định của giao diện.

Nếu chúng ta có một giao diện khác với các phương thức sau:

public interface SomeInterfaceTwo {

    void usualAbstractMethod(String inputString);

    default void defaultMethod(String inputString){
        System.out.println("Inside SomeInterfaceTwo defaultMethod::"+inputString);
    }

}

Java không cho phép mở rộng nhiều lớp vì nó dẫn đến Bài toán Diamond Diamond , nơi trình biên dịch không thể quyết định sử dụng phương thức siêu lớp nào. Với các phương thức mặc định, vấn đề kim cương cũng sẽ phát sinh đối với các giao diện. Bởi vì nếu một lớp học đang thực hiện cả hai

SomeInterfaceOne and SomeInterfaceTwo

và không thực hiện phương thức mặc định phổ biến, trình biên dịch không thể quyết định chọn cái nào. Để tránh vấn đề này, trong java 8 bắt buộc phải thực hiện các phương thức mặc định phổ biến của các giao diện khác nhau. Nếu bất kỳ lớp nào đang thực hiện cả hai giao diện trên, thì nó phải cung cấp triển khai cho phương thức defaultMethod () nếu không trình biên dịch sẽ đưa ra lỗi thời gian biên dịch.


11
+1, đây thực sự là một câu trả lời tốt để tránh nhầm lẫn. Nhưng tôi đã không thấy bất kỳ liên kết nào và không biết tại sao bạn trích dẫn những dòng có giá trị. Làm cho chúng như điểm nếu có thể :).
Suresh Atta

Đọc nhận xét của tôi ở trên về việc mô phỏng nhiều kế thừa bằng cách sử dụng giao diện và sử dụng giao diện để có loại cơ sở cho các lớp của các gia đình khác nhau. Tôi nghĩ rằng người phỏng vấn muốn nghe loại câu trả lời từ người được phỏng vấn.
Francisco Goldenstein

Nhận xét của bạn cũng chỉ ra một ví dụ tốt về sử dụng giao diện. Tôi đã viết, những gì tôi cảm thấy trong khi làm việc hàng ngày. Những từ này có thể không chuyên nghiệp hoặc chính xác. Nhưng đó là những gì tôi biết sau khi làm việc chặt chẽ với các lớp và giao diện trừu tượng trong mã hóa hàng ngày của tôi.
Shailesh Saxena

4. Thực hiện cụ thể cũng là các quy tắc, có thực hiện mặc định.
Trung úy

@Luten: Theo hiểu biết của tôi, Nếu bạn có thể tránh / bỏ qua một quy tắc mà không có bất kỳ vấn đề nào, đó phải là một hướng dẫn không phải là quy tắc. Xin hãy sửa tôi nếu tôi sai.
Shailesh Saxena

168

Bạn đã thực hiện một bản tóm tắt tốt về sự khác biệt thực tế trong sử dụng và thực hiện nhưng không nói gì về sự khác biệt về ý nghĩa.

An giao diện là một mô tả về hành vi mà một lớp thực hiện sẽ có. Lớp triển khai đảm bảo rằng nó sẽ có các phương thức có thể được sử dụng trên nó. Nó về cơ bản là một hợp đồng hoặc một lời hứa mà lớp phải thực hiện.

Một lớp trừu tượng là một cơ sở cho các lớp con khác nhau chia sẻ hành vi không cần phải lặp đi lặp lại. Các lớp con phải hoàn thành hành vi và có tùy chọn ghi đè hành vi được xác định trước (miễn là nó không được định nghĩa là finalhoặcprivate ).

Bạn sẽ tìm thấy các ví dụ tốt trong java.utilgói bao gồm các giao diện như Listvà các lớp trừu tượng giống như AbstractListđã thực hiện giao diện. Các tài liệu chính thức mô tả AbstractListnhư sau:

Lớp này cung cấp một triển khai khung xương của giao diện Danh sách để giảm thiểu nỗ lực cần thiết để thực hiện giao diện này được hỗ trợ bởi kho lưu trữ dữ liệu "truy cập ngẫu nhiên" (chẳng hạn như một mảng).


16
Đây nên là câu trả lời. Không phải là một danh sách các chi tiết, nhưng khái niệm cơ bản tạo ra sự khác biệt giữa một giao diện và một lớp trừu tượng, không chỉ trong Java mà nói chung.
edc65

1
Cái này thật sự rất tốt. Tất nhiên những câu trả lời khác cũng tốt. Nhưng điều này cho bạn biết một abstracttừ khóa chính về từ khóa, đó là khi trình biên dịch nhìn thấy điều này, họ biết, thông tin sau đây không đầy đủ và cần thực hiện . Các giao diện luôn không đầy đủ, nhưng các lớp trừu tượng là trừu tượng vì chúng phải có incomplete (abstract)các phương thức.
Rakib

85

Một giao diện bao gồm các biến singleton (chung tĩnh) và các phương thức trừu tượng công khai. Chúng ta thường thích sử dụng một giao diện trong thời gian thực khi chúng ta biết phải làm gì nhưng không biết làm thế nào để làm điều đó .

Khái niệm này có thể được hiểu rõ hơn bằng ví dụ:

Hãy xem xét một lớp thanh toán. Thanh toán có thể được thực hiện bằng nhiều cách, chẳng hạn như PayPal, thẻ tín dụng, v.v. Vì vậy, chúng tôi thường lấy Thanh toán làm giao diện chứa makePayment()phương thức và CreditCard và PayPal là hai lớp triển khai.

public interface Payment
{
    void makePayment();//by default it is a abstract method
}
public class PayPal implements Payment
{
    public void makePayment()
    {
        //some logic for PayPal payment
        //e.g. Paypal uses username and password for payment
    }
}
public class CreditCard implements Payment
{
    public void makePayment()
    {
        //some logic for CreditCard payment
        //e.g. CreditCard uses card number, date of expiry etc...
    }
}

Trong ví dụ trên, CreditCard và PayPal là hai lớp / chiến lược triển khai. Một Giao diện cũng cho phép chúng ta khái niệm đa kế thừa trong Java mà một lớp trừu tượng không thể thực hiện được.

Chúng tôi chọn một lớp trừu tượng khi có một số tính năng mà chúng tôi biết phải làm gì và các tính năng khác mà chúng tôi biết cách thực hiện .

Hãy xem xét ví dụ sau:

public abstract class Burger
{
    public void packing()
    {
        //some logic for packing a burger
    }
    public abstract void price(); //price is different for different categories of burgers
}
public class VegBerger extends Burger
{
    public void price()
    {
        //set price for a veg burger.
    }
}
public class NonVegBerger extends Burger
{
    public void price()
    {
        //set price for a non-veg burger.
    }
}

Nếu chúng ta thêm các phương thức (cụ thể / trừu tượng) trong tương lai vào một lớp trừu tượng nhất định, thì lớp triển khai sẽ không cần thay đổi mã của nó. Tuy nhiên, nếu chúng ta thêm các phương thức trong một giao diện trong tương lai, chúng ta phải thêm các triển khai cho tất cả các lớp đã thực hiện giao diện đó, nếu không sẽ xảy ra lỗi thời gian biên dịch.

Có những khác biệt khác nhưng đây là những điểm chính có thể là những gì người phỏng vấn của bạn mong đợi. Hy vọng điều này là hữu ích.


1
Chà, câu trả lời này có ý nghĩa rất nhiều, và nó khá rõ ràng với ví dụ, khi chúng ta bắt đầu lựa chọn giữa interfaceabstract class.
MAC

"Phải làm gì nhưng không biết cách thực hiện" khi chúng ta định nghĩa một phương thức mà không thực hiện bất kỳ triển khai nào trong đó "void makePayment ();", trong khi xác định các triển khai của phương thức trong lớp sẽ thực hiện giao diện.
Abdel-Raouf

45

Sự khác biệt giữa lớp Abstact và giao diện

  1. Các lớp trừu tượng so với các giao diện trong Java 8
  2. Sự khác biệt về khái niệm:

Các phương thức mặc định giao diện trong Java 8

  1. Phương pháp mặc định là gì?
  2. Đã giải quyết lỗi biên dịch phương thức ForEach bằng Phương thức mặc định
  3. Phương pháp mặc định và nhiều vấn đề mơ hồ kế thừa
  4. Điểm quan trọng về các phương thức mặc định của giao diện java:

Phương thức tĩnh giao diện Java

  1. Phương thức tĩnh Giao diện Java, ví dụ mã, phương thức tĩnh so với phương thức mặc định
  2. Điểm quan trọng về phương thức tĩnh giao diện java:

Giao diện chức năng Java



Các lớp trừu tượng so với các giao diện trong Java 8

Các thay đổi giao diện Java 8 bao gồm các phương thức tĩnh và các phương thức mặc định trong các giao diện. Trước Java 8, chúng ta chỉ có thể có các khai báo phương thức trong các giao diện. Nhưng từ Java 8, chúng ta có thể có các phương thức mặc định và phương thức tĩnh trong các giao diện.

Sau khi giới thiệu Phương thức mặc định, có vẻ như các giao diện và các lớp trừu tượng là như nhau. Tuy nhiên, chúng vẫn là khái niệm khác nhau trong Java 8.

Lớp trừu tượng có thể định nghĩa hàm tạo. Chúng có cấu trúc chặt chẽ hơn và có thể có một trạng thái liên quan đến chúng. Ngược lại, phương thức mặc định chỉ có thể được triển khai trong các điều khoản gọi các phương thức giao diện khác, không có tham chiếu đến trạng thái của một triển khai cụ thể. Do đó, cả hai sử dụng cho các mục đích khác nhau và lựa chọn giữa hai thực sự phụ thuộc vào bối cảnh kịch bản.

Sự khác biệt về khái niệm:

Các lớp trừu tượng có giá trị cho việc triển khai các giao diện của bộ xương (tức là một phần) nhưng không nên tồn tại nếu không có giao diện phù hợp.

Vì vậy, khi các lớp trừu tượng được giảm hiệu quả thành tầm nhìn thấp, việc triển khai các giao diện của bộ xương, các phương thức mặc định có thể loại bỏ điều này không? Quyết định: Không! Việc thực hiện các giao diện hầu như luôn đòi hỏi một số hoặc tất cả các công cụ xây dựng lớp mà các phương thức mặc định thiếu. Và nếu một số giao diện không, đó rõ ràng là một trường hợp đặc biệt, điều này sẽ không khiến bạn lạc lối.

Các phương thức mặc định giao diện trong Java 8

Java 8 giới thiệu tính năng mới của Phương thức mặc định , hay (Phương thức bảo vệ), cho phép nhà phát triển thêm các phương thức mới vào Giao diện mà không phá vỡ việc triển khai các Giao diện này. Nó cung cấp tính linh hoạt để cho phép Giao diện xác định việc triển khai sẽ sử dụng làm mặc định trong trường hợp Lớp cụ thể không cung cấp triển khai cho phương thức đó.

Hãy xem xét ví dụ nhỏ để hiểu cách thức hoạt động của nó:

public interface OldInterface {
    public void existingMethod();
 
    default public void newDefaultMethod() {
        System.out.println("New default method"
               + " is added in interface");
    }
}

Lớp sau sẽ biên dịch thành công trong Java JDK 8,

public class OldInterfaceImpl implements OldInterface {
    public void existingMethod() {
     // existing implementation is here…
    }
}

Nếu bạn tạo một phiên bản của OldInterfaceImpl:

OldInterfaceImpl obj = new OldInterfaceImpl ();
// print “New default method add in interface”
obj.newDefaultMethod(); 

Phương thức mặc định:

Các phương thức mặc định không bao giờ là cuối cùng, không thể được đồng bộ hóa và không thể ghi đè các phương thức của Object. Chúng luôn được công khai, điều này hạn chế nghiêm trọng khả năng viết các phương pháp ngắn và có thể sử dụng lại.

Các phương thức mặc định có thể được cung cấp cho Giao diện mà không ảnh hưởng đến các Lớp triển khai vì nó bao gồm triển khai. Nếu mỗi phương thức được thêm vào trong Giao diện được xác định bằng triển khai thì không có Lớp triển khai nào bị ảnh hưởng. Một lớp triển khai có thể ghi đè lên việc thực hiện mặc định được cung cấp bởi Giao diện.

Các phương thức mặc định cho phép thêm chức năng mới vào các Giao diện hiện có mà không phá vỡ triển khai cũ của các Giao diện này.

Khi chúng tôi mở rộng giao diện chứa phương thức mặc định, chúng tôi có thể thực hiện như sau,

  1. Không ghi đè phương thức mặc định và sẽ kế thừa phương thức mặc định.
  2. Ghi đè phương thức mặc định tương tự như các phương thức khác mà chúng tôi ghi đè trong lớp con.
  3. Redeclare phương thức mặc định là trừu tượng, buộc lớp con ghi đè lên nó.

Đã giải quyết lỗi biên dịch phương thức ForEach bằng Phương thức mặc định

Đối với Java 8, các bộ sưu tập JDK đã được mở rộng và phương thức forEach được thêm vào toàn bộ bộ sưu tập (hoạt động cùng với lambdas). Với cách thông thường, mã trông như dưới đây,

public interface Iterable<T> {
    public void forEach(Consumer<? super T> consumer);
}

Do kết quả này, mỗi Lớp triển khai có lỗi biên dịch, do đó, một phương thức mặc định được thêm vào bằng cách triển khai bắt buộc để thực hiện không nên thay đổi.

Giao diện lặp có thể lặp lại với phương thức Mặc định bên dưới,

public interface Iterable<T> {
    public default void forEach(Consumer
                   <? super T> consumer) {
        for (T t : this) {
            consumer.accept(t);
        }
    }
}

Cơ chế tương tự đã được sử dụng để thêm Stream trong Giao diện JDK mà không phá vỡ các Class triển khai.


Phương pháp mặc định và nhiều vấn đề mơ hồ kế thừa

Do Lớp java có thể triển khai nhiều Giao diện và mỗi Giao diện có thể định nghĩa phương thức mặc định có cùng chữ ký phương thức, do đó, các phương thức được kế thừa có thể xung đột với nhau.

Xem xét ví dụ dưới đây,

public interface InterfaceA {  
       default void defaultMethod(){  
           System.out.println("Interface A default method");  
    }  
}
 
public interface InterfaceB {
   default void defaultMethod(){
       System.out.println("Interface B default method");
   }
}
 
public class Impl implements InterfaceA, InterfaceB  {
}

Đoạn mã trên sẽ không biên dịch được với lỗi sau,

java: class Impl kế thừa các mặc định không liên quan cho defaultMethod () từ các loại InterfaceA và InterfaceB

Để sửa lỗi lớp này, chúng tôi cần cung cấp phương thức thực hiện mặc định:

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
    }
}

Hơn nữa, nếu chúng tôi muốn gọi triển khai mặc định được cung cấp bởi bất kỳ Giao diện siêu nào thay vì triển khai riêng của chúng tôi, chúng tôi có thể làm như sau,

public class Impl implements InterfaceA, InterfaceB {
    public void defaultMethod(){
        // existing code here..
        InterfaceA.super.defaultMethod();
    }
}

Chúng tôi có thể chọn bất kỳ triển khai mặc định hoặc cả hai như là một phần của phương pháp mới của chúng tôi.

Điểm quan trọng về các phương thức mặc định của giao diện java:

  1. Các phương thức mặc định của giao diện Java sẽ giúp chúng tôi mở rộng các giao diện mà không sợ phá vỡ các lớp triển khai.
  2. Các phương thức mặc định của giao diện Java đã thu hẹp sự khác biệt giữa các giao diện và các lớp trừu tượng.
  3. Các phương thức mặc định của giao diện Java 8 sẽ giúp chúng ta tránh các lớp tiện ích, chẳng hạn như tất cả các phương thức lớp Bộ sưu tập có thể được cung cấp trong chính các giao diện.
  4. Các phương thức mặc định của giao diện Java sẽ giúp chúng ta loại bỏ các lớp triển khai cơ sở, chúng ta có thể cung cấp cài đặt mặc định và các lớp triển khai có thể chọn lớp nào để ghi đè.
  5. Một trong những lý do chính để giới thiệu các phương thức mặc định trong các giao diện là để tăng cường API Bộ sưu tập trong Java 8 để hỗ trợ các biểu thức lambda.
  6. Nếu bất kỳ lớp nào trong hệ thống phân cấp có một phương thức có cùng chữ ký, thì các phương thức mặc định trở nên không liên quan. Một phương thức mặc định không thể ghi đè một phương thức từ java.lang.Object. Lý do rất đơn giản, đó là vì Object là lớp cơ sở cho tất cả các lớp java. Vì vậy, ngay cả khi chúng ta có các phương thức lớp Object được định nghĩa là các phương thức mặc định trong các giao diện, nó sẽ vô dụng vì phương thức lớp Object sẽ luôn được sử dụng. Đó là lý do để tránh nhầm lẫn, chúng ta không thể có các phương thức mặc định ghi đè các phương thức lớp Object.
  7. Các phương thức mặc định của giao diện Java cũng được gọi là Phương thức bảo vệ hoặc Phương thức mở rộng ảo.

Liên kết tài nguyên:

  1. Giao diện với các phương thức mặc định so với lớp Trừu tượng trong Java 8
  2. Lớp trừu tượng so với giao diện trong kỷ nguyên JDK 8
  3. Giao diện tiến hóa thông qua các phương thức mở rộng ảo

Phương thức tĩnh giao diện Java

Phương thức tĩnh Giao diện Java, ví dụ mã, phương thức tĩnh so với phương thức mặc định

Phương thức tĩnh giao diện Java tương tự như phương thức mặc định ngoại trừ việc chúng ta không thể ghi đè chúng trong các lớp triển khai. Tính năng này giúp chúng tôi tránh các kết quả không mong muốn khi thực hiện kém trong các lớp thực hiện. Hãy xem xét điều này với một ví dụ đơn giản.

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

Bây giờ chúng ta hãy xem một lớp triển khai đang có phương thức isNull () với việc triển khai kém.

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");

        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

Lưu ý rằng isNull (Chuỗi str) là một phương thức lớp đơn giản, nó không ghi đè phương thức giao diện. Ví dụ: nếu chúng ta sẽ thêm chú thích @Override vào phương thức isNull (), nó sẽ dẫn đến lỗi trình biên dịch.

Bây giờ khi chúng tôi sẽ chạy ứng dụng, chúng tôi nhận được đầu ra sau.

Kiểm tra Null giao diện

Impl Null Kiểm tra

Nếu chúng ta thực hiện phương thức giao diện từ tĩnh sang mặc định, chúng ta sẽ nhận được đầu ra sau.

Impl Null Kiểm tra

In MyData ::

Impl Null Kiểm tra

Phương thức tĩnh của giao diện Java chỉ hiển thị với các phương thức giao diện, nếu chúng ta loại bỏ phương thức isNull () khỏi lớp MyDataImpl, chúng ta sẽ không thể sử dụng nó cho đối tượng MyDataImpl. Tuy nhiên, giống như các phương thức tĩnh khác, chúng ta có thể sử dụng các phương thức tĩnh giao diện bằng cách sử dụng tên lớp. Ví dụ: một tuyên bố hợp lệ sẽ là:

boolean result = MyData.isNull("abc");

Điểm quan trọng về phương thức tĩnh giao diện java:

  1. Phương thức tĩnh của giao diện Java là một phần của giao diện, chúng ta không thể sử dụng nó cho các đối tượng lớp thực hiện.
  2. Các phương thức tĩnh của giao diện Java rất tốt để cung cấp các phương thức tiện ích, ví dụ kiểm tra null, sắp xếp bộ sưu tập, v.v.
  3. Phương thức tĩnh giao diện Java giúp chúng tôi cung cấp bảo mật bằng cách không cho phép các lớp thực hiện ghi đè lên chúng.
  4. Chúng ta không thể định nghĩa phương thức tĩnh giao diện cho các phương thức của lớp Object, chúng ta sẽ gặp lỗi trình biên dịch là vì Phương thức tĩnh này không thể ẩn phương thức cá thể khỏi Object. Điều này là do java không được phép trong java, vì Object là lớp cơ sở cho tất cả các lớp và chúng ta không thể có một phương thức tĩnh cấp lớp và một phương thức cá thể khác có cùng chữ ký.
  5. Chúng ta có thể sử dụng các phương thức tĩnh của giao diện java để loại bỏ các lớp tiện ích như Bộ sưu tập và di chuyển tất cả các phương thức tĩnh của nó sang giao diện tương ứng, rất dễ tìm và sử dụng.

Giao diện chức năng Java

Trước khi kết thúc bài viết, tôi muốn giới thiệu ngắn gọn về các giao diện Chức năng. Một giao diện với chính xác một phương thức trừu tượng được gọi là Giao diện chức năng.

Một chú thích mới @FunctionalInterfaceđã được giới thiệu để đánh dấu một giao diện là Giao diện chức năng.@FunctionalInterfacechú thích là một phương tiện để tránh vô tình bổ sung các phương thức trừu tượng trong các giao diện chức năng. Đó là tùy chọn nhưng thực hành tốt để sử dụng nó.

Các giao diện chức năng được chờ đợi từ lâu và tính năng được tìm kiếm nhiều của Java 8 vì nó cho phép chúng tôi sử dụng các biểu thức lambda để khởi tạo chúng. Một gói java.util.feft mới với một loạt các giao diện chức năng được thêm vào để cung cấp các loại mục tiêu cho các biểu thức lambda và các tham chiếu phương thức. Chúng tôi sẽ xem xét các giao diện chức năng và biểu thức lambda trong các bài viết trong tương lai.

Vị trí tài nguyên:

  1. Thay đổi giao diện Java 8 - phương thức tĩnh, phương thức mặc định

8
Tôi chính xác đang tìm kiếm các loại câu trả lời cập nhật. Cảm ơn về sự phản hồi nhanh chóng.
Ravindra babu

41

Tất cả các tuyên bố của bạn là hợp lệ ngoại trừ tuyên bố đầu tiên của bạn (sau khi phát hành Java 8):

Các phương thức của giao diện Java hoàn toàn trừu tượng và không thể có các triển khai

Từ trang tài liệu :

Giao diện là một kiểu tham chiếu, tương tự như một lớp, chỉ có thể chứa các hằng, chữ ký phương thức, phương thức mặc định, phương thức tĩnh và các kiểu lồng nhau

Các thân phương thức chỉ tồn tại cho các phương thức mặc định và các phương thức tĩnh.

Phương thức mặc định:

Một giao diện có thể có các phương thức mặc định , nhưng khác với các phương thức trừu tượng trong các lớp trừu tượng.

Các phương thức mặc định cho phép bạn thêm chức năng mới vào các giao diện của thư viện và đảm bảo khả năng tương thích nhị phân với mã được viết cho các phiên bản cũ hơn của các giao diện đó.

Khi bạn mở rộng giao diện chứa phương thức mặc định, bạn có thể thực hiện các thao tác sau:

  1. Không đề cập đến phương thức mặc định nào cả, điều này cho phép giao diện mở rộng của bạn kế thừa phương thức mặc định.
  2. Redeclare phương thức mặc định, mà làm cho nó abstract.
  3. Xác định lại phương thức mặc định, ghi đè lên nó.

Phương pháp tĩnh:

Ngoài các phương thức mặc định, bạn có thể định nghĩa các phương thức tĩnh trong các giao diện. (Một phương thức tĩnh là một phương thức được liên kết với lớp trong đó nó được định nghĩa chứ không phải với bất kỳ đối tượng nào. Mọi phiên bản của lớp đều chia sẻ các phương thức tĩnh của nó.)

Điều này giúp bạn dễ dàng tổ chức các phương thức trợ giúp trong thư viện của mình;

Mã ví dụ từ trang tài liệu về interfaceviệc có staticdefaultphương pháp.

import java.time.*;

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second);
    LocalDateTime getLocalDateTime();

    static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

Sử dụng các hướng dẫn dưới đây để chọn sử dụng một giao diện hoặc lớp trừu tượng.

Giao diện:

  1. Để xác định hợp đồng (tốt nhất là không trạng thái - ý tôi là không có biến)
  2. Để liên kết các lớp không liên quan với có một khả năng.
  3. Để khai báo các biến không đổi công khai ( trạng thái bất biến )

Lớp trừu tượng:

  1. Chia sẻ mã giữa một số lớp liên quan chặt chẽ. Nó thành lập là một mối quan hệ.

  2. Chia sẻ trạng thái chung giữa các lớp liên quan (trạng thái có thể được sửa đổi trong các lớp cụ thể)

Bài viết liên quan:

Giao diện so với lớp trừu tượng (chung OO)

Implements vs extends: Khi nào nên sử dụng? Có gì khác biệt?

Bằng cách đi qua những ví dụ này, bạn có thể hiểu rằng

Các lớp không liên quan có thể có các khả năng thông qua giao diện nhưng các lớp liên quan thay đổi hành vi thông qua việc mở rộng các lớp cơ sở.


Bạn có ý gì khi nói "hợp đồng không quốc tịch"? Đó là mục 1 về giao diện
Maksim Dmitriev

1
Sự vắng mặt của trạng thái đột biến. Vì giao diện có thể có các hằng số, dữ liệu có thể bị thay đổi không giống như các lớp trừu tượng
Ravindra babu

1
Sửa lỗi trong tuyên bố trên. Trong giao diện, Dữ liệu không thể bị thay đổi không giống như lớp trừu tượng
Ravindra babu

2
đây là câu trả lời tốt nhất Nó không chỉ giải quyết Java8 mà còn giải thích trong những tình huống cụ thể bạn sẽ sử dụng một trong hai tình huống.
Shuklaswag

Khái niệm statelesstrong giao diện là một hit tốt. Giao diện không thể có bất kỳ trạng thái nào (Giao diện có thể có hằng số nhưng chúng là cuối cùng / tĩnh do đó không thay đổi).
Kaihua

22

Lời giải thích của bạn có vẻ tốt, nhưng có thể giống như bạn đang đọc tất cả từ sách giáo khoa? : - /

Điều tôi bận tâm hơn là, ví dụ của bạn vững chắc đến mức nào? Bạn có bận tâm đến hầu hết tất cả sự khác biệt giữa trừu tượng và giao diện không?

Cá nhân, tôi muốn đề xuất liên kết này: http://mindprod.com/jgloss/interfacevsabauge.html#TABLE

cho một danh sách đầy đủ của sự khác biệt ..

Hy vọng nó sẽ giúp bạn và tất cả các độc giả khác trong các cuộc phỏng vấn trong tương lai của họ


1
liên kết được chia sẻ thực sự tuyệt vời
Premraj

Bạn có thể cung cấp triển khai mặc định trong các giao diện java bằng từ khóa mặc định
Ogen

21

Nhiều nhà phát triển cơ sở mắc sai lầm khi nghĩ về giao diện, các lớp trừu tượng và cụ thể là các biến thể nhỏ của cùng một thứ và chọn một trong số chúng hoàn toàn dựa trên cơ sở kỹ thuật: Tôi có cần nhiều kế thừa không? Tôi có cần một số nơi để đặt phương pháp phổ biến? Tôi có cần phải bận tâm với một cái gì đó ngoài một lớp học cụ thể không? Điều này là sai, và ẩn trong những câu hỏi này là vấn đề chính: "Tôi" . Khi bạn tự viết mã cho chính mình, bạn hiếm khi nghĩ đến các nhà phát triển hiện tại hoặc tương lai khác đang làm việc hoặc với mã của bạn.

Các giao diện và các lớp trừu tượng, mặc dù rõ ràng tương tự từ quan điểm kỹ thuật, có ý nghĩa và mục đích hoàn toàn khác nhau.

Tóm lược

  1. Một giao diện xác định một hợp đồng mà một số thực hiện sẽ thực hiện cho bạn .

  2. Một lớp trừu tượng cung cấp một hành vi mặc địnhviệc triển khai của bạn có thể sử dụng lại.

Hai điểm trên đây là những gì tôi đang tìm kiếm khi phỏng vấn, và là một bản tóm tắt đủ nhỏ gọn. Đọc để biết thêm chi tiết.

Tóm tắt thay thế

  1. Giao diện dùng để xác định API công khai
  2. Một lớp trừu tượng là để sử dụng nội bộ và để xác định SPI

Ví dụ như

Nói cách khác: Một lớp cụ thể thực hiện công việc thực tế, theo một cách rất cụ thể. Ví dụ, một nút sử dụng các nút được liên kết đôi để lưu trữ một danh sách các đối tượng, thay vào đó cung cấp phép lặp nhanh, thay đổi tại chỗ và chèn / xóa / thêm, nhưng rất tệ khi truy cập ngẫu nhiên. Hai loại danh sách này được tối ưu hóa cho các trường hợp sử dụng khác nhau và vấn đề là bạn sẽ sử dụng chúng như thế nào. Khi bạn đang cố gắng loại bỏ hiệu suất khỏi danh sách mà bạn đang tương tác nhiều và khi chọn loại danh sách tùy thuộc vào bạn, bạn nên cẩn thận chọn danh sách nào bạn đang bắt đầu.ArrayList sử dụng một vùng bộ nhớ liền kề để lưu trữ một danh sách các đối tượng một cách gọn nhẹ, cho phép truy cập ngẫu nhiên, lặp lại và thay đổi tại chỗ nhanh chóng, nhưng rất tệ khi chèn, xóa và đôi khi thậm chí bổ sung; trong khi đó, mộtLinkedList

Mặt khác, những người dùng cấp cao của danh sách không thực sự quan tâm đến cách nó được thực hiện và họ nên được cách ly khỏi những chi tiết này. Chúng ta hãy tưởng tượng rằng Java đã không làm lộ Listgiao diện, nhưng chỉ có một Listlớp cụ thể thực sự LinkedListlà ngay bây giờ. Tất cả các nhà phát triển Java sẽ điều chỉnh mã của họ để phù hợp với các chi tiết triển khai: tránh truy cập ngẫu nhiên, thêm bộ đệm để tăng tốc truy cập hoặc chỉ tự thực hiện lại ArrayList, mặc dù nó không tương thích với tất cả các mã khác chỉ thực sự hoạt động List. Điều đó thật tồi tệ ... Nhưng bây giờ hãy tưởng tượng rằng các bậc thầy Java thực sự nhận ra rằng một danh sách được liên kết là khủng khiếp đối với hầu hết các trường hợp sử dụng thực tế và đã quyết định chuyển sang một danh sách mảng cho riêng họListlớp có sẵn. Điều này sẽ ảnh hưởng đến hiệu suất của mọi chương trình Java trên thế giới và mọi người sẽ không hài lòng về nó. Và thủ phạm chính là các chi tiết triển khai đã có sẵn và các nhà phát triển cho rằng những chi tiết đó là một hợp đồng vĩnh viễn mà họ có thể dựa vào. Đây là lý do tại sao việc ẩn các chi tiết triển khai và chỉ xác định một hợp đồng trừu tượng là rất quan trọng. Đây là mục đích của giao diện: xác định loại đầu vào mà phương thức chấp nhận và loại đầu ra nào được mong đợi, mà không để lộ tất cả các can đảm sẽ lập trình viên điều chỉnh mã của họ để phù hợp với các chi tiết bên trong có thể thay đổi với bất kỳ cập nhật nào trong tương lai .

Một lớp trừu tượng nằm ở giữa giữa các giao diện và các lớp cụ thể. Nó được cho là để giúp triển khai chia sẻ mã phổ biến hoặc nhàm chán. Ví dụ, AbstractCollectioncung cấp các triển khai cơ bản cho isEmptydựa trên kích thước là 0, containskhi lặp và so sánh, addAllnhư được lặp lại add, v.v. Điều này cho phép triển khai tập trung vào các phần quan trọng phân biệt giữa chúng: cách thực sự lưu trữ và truy xuất dữ liệu.

Một góc nhìn khác: API so với SPI

Các giao diện là các cổng kết nối thấp giữa các phần khác nhau của mã. Chúng cho phép các thư viện tồn tại và phát triển mà không phá vỡ mọi người dùng thư viện khi có gì đó thay đổi bên trong. Nó được gọi là Giao diện lập trình ứng dụng , không phải các lớp lập trình ứng dụng. Ở quy mô nhỏ hơn, họ cũng cho phép nhiều nhà phát triển cộng tác thành công trên các dự án quy mô lớn, bằng cách tách các mô-đun khác nhau thông qua các giao diện được ghi chép tốt.

Các lớp trừu tượng là các trình trợ giúp gắn kết cao sẽ được sử dụng khi triển khai một giao diện, giả sử một số mức độ chi tiết thực hiện. Ngoài ra, các lớp trừu tượng được sử dụng để xác định SPI, Giao diện nhà cung cấp dịch vụ.

Sự khác biệt giữa API và SPI là tinh tế, nhưng quan trọng: đối với API, trọng tâm là người sử dụng nó và đối với SPI, trọng tâm là người thực hiện nó.

Việc thêm các phương thức vào API rất dễ dàng, tất cả người dùng API hiện tại vẫn sẽ biên dịch. Việc thêm các phương thức vào SPI rất khó, vì mọi nhà cung cấp dịch vụ (triển khai cụ thể) sẽ phải thực hiện các phương thức mới. Nếu các giao diện được sử dụng để xác định SPI, nhà cung cấp sẽ phải phát hành phiên bản mới bất cứ khi nào hợp đồng SPI thay đổi. Nếu các lớp trừu tượng được sử dụng thay thế, các phương thức mới có thể được định nghĩa theo các phương thức trừu tượng hiện có hoặc dưới dạng sơ throw not implemented exceptionkhai trống , ít nhất sẽ cho phép một phiên bản cũ hơn của việc triển khai dịch vụ vẫn biên dịch và chạy.

Một lưu ý về Java 8 và các phương thức mặc định

Mặc dù Java 8 đã giới thiệu các phương thức mặc định cho các giao diện, làm cho dòng giữa các giao diện và các lớp trừu tượng trở nên mờ hơn, nhưng điều này không phải để các triển khai có thể sử dụng lại mã, nhưng để dễ dàng thay đổi các giao diện phục vụ cả dưới dạng API và SPI (hoặc được sử dụng sai để xác định SPI thay vì các lớp trừu tượng).

"Sách kiến ​​thức"

Các chi tiết kỹ thuật được cung cấp trong câu trả lời của OP được coi là "kiến thức sách" bởi vì đây thường là cách tiếp cận được sử dụng trong trường học và trong hầu hết các sách công nghệ về ngôn ngữ: điều gì là, không phải cách sử dụng nó trong thực tế, đặc biệt là trong các ứng dụng quy mô lớn .

Đây là một tương tự: giả sử câu hỏi là:

Điều gì là tốt hơn để thuê cho đêm vũ hội, xe hơi hoặc phòng khách sạn?

Câu trả lời kỹ thuật nghe như:

Vâng, trong một chiếc xe bạn có thể làm điều đó sớm hơn, nhưng trong một phòng khách sạn bạn có thể làm điều đó thoải mái hơn. Mặt khác, phòng khách sạn chỉ ở một nơi, trong khi trong xe bạn có thể làm điều đó ở nhiều nơi hơn, như giả sử bạn có thể đến điểm vista để ngắm cảnh đẹp, hoặc trong một nhà hát lái xe, hoặc nhiều nơi khác, hoặc thậm chí ở nhiều nơi. Ngoài ra, phòng khách sạn có vòi sen.

Điều đó hoàn toàn đúng, nhưng hoàn toàn bỏ lỡ những điểm chúng là hai thứ hoàn toàn khác nhau và cả hai có thể được sử dụng cùng một lúc cho các mục đích khác nhau và khía cạnh "thực hiện" không phải là điều quan trọng nhất về một trong hai lựa chọn . Câu trả lời thiếu quan điểm, nó cho thấy một lối suy nghĩ non nớt, trong khi trình bày chính xác "sự thật".


Ý bạn là "khớp nối thấp"?
dùng2418306

@ user2418306 Không, sự gắn kết là một thuật ngữ chung hơn bao gồm khớp nối, mặc dù chúng là từ đồng nghĩa gần gũi và một trong hai thuật ngữ sẽ có hiệu quả.
Sergiu Dumitriu

9

Còn suy nghĩ theo cách sau:

  • Mối quan hệ giữa một lớp và một lớp trừu tượng thuộc loại "is-a"
  • Mối quan hệ giữa một lớp và một giao diện thuộc loại "has-a"

Vì vậy, khi bạn có một lớp Động vật có vú trừu tượng, một lớp con người và giao diện Lái xe, thì bạn có thể nói

  • mỗi con người là một động vật có vú
  • Mỗi người có một Lái xe (hành vi)

Đề nghị của tôi là cụm từ kiến ​​thức cuốn sách chỉ ra rằng anh ấy muốn nghe sự khác biệt về ngữ nghĩa giữa cả hai (như những người khác ở đây đã đề xuất).


9

Giao diện là một "hợp đồng" trong đó lớp thực hiện hợp đồng hứa sẽ thực hiện các phương thức. Một ví dụ khi tôi phải viết một giao diện thay vì một lớp là khi tôi đang nâng cấp một trò chơi từ 2D lên 3D. Tôi đã phải tạo một giao diện để chia sẻ các lớp giữa phiên bản 2D và 3D của trò chơi.

package adventure;
import java.awt.*;
public interface Playable {
    public void playSound(String s);
    public Image loadPicture(String s);    
}

Sau đó, tôi có thể thực hiện các phương thức dựa trên môi trường, trong khi vẫn có thể gọi các phương thức đó từ một đối tượng không biết phiên bản nào của trò chơi đang tải.

public class Adventure extends JFrame implements Playable

public class Dungeon3D extends SimpleApplication implements Playable

public class Main extends SimpleApplication implements AnimEventListener, ActionListener, Playable

Thông thường, trong thế giới game, thế giới có thể là một lớp trừu tượng thực hiện các phương thức trên trò chơi:

public abstract class World...

    public Playable owner;

    public Playable getOwner() {
        return owner;
    }

    public void setOwner(Playable owner) {
        this.owner = owner;
    }

6

Các lớp trừu tượng không phải là sự trừu tượng thuần túy bcz bộ sưu tập cụ thể của nó (các phương thức đã thực hiện) cũng như các phương thức chưa được thực hiện. Nhưng Giao diện là bcz trừu tượng thuần túy, chỉ có các phương thức chưa được thực hiện chứ không phải phương pháp cụ thể.

Tại sao lớp trừu tượng?

  1. Nếu người dùng muốn viết chức năng chung cho tất cả các đối tượng.
  2. Các lớp trừu tượng là lựa chọn tốt nhất để triển khai lại trong tương lai để thêm nhiều chức năng hơn mà không ảnh hưởng đến người dùng cuối.

Tại sao giao diện?

  1. Nếu người dùng muốn viết các chức năng khác nhau sẽ là chức năng khác nhau trên các đối tượng.
  2. Các giao diện là sự lựa chọn tốt nhất mà nếu không cần phải sửa đổi các yêu cầu một khi giao diện đã được xuất bản.

5

Một giao diện giống như một bộ gen được công khai ghi nhận có một số loại có hiệu lực: Một DNA thử nghiệm sẽ cho tôi biết liệu tôi đã có chúng - và nếu tôi làm, tôi công khai có thể làm cho nó biết rằng tôi là một "tàu sân "Và một phần trong hành vi hoặc trạng thái của tôi sẽ phù hợp với họ. (Nhưng tất nhiên, tôi có thể có nhiều gen khác cung cấp các tính trạng ngoài phạm vi này.)

Một lớp trừu tượng giống như tổ tiên đã chết của một loài đơn tính (*): Cô ấy không thể được đưa vào cuộc sống nhưng một hậu duệ sống (tức là không trừu tượng ) thừa hưởng tất cả các gen của cô ấy.

(*) Để kéo dài phép ẩn dụ này, giả sử tất cả các thành viên của loài sống cùng tuổi. Điều này có nghĩa là tất cả tổ tiên của một tổ tiên đã chết cũng phải chết - và tương tự, tất cả các hậu duệ của một tổ tiên còn sống phải còn sống.


4

Tôi thực hiện các cuộc phỏng vấn cho công việc và tôi sẽ xem xét câu trả lời của bạn không thuận lợi (xin lỗi nhưng tôi rất trung thực). Nghe có vẻ như bạn đã đọc về sự khác biệt và sửa đổi một câu trả lời nhưng có lẽ bạn chưa bao giờ sử dụng nó trong thực tế.

Một lời giải thích tốt về lý do tại sao bạn sẽ sử dụng từng có thể tốt hơn nhiều so với việc có một lời giải thích chính xác về sự khác biệt. Nhà tuyển dụng ultimatley muốn các lập trình viên làm những việc không biết họ có thể khó thể hiện trong một cuộc phỏng vấn. Câu trả lời bạn đưa ra sẽ tốt nếu áp dụng cho một công việc dựa trên tài liệu hoặc kỹ thuật nhưng không phải là vai trò của nhà phát triển.

Tốt nhất của may mắn với các cuộc phỏng vấn trong tương lai.

Ngoài ra câu trả lời của tôi cho câu hỏi này là về kỹ thuật phỏng vấn hơn là các tài liệu kỹ thuật mà bạn đã cung cấp. Có lẽ xem xét đọc về nó. https://workplace.stackexchange.com/ có thể là một nơi tuyệt vời cho loại điều này.


1
Bạn có thể cho tôi biết làm thế nào bạn đã trả lời nó? Có thể nó có thể giúp tôi.
code_fish

cung cấp cho bạn câu trả lời cung cấp ít hơn rất nhiều sau đó giúp bạn giải quyết nó, về cơ bản đưa ra một ví dụ thực tế về thời điểm bạn sẽ sử dụng từng cái và giải thích lý do tại sao mỗi cái phù hợp với các nhiệm vụ khác nhau.
Adrian

4

Bạn chọn Giao diện trong Java để tránh Sự cố Kim cương trong nhiều kế thừa .

Nếu bạn muốn tất cả các phương thức của bạn được thực hiện bởi khách hàng của bạn, bạn đi cho giao diện. Nó có nghĩa là bạn thiết kế toàn bộ ứng dụng một cách trừu tượng.

Bạn chọn lớp trừu tượng nếu bạn đã biết điểm chung. Ví dụ: Lấy một lớp trừu tượng Car. Ở cấp độ cao hơn bạn thực hiện các phương pháp xe phổ biến như thế nào calculateRPM(). Đó là một phương pháp phổ biến và bạn để khách hàng thực hiện hành vi của chính mình như
calculateMaxSpeed()v.v. Có lẽ bạn sẽ giải thích bằng cách đưa ra một vài ví dụ thời gian thực mà bạn gặp phải trong công việc hàng ngày.



3

Sự khác biệt chính mà tôi đã quan sát là lớp trừu tượng cung cấp cho chúng ta một số hành vi phổ biến đã được triển khai và các lớp con chỉ cần thực hiện chức năng cụ thể tương ứng với chúng. trong đó đối với một giao diện sẽ chỉ xác định những nhiệm vụ nào cần được thực hiện và không có triển khai nào được đưa ra bởi giao diện. Tôi có thể nói nó chỉ định hợp đồng giữa chính nó và các lớp được thực hiện.


3

Ngay cả tôi đã phải đối mặt với cùng một câu hỏi trong nhiều cuộc phỏng vấn và tin tôi rằng nó làm cho thời gian của bạn trở nên khốn khổ để thuyết phục người phỏng vấn. Nếu tôi vốn có tất cả các câu trả lời từ phía trên thì tôi cần thêm một điểm chính để làm cho nó thuyết phục hơn và sử dụng OO một cách tốt nhất

Trong trường hợp bạn không lập kế hoạch cho bất kỳ sửa đổi nào trong các quy tắc , để lớp con được theo dõi, trong một tương lai dài, hãy chuyển sang giao diện, vì bạn sẽ không thể sửa đổi trong đó và nếu bạn làm như vậy, bạn cần phải đi đến thay đổi trong tất cả các lớp con khác, trong khi đó, nếu bạn nghĩ, bạn muốn sử dụng lại chức năng, đặt một số quy tắc và cũng mở nó để sửa đổi , hãy chuyển sang lớp Trừu tượng.

Nghĩ theo cách này, bạn đã sử dụng một dịch vụ tiêu thụ hoặc bạn đã cung cấp một số mã cho thế giới và Bạn có cơ hội sửa đổi một cái gì đó, giả sử kiểm tra bảo mật Và nếu tôi là người tiêu dùng mã và Một buổi sáng sau khi cập nhật, tôi tìm tất cả các dấu đọc trong Eclipse của tôi, toàn bộ ứng dụng bị hỏng. Vì vậy, để ngăn chặn những cơn ác mộng như vậy, hãy sử dụng Tóm tắt trên Giao diện

Tôi nghĩ rằng điều này có thể thuyết phục Người phỏng vấn ở một mức độ nào đó ... Cuộc phỏng vấn hạnh phúc phía trước.


2

Khi tôi đang cố gắng chia sẻ hành vi giữa 2 lớp có liên quan chặt chẽ với nhau, tôi tạo một lớp trừu tượng chứa hành vi chung và đóng vai trò là cha mẹ cho cả hai lớp.

Khi tôi đang cố gắng xác định Loại, một danh sách các phương thức mà người dùng đối tượng của tôi có thể gọi một cách đáng tin cậy, sau đó tôi tạo một giao diện.

Ví dụ, tôi sẽ không bao giờ tạo một lớp trừu tượng với 1 lớp con cụ thể vì các lớp trừu tượng là về hành vi chia sẻ. Nhưng tôi rất có thể tạo ra một giao diện chỉ với một lần thực hiện. Người sử dụng mã của tôi sẽ không biết rằng chỉ có một triển khai. Thật vậy, trong một bản phát hành trong tương lai có thể có một số triển khai, tất cả đều là các lớp con của một số lớp trừu tượng mới thậm chí không tồn tại khi tôi tạo giao diện.

Điều đó có vẻ cũng hơi quá Nếu người phỏng vấn (hoặc OP) thực sự muốn có nhiều kinh nghiệm cá nhân của tôi về điều đó, tôi đã sẵn sàng với những giai thoại về giao diện đã phát triển không cần thiết và ngược lại.

Một điều nữa. Java 8 bây giờ cho phép bạn đặt mã mặc định vào một giao diện, làm mờ thêm ranh giới giữa các giao diện và các lớp trừu tượng. Nhưng từ những gì tôi đã thấy, tính năng đó được sử dụng quá mức ngay cả bởi các nhà sản xuất thư viện lõi Java. Tính năng đó đã được thêm vào, và đúng như vậy, để có thể mở rộng giao diện mà không tạo ra tính không tương thích nhị phân. Nhưng nếu bạn đang tạo Loại hoàn toàn mới bằng cách xác định giao diện, thì giao diện đó phải CHỈ LÀ một giao diện. Nếu bạn cũng muốn cung cấp mã chung, thì bằng mọi cách hãy tạo một lớp trợ giúp (trừu tượng hoặc cụ thể). Đừng làm lộn xộn giao diện của bạn ngay từ đầu với chức năng mà bạn có thể muốn thay đổi.


2

Sự khác biệt cơ bản giữa giao diện và lớp trừu tượng là, giao diện hỗ trợ nhiều kế thừa nhưng lớp trừu tượng thì không.

Trong lớp trừu tượng, bạn cũng có thể cung cấp tất cả các phương thức trừu tượng như giao diện.

Tại sao lớp trừu tượng là bắt buộc?

Trong một số tình huống, trong khi xử lý yêu cầu người dùng, lớp trừu tượng không biết ý định của người dùng. Trong kịch bản đó, chúng tôi sẽ định nghĩa một phương thức trừu tượng trong lớp và yêu cầu người dùng mở rộng lớp này, vui lòng cung cấp ý định của bạn trong phương thức trừu tượng. Trong trường hợp này, các lớp trừu tượng rất hữu ích

Tại sao giao diện là bắt buộc?

Hãy nói rằng, tôi có một công việc mà tôi không có kinh nghiệm trong lĩnh vực đó. Ví dụ, nếu bạn muốn xây dựng một tòa nhà hoặc đập, vậy bạn sẽ làm gì trong kịch bản đó?

  1. bạn sẽ xác định được yêu cầu của bạn là gì và lập hợp đồng với yêu cầu đó.
  2. Sau đó gọi Đấu thầu để xây dựng dự án của bạn
  3. Ai đã từng xây dựng dự án, điều đó sẽ đáp ứng yêu cầu của bạn. Nhưng logic xây dựng là khác nhau từ một nhà cung cấp với nhà cung cấp khác.

Ở đây tôi không bận tâm về logic họ đã xây dựng như thế nào. Đối tượng cuối cùng có thỏa mãn yêu cầu của tôi hay không, đó chỉ là điểm chính của tôi.

Ở đây các yêu cầu của bạn được gọi là giao diện và hàm tạo được gọi là người triển khai.


2

Trong một vài từ, tôi sẽ trả lời theo cách này:

  • kế thừa thông qua hệ thống phân cấp lớp hàm ý kế thừa nhà nước ;
  • trong khi kế thừa thông qua các giao diện là viết tắt của kế thừa hành vi ;

Các lớp trừu tượng có thể được coi là một cái gì đó giữa hai trường hợp này (nó giới thiệu một số trạng thái nhưng cũng bắt buộc bạn phải xác định một hành vi), một lớp trừu tượng hoàn toàn là một giao diện (đây là sự phát triển thêm của các lớp chỉ bao gồm các phương thức ảo trong C ++ như theo như tôi biết về cú pháp của nó).

Tất nhiên, bắt đầu từ Java 8 mọi thứ đã thay đổi một chút, nhưng ý tưởng vẫn như vậy.

Tôi đoán điều này là khá đủ cho một cuộc phỏng vấn Java điển hình, nếu bạn không được phỏng vấn với một nhóm biên dịch.


1

Theo những gì tôi hiểu, một Giao diện, bao gồm các biến và phương thức cuối cùng không có triển khai, được một lớp triển khai để có được một nhóm các phương thức hoặc phương thức có liên quan với nhau. Mặt khác, một lớp trừu tượng, có thể chứa các biến và phương thức không phải là cuối cùng với các triển khai, thường được sử dụng như một hướng dẫn hoặc như một siêu lớp mà tất cả các lớp liên quan hoặc tương tự thừa hưởng từ đó. Nói cách khác, một lớp trừu tượng chứa tất cả các phương thức / biến được chia sẻ bởi tất cả các lớp con của nó.


1

Trong lớp trừu tượng, bạn có thể viết triển khai mặc định của các phương thức! Nhưng trong Giao diện bạn không thể. Về cơ bản, trong giao diện tồn tại các phương thức ảo thuần túy phải được thực hiện bởi lớp thực hiện giao diện.


1

Đúng, câu trả lời của bạn là đúng về mặt kỹ thuật nhưng bạn đã sai ở chỗ không cho họ thấy bạn hiểu những mặt trái và mặt trái của việc chọn cái này hơn cái kia. Ngoài ra, họ có thể lo ngại / bối rối về khả năng tương thích của cơ sở mã của họ với các bản nâng cấp trong tương lai. Loại phản hồi này có thể có ích (ngoài những gì bạn nói):

"Việc chọn một lớp trừu tượng trên một lớp giao diện phụ thuộc vào những gì chúng ta dự đoán tương lai của mã sẽ là gì.

Các lớp trừu tượng cho phép khả năng tương thích tốt hơn vì bạn có thể tiếp tục thêm hành vi vào Lớp trừu tượng trong tương lai mà không phá vỡ mã hiện tại của bạn -> điều này là không thể với Lớp giao diện.

Mặt khác, các lớp giao diện linh hoạt hơn các lớp trừu tượng. Điều này là do họ có thể thực hiện nhiều giao diện . Vấn đề là Java không có nhiều kế thừa nên việc sử dụng các lớp trừu tượng sẽ không cho phép bạn sử dụng bất kỳ cấu trúc phân cấp lớp nào khác ...

Vì vậy, cuối cùng, một quy tắc chung tốt là: Thích sử dụng các lớp giao diện khi không có triển khai mặc định / mặc định trong cơ sở mã của bạn. Và, sử dụng Lớp trừu tượng để duy trì khả năng tương thích nếu bạn biết bạn sẽ cập nhật lớp của mình trong tương lai. "

Chúc may mắn trong cuộc phỏng vấn tiếp theo của bạn!


1

Tôi sẽ cố gắng trả lời bằng cách sử dụng kịch bản thực tế để thể hiện sự khác biệt giữa hai người.

Các giao diện đi kèm với tải trọng bằng không, nghĩa là không có trạng thái nào phải được duy trì và do đó, là lựa chọn tốt hơn để chỉ liên kết hợp đồng (khả năng) với một lớp.

Ví dụ: giả sử tôi có một lớp Nhiệm vụ thực hiện một số hành động, bây giờ để thực thi một tác vụ trong luồng riêng biệt, tôi thực sự không cần phải mở rộng lớp Thread thay vì lựa chọn tốt hơn là thực hiện giao diện Runnable (nghĩa là thực hiện phương thức run () của nó ) và sau đó chuyển đối tượng của lớp Nhiệm vụ này sang một đối tượng Thread và gọi phương thức start () của nó.

Bây giờ bạn có thể hỏi điều gì nếu Runnable là một lớp trừu tượng?

Vâng về mặt kỹ thuật là có thể nhưng thiết kế khôn ngoan đó sẽ là một lý do lựa chọn kém là:

  • Runnable không có trạng thái liên quan đến nó và nó cũng không cung cấp bất kỳ triển khai mặc định nào cho phương thức run ()
  • Nhiệm vụ sẽ phải mở rộng nó do đó nó không thể mở rộng bất kỳ lớp nào khác
  • Nhiệm vụ không có gì để cung cấp như chuyên môn hóa cho lớp Runnable, tất cả những gì nó cần là ghi đè phương thức run ()

Nói cách khác, lớp Nhiệm vụ cần một khả năng để chạy trong một luồng mà nó đạt được bằng cách triển khai các câu giao diện Runnable mở rộng lớp Thread sẽ biến nó thành một luồng.

Đơn giản chỉ cần đặt giao diện cho chúng tôi để xác định một khả năng (hợp đồng), trong khi sử dụng một lớp trừu tượng để xác định triển khai khung (chung / một phần) của nó.

Disclaimer: ví dụ ngớ ngẩn sau, cố gắng không phán xét :-P

interface Forgiver {
    void forgive();
}

abstract class GodLike implements Forgiver {
    abstract void forget();
    final void forgive() {
        forget();
    }
}

Bây giờ bạn đã được chọn là GodLike nhưng bạn có thể chọn chỉ là Người tha thứ (không phải là GodLike) và làm:

class HumanLike implements Forgiver {
    void forgive() {
       // forgive but remember    
    }
}

Hoặc bạn có thể chọn trở thành GodLike và làm:

class AngelLike extends GodLike {
    void forget() {
       // forget to forgive     
    }
}

PS với giao diện java 8 cũng có thể có các phương thức tĩnh (triển khai quá mức) và do đó giao diện b / w và lớp trừu tượng thậm chí còn bị thu hẹp hơn.


1

Hầu như mọi thứ dường như đã được đề cập ở đây rồi .. Thêm một điểm nữa vào việc triển khai thực tế của abstractlớp:

abstracttừ khóa cũng được sử dụng chỉ ngăn không cho một lớp được khởi tạo. Nếu bạn có một lớp cụ thể mà bạn không muốn được khởi tạo - Hãy tạo nó abstract.


1

hmm bây giờ mọi người đang tiếp cận thực tế đói, bạn hoàn toàn đúng nhưng hầu hết người phỏng vấn trông theo yêu cầu hiện tại của họ và muốn một cách tiếp cận thực tế.

Sau khi kết thúc câu trả lời của bạn, bạn nên nhảy vào ví dụ:

Trừu tượng:

ví dụ chúng ta có chức năng lương có một số thông số chung cho tất cả nhân viên. sau đó chúng ta có thể có một lớp trừu tượng được gọi là CTC với thân phương thức được xác định một phần và nó sẽ được mở rộng bởi tất cả các loại nhân viên và được thiết kế lại theo mỗi phần bổ sung của họ. Đối với functonality phổ biến.

public abstract class CTC {

    public int salary(int hra, int da, int extra)
    {
        int total;
        total = hra+da+extra;
        //incentive for specific performing employee
        //total = hra+da+extra+incentive;
        return total;
    }
}

class Manger extends CTC
{
}


class CEO extends CTC
{
}

class Developer extends CTC
{   
}

Giao diện

Giao diện trong java cho phép có chức năng intercae mà không cần mở rộng giao diện đó và bạn phải rõ ràng với việc triển khai chữ ký của chức năng mà bạn muốn giới thiệu trong ứng dụng của mình. nó sẽ buộc bạn phải có definiton. Đối với chức năng khác nhau.

public interface EmployeType {

    public String typeOfEmployee();
}

class ContarctOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "contract";
    }

}

class PermanentOne implements EmployeType
{

    @Override
    public String typeOfEmployee() {
        return "permanent";
    }

}

bạn cũng có thể có hoạt động bắt buộc như vậy với lớp trừu tượng bằng cách định nghĩa methgos là một lớp trừu tượng, bây giờ một lớp tha mở rộng lớp trừu tượng làm lại lớp trừu tượng cho đến khi nó ghi đè hàm trừu tượng đó.


1

Từ những gì tôi hiểu và cách tôi tiếp cận,

Giao diện giống như một đặc tả / hợp đồng, bất kỳ lớp nào thực hiện một lớp giao diện đều phải thực hiện tất cả các phương thức được định nghĩa trong lớp trừu tượng (ngoại trừ các phương thức mặc định (được giới thiệu trong Java 8))

Trong khi tôi định nghĩa một bản tóm tắt lớp khi tôi biết việc triển khai cần thiết cho một số phương thức của lớp và một số phương thức tôi vẫn không biết điều gì sẽ được thực hiện (chúng ta có thể biết chữ ký hàm nhưng không phải là triển khai). Tôi làm điều này để sau này trong phần phát triển khi tôi biết các phương thức này được triển khai như thế nào, tôi có thể mở rộng lớp trừu tượng này và thực hiện các phương thức này.

Lưu ý: Bạn không thể có thân hàm trong các phương thức giao diện trừ khi phương thức là tĩnh hoặc mặc định.


0

Tôi tin rằng những gì người phỏng vấn đang cố gắng nhận được có lẽ là sự khác biệt giữa giao diện và cách thực hiện.

Giao diện - không phải là giao diện Java, mà là "giao diện" theo nghĩa chung hơn - đối với một mô-đun mã, về cơ bản, là hợp đồng được thực hiện với mã máy khách sử dụng giao diện.

Việc thực hiện một mô-đun mã là mã nội bộ làm cho mô-đun hoạt động. Thường thì bạn có thể thực hiện một giao diện cụ thể theo nhiều cách khác nhau và thậm chí thay đổi việc thực hiện mà không cần mã máy khách thậm chí còn nhận thức được sự thay đổi.

Một giao diện Java chỉ nên được sử dụng như một giao diện theo nghĩa chung ở trên, để xác định cách lớp hoạt động vì lợi ích của mã máy khách khi sử dụng lớp mà không chỉ định bất kỳ triển khai nào. Do đó, một giao diện bao gồm chữ ký phương thức - tên, kiểu trả về và danh sách đối số - cho các phương thức dự kiến ​​sẽ được gọi bằng mã máy khách và về nguyên tắc nên có nhiều Javadoc cho mỗi phương thức mô tả phương thức đó làm gì. Lý do hấp dẫn nhất để sử dụng một giao diện là nếu bạn dự định có nhiều triển khai giao diện khác nhau, có thể chọn một triển khai tùy thuộc vào cấu hình triển khai.

Ngược lại, một lớp trừu tượng Java cung cấp một phần triển khai của lớp, thay vì có mục đích chính là chỉ định một giao diện. Nó nên được sử dụng khi nhiều lớp chia sẻ mã, nhưng khi các lớp con cũng được dự kiến ​​sẽ cung cấp một phần của việc thực hiện. Điều này cho phép mã được chia sẻ chỉ xuất hiện ở một nơi - lớp trừu tượng - trong khi làm rõ rằng các phần của việc triển khai không có trong lớp trừu tượng và dự kiến ​​sẽ được cung cấp bởi các lớp con.


0

câu trả lời của bạn là đúng nhưng người phỏng vấn cần bạn phân biệt theo quan điểm công nghệ phần mềm chứ không phải theo các chi tiết của Java.

Từ ngữ đơn giản:

Giao diện giống như giao diện của cửa hàng, bất cứ thứ gì được hiển thị trên cửa hàng đều phải có trong cửa hàng, vì vậy mọi phương thức trong Giao diện phải được thực hiện trong lớp cụ thể. Bây giờ sẽ ra sao nếu một số lớp chia sẻ một số phương thức chính xác và khác nhau ở những lớp khác. Giả sử Giao diện nói về một cửa hàng chứa hai thứ và giả sử chúng ta có hai cửa hàng đều chứa dụng cụ thể thao nhưng một cái có thêm quần áo và cái còn lại có thêm giày. Vì vậy, những gì bạn làm là tạo một lớp trừu tượng cho Thể thao thực hiện phương thức Thể thao và không thực hiện phương thức khác. Lớp trừu tượng ở đây có nghĩa là cửa hàng này không tồn tại nhưng nó là cơ sở cho các lớp / cửa hàng khác. Bằng cách này, bạn đang tổ chức mã, tránh các lỗi sao chép mã, thống nhất mã và đảm bảo khả năng sử dụng lại của một số lớp khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.