2015-05-26 19 views
7

Tôi biết đây là một câu hỏi rất đơn giản, nhưng tôi đã làm việc bằng Python trong một thời gian dài và bây giờ tôi phải quay trở lại Java, dường như có vấn đề thay đổi chip và gói đầu của tôi xung quanh tính đa hình cơ bản của Java.Xác định chữ ký của phương thức bằng cách sử dụng các lớp kế thừa trong các phương thức trừu tượng của Java

Có thể ghi đè (thực hiện, chính xác) phương thức 'abstract' trong lớp bằng Java sử dụng một trong các lớp được thừa hưởng làm đối số không?

Hãy để tôi giải thích với một ví dụ rất đơn giản (sau khi "gần như chính thức"example với hình dạng)

class Shape {} 
class Circle extends Shape {} 
class Triangle extends Shape {} 

abstract class ShapeDrawer { 
    abstract void draw(Shape s); 
}      
class CircleDrawer extends ShapeDrawer { 
    void draw(Circle c){ 
     System.out.println("Drawing circle"); 
    } 
} 

Có cách nào của việc có Java xác định các phương pháp draw trong lớp CircleDrawer như việc thực hiện của trừu tượng draw trong ShapeDrawer? (Lớp Circle kéo dài từ Shape sau khi tất cả)

Nếu không đặt: Những gì tôi muốn là các phương pháp draw của lớp CircleDrawer chỉ chấp nhận trường hợp của loại Circle, nhưng cùng một lúc, tôi muốn nói trình biên dịch Java rằng void draw(Circle c) thực sự là việc thực hiện phương thức trừu tượng abstract void draw(Shape s) nằm trong lớp cha của nó.

Cảm ơn bạn trước.

+1

Tôi có thể chỉ đọc sai, nhưng nếu đó không phải là điều bạn muốn, bạn có thể cung cấp ví dụ về những gì bạn muốn? – Aify

+0

@Aify, tôi đã chỉnh sửa câu hỏi mô tả những gì tôi muốn đạt được. Hy vọng là rõ ràng hơn bây giờ? Hãy cho tôi biết nếu nó không phải là. – BorrajaX

+1

Đừng quên tắt nguồn trước khi bạn vứt con chip đó ra. – markspace

Trả lời

7

Bạn có thể giải quyết vấn đề của bạn bằng phương tiện của Generics:

public abstract class ShapeDrawer<T extends Shape> { 
    public abstract void draw(T shape); 
} 

public class CircleDrawer extends ShapeDrawer<Circle> { 
    public void draw(Circle circle) { ... } 
} 
1

Không, Java phương pháp chữ ký phải phù hợp chính xác, bạn không thể sử dụng phân nhóm, hoặc bạn sẽ quá tải một phương pháp thay vì trọng nó.

Bạn có thể trả lại một loại phụ, nhưng đó là điều đó và các loại trả lại không phải là một phần của chữ ký phương thức.

4

Bạn không thể và có một lý do rất tốt khiến bạn không thể. Hãy tuyên bố này

public abstract class ShapeDrawer { 
    public abstract void draw(Shape s); 
} 

Bây giờ mất một mã mà nhận được một ShapeDrawer và cố gắng sử dụng nó:

public void foo(ShapeDrawer drawer, Shape shape) { 
    drawer.draw(shape); 
} 

Mã này nên làm việc vì việc kê khai của ShapeDrawer lời hứa rằng bất cứ ai thực hiện nó sẽ cung cấp một phương pháp gọi là draw() và phương pháp đó có thể xử lý bất kỳ Shape nào.

Nhưng nếu bạn được phép làm điều này:

public class CircleDrawer extends ShapeDrawer { 
    public void draw(Circle c) {...} 
} 

Điều đó sẽ không còn giữ đúng, bạn CircleDrawer sẽ không thể đáp ứng lời hứa rằng nó có thể đối phó với bất kỳ Shape.


Tuy nhiên tưởng tượng tuyên bố này:

public abstract class ShapeCreator { 
    public abstract Shape create(); 
} 

public class CircleCreator extends ShapeCreator { 
    public Circle create() {...} 
} 

Sẽ làm việc này?Có, nó sẽ (miễn là bạn sử dụng Java 5 hoặc mới hơn), bởi vì không giống như khai báo đầu tiên, những lời hứa ShapeCreator là nó sẽ có một phương pháp gọi là create(), sẽ trả về Shape. Vì Circle là một Shape, một lớp con của ShapeCreator có thể quyết định chỉ trả lại Circle giây, không có lời hứa nào bị hỏng.


Vậy làm cách nào để bạn đạt được những gì bạn muốn? Xem loonytune's answer :)

1

Không phải về mặt kỹ thuật, nhưng bạn có thể thực hiện hack xung quanh nó cho chức năng bạn đã chỉ định.

public abstract ShapeDrawer { 
    public abstract void draw(Shape s); 
}      
public CircleDrawer extends ShapeDrawer { 
    public void draw(Shape s){ 
     if (s instanceof Circle) { 
      System.out.println("Drawing circle"); 
     } 
    } 
} 
+0

Điều này là OK, nhưng về cơ bản giống như ví dụ về generics đã được đưa ra. Tôi thích generics hơn nếu tôi sẽ làm một cái gì đó như thế này. – markspace

+0

Nó gần, nhưng không đủ gần để nói nó giống nhau. Bằng cách làm theo cách này, bạn vẫn có thể truyền qua các hình dạng khác về mặt kỹ thuật và thực hiện các loại xử lý khác - ví dụ: in "đây không phải là một vòng tròn", hoặc một cái gì đó tương tự. Nhưng mua bằng Generics, bạn thậm chí không được phép gọi nó bằng thứ gì đó không phải là một Vòng tròn. – Aify

+0

Nội bộ, tất cả các generics không kiểm tra loại cá thể tương tự như những gì bạn đã làm. Tuy nhiên, trình biên dịch nên * ngăn cản * bạn truyền bất cứ thứ gì không phải là một Vòng tròn, và trong hầu hết các trường hợp đó là một chiến thắng lớn. – markspace

Các vấn đề liên quan