2011-09-05 42 views
47

Tôi muốn biết là có bất kỳ cách nào mà tôi có thể làm cho nó bắt buộc đối với các lớp thực hiện để khai báo các đối tượng xử lý/nguyên thủy như họ làm với phương pháp. ví dụ:Thuộc tính/biến thành viên trong giao diện?

public interface Rectangle {  
    int height = 0; 
    int width = 0; 

    public int getHeight(); 
    public int getWidth(); 
    public void setHeight(int height); 
    public void setWidth(int width);     
} 


public class Tile implements Rectangle{ 
    @Override 
    public int getHeight() { 
     return 0; 
    } 

    @Override 
    public int getWidth() { 
     return 0; 
    } 

    @Override 
    public void setHeight(int height) { 
    } 

    @Override 
    public void setWidth(int width) { 
    } 

} 

Trong phương pháp trên, chúng ta có thể bắt buộc lớp Gạch để khai báo thuộc tính chiều cao và chiều rộng bằng cách sử dụng giao diện? Đối với một số lý do tôi muốn làm điều đó với giao diện duy nhất!

Tôi bước đầu nghĩ đến việc sử dụng nó với kế thừa. Nhưng vấn đề là tôi phải đối phó với 3 lớp.

  1. Rectangle
  2. Ngói
  3. JLabel.!

 

class Tile extends JLabel implements Rectangle {} 

sẽ làm việc.!

nhưng

class Tile extends JLabel extends Rectangle {} 

woud không.!

+4

Giao diện của bạn không chính xác. Nó không thể chứa các thuộc tính. Có lẽ bạn muốn sử dụng một lớp trừu tượng? – pvoosten

+5

@lbp Điều đó [sẽ thực sự biên dịch] (http://www.coderanch.com/t/178630/java-SCJA/certification/Instance-variables-interface) ;-) Nó chỉ là ... không phải là "mong đợi" hành vi. Trình biên dịch giả định/áp dụng một sửa đổi 'cuối cùng tĩnh'. –

+0

Bạn có thể muốn sử dụng Chiều cao thay vì Hieght và Hight. Hight là phân từ quá khứ của highten, hihten, để gọi, được gọi.;) –

Trả lời

52

Điểm của giao diện là chỉ định API công khai. Giao diện không có trạng thái. Bất kỳ biến nào mà bạn tạo đều thực sự là hằng số (vì vậy hãy cẩn thận khi tạo các đối tượng có thể thay đổi trong giao diện).

Về cơ bản một giao diện cho biết đây là tất cả các phương pháp mà một lớp thực hiện nó phải hỗ trợ. Nó có lẽ sẽ tốt hơn nếu những người sáng tạo của Java không cho phép các hằng số trong các giao diện, nhưng đã quá muộn để loại bỏ nó ngay bây giờ (và có một số trường hợp các hằng số là hợp lý trong các giao diện).

Vì bạn chỉ xác định những phương thức nào cần được triển khai nên không có ý tưởng về trạng thái (không có biến mẫu). Nếu bạn muốn yêu cầu mỗi lớp có một biến nhất định, bạn cần phải sử dụng một lớp trừu tượng.

Cuối cùng, bạn nên nói chung, không sử dụng các biến công cộng, vì vậy ý ​​tưởng đưa các biến vào giao diện là một ý tưởng tồi để bắt đầu.

Câu trả lời ngắn - bạn không thể làm những gì bạn muốn bởi vì nó "sai" trong Java.

Edit:

class Tile 
    implements Rectangle 
{ 
    private int height; 
    private int width; 

    @Override 
    public int getHeight() { 
     return height; 
    } 

    @Override 
    public int getWidth() { 
     return width; 
    } 

    @Override 
    public void setHeight(int h) { 
     height = h; 
    } 

    @Override 
    public void setWidth(int w) { 
     width = w; 
    } 
} 

một phiên bản thay thế sẽ là:

abstract class AbstractRectangle 
    implements Rectangle 
{ 
    private int height; 
    private int width; 

    @Override 
    public int getHeight() { 
     return height; 
    } 

    @Override 
    public int getWidth() { 
     return width; 
    } 

    @Override 
    public void setHeight(int h) { 
     height = h; 
    } 

    @Override 
    public void setWidth(int w) { 
     width = w; 
    } 
} 

class Tile 
    extends AbstractRectangle 
{ 
} 
+0

kk! vì vậy làm thế nào để tôi đi về nó. ?? (Tôi đã chỉnh sửa câu hỏi, xin kiểm tra)! – Shrey

+0

Điều này sẽ giúp tôi giả sử ..! thnxx :) – Shrey

+0

Nhưng điều đó để lại vấn đề mà bạn không thể gây rối với chiều cao trong việc thực hiện cụ thể. Vì vậy, bạn biết bạn cần một chiều cao, bạn biết bạn cần để có thể trả lại chiều cao, nhưng bạn không thể để nó cho mỗi thực hiện để tính toán chiều cao (mà tôi nghĩ rằng đánh bại mục đích). Tất nhiên bạn có thể khai báo 'getHeight' trừu tượng và không khai báo chiều cao nào cả, nhưng sau đó bạn phải lặp lại mã trả về mỗi lần, chỉ để bạn có thể giữ biến riêng tư. –

6

Giao diện không thể yêu cầu các biến mẫu được xác định - chỉ các phương thức.

(Variables can be defined in interfaces, nhưng họ không hành xử như có thể mong đợi:. Họ được đối xử như final static)

Chúc mừng mã hóa.

7

Bạn chỉ có thể thực hiện việc này với lớp trừu tượng, không phải bằng giao diện.

Khai báo Rectangle làm abstract class thay vì interface và khai báo các phương pháp phải được thực hiện bởi lớp con là public abstract. Sau đó, lớp Tile kéo dài lớp Rectangle và phải triển khai phương pháp trừu tượng từ Rectangle.

+0

Tôi bước đầu nghĩ đến việc sử dụng nó với sự kế thừa. Nhưng vấn đề là tôi phải đối phó với 3 lớp. 1. Hình chữ nhật 2. Ngói 3. JLabel.! Lớp Tile mở rộng JLabel thực hiện Rectangle {} sẽ hoạt động.! nhưng lớp Gạch mở rộng JLabel mở rộng Hình chữ nhật {} không được. – Shrey

2

Trong Java, bạn không thể. Giao diện phải làm với các phương thức và chữ ký, nó không phải làm với trạng thái bên trong của một đối tượng - đó là một câu hỏi thực hiện. Và điều này cũng có ý nghĩa - ý tôi là, đơn giản chỉ vì các thuộc tính nhất định tồn tại, nó không có nghĩa là chúng phải được sử dụng bởi lớp thực hiện. getHeight thực sự có thể trỏ đến biến chiều rộng (giả sử rằng người triển khai thực hiện là một sadist).

(Là một lưu ý - đây là không đúng sự thật của tất cả các ngôn ngữ, ActionScript cho phép khai báo các thuộc tính giả, và tôi tin rằng C# không quá)

+1

Trong C# * getters/setters * (mà thực sự chỉ là các cuộc gọi phương thức đặc biệt) có thể nằm trong các giao diện - các biến mẫu không thể. –

+0

Đó là những gì tôi nghĩ (và đó là lý do tại sao tôi nói giả) ActionScript làm điều tương tự. – cwallenpoole

+0

kk !! thừa kế thay vì thực hiện sẽ giúp. Nhưng điều này sẽ phát sinh cho tôi một vấn đề mới ..! bạn có thể gợi ý cho tôi cách để đi về nó? (xem câu hỏi đã chỉnh sửa) thnx !! – Shrey

0

Fields trong giao diện đang ngầm public static final. Thậm chí nếu bạn sử dụng một lớp trừu tượng thay vì một giao diện, tôi khuyên bạn nên tạo tất cả các hằng số (public static final của một tham chiếu đối tượng nguyên thủy hoặc không thay đổi) private. Nói chung, "ưu tiên thành phần thừa kế" - số Tile không phải là Rectangle (tất nhiên, bạn có thể chơi trò chơi chữ với "is-a" và "has-a").

+0

Hình dạng của Tile là hình chữ nhật .. ?? (là-a và có-một confuses tôi nhất) – Shrey

+0

Tôi đoán A nên mở rộng B nếu và chỉ khi câu trả lời cho 'là mỗi B a A' là đúng ..! đọc từ Java hiệu quả .. – Shrey

+1

Làm thế nào B có thể là A nếu A mở rộng B? Bạn có nó trở lại phía trước. – RichieHH

0

Something quan trọng đã được nói bởi Tom:

nếu bạn sử dụng có-một khái niệm, bạn tránh vấn đề.

Thật vậy, nếu thay vì sử dụng kéo dàicụ bạn xác định hai thuộc tính, một trong những loại hình chữ nhật, một trong những loại JLabel trong lớp Tile của bạn, sau đó bạn có thể định nghĩa một Rectangle để thể là một giao diện hoặc một lớp học.

Hơn nữa, tôi thường khuyến khích sử dụng giao diện kết nối với-a, nhưng tôi đoán nó sẽ là quá mức cần thiết trong hoàn cảnh của bạn. Tuy nhiên, bạn là người duy nhất có thể quyết định điểm này (tính linh hoạt/kỹ thuật quá mức).

4

Java 8 đã giới thiệu default methods cho các giao diện sử dụng mà bạn có thể tải xuống các phương pháp. Theo các giao diện OOP nên hoạt động như một hợp đồng giữa hai hệ thống/bên.

Nhưng tôi vẫn tìm thấy cách để đạt được các thuộc tính lưu trữ trong giao diện. Tôi thừa nhận đó là việc thực hiện xấu xí.

import java.util.Map; 
    import java.util.WeakHashMap; 

interface Rectangle 
{ 

class Storage 
{ 
    private static final Map<Rectangle, Integer> heightMap = new WeakHashMap<>(); 
    private static final Map<Rectangle, Integer> widthMap = new WeakHashMap<>(); 
} 

default public int getHeight() 
{ 
    return Storage.heightMap.get(this); 
} 

default public int getWidth() 
{ 
    return Storage.widthMap.get(this); 
} 

default public void setHeight(int height) 
{ 
    Storage.heightMap.put(this, height); 
} 

default public void setWidth(int width) 
{ 
    Storage.widthMap.put(this, width); 
} 
} 

Giao diện này rất xấu. Để lưu trữ thuộc tính đơn giản, nó cần hai hashmaps và mỗi hashmap theo mặc định tạo ra 16 mục theo mặc định. Ngoài ra khi đối tượng thực sự được dereferenced JVM bổ sung cần phải loại bỏ tham chiếu yếu này.

+0

Khá thú vị nhưng lạ :). Bạn thậm chí có thể loại bỏ lớp bên trong và chỉ lưu trữ các bản đồ cuối cùng tĩnh trong chính giao diện của bạn. – iMysak

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