2011-09-06 39 views
5

Tôi chỉ tình cờ gặp một số tình huống có vẻ lạ đối với tôi. Dù sao tôi cũng có thể bỏ lỡ điều hiển nhiên ở đây, xin hãy giúp tôi.Nhà xây dựng Scala có bị trùng lặp không?

Xem xét Scala repl kịch bản sau đây:

scala> class X(val s: String) { def run=println("(X): "+s) } 
defined class X 

scala> class Y(s: String) extends X("MY "+s) { override def run=println("(Y): "+s) } 
defined class Y 

scala> new Y("fish").run 
(Y): fish 

Trong kịch bản tôi đang xác định một lớp X với một thuộc tính lớp "val s". Sau đó, tôi định nghĩa một lớp Y được cho là lấy một đối số hàm tạo và chuyển nó tới X- nó làm. Để hiển thị sự khác biệt tôi sửa đổi "s" trước khi tôi đưa nó cho X ("MY" + s).

Cuối cùng, tôi tạo một Y mới và gọi "chạy". Điều này in "cá" vào giao diện điều khiển vì vậy rõ ràng thuộc tính "s" của lớp "X" đã được shadowed bởi một thuộc tính mới "s" mà tôi tạo ra trong "Y".

Tôi đã thử với Scala 2.8 và 2.9.1 với cùng một kết quả.

Đây có phải là cách này không? Tôi phải làm gì nếu tôi chỉ muốn truyền các đối số constructor từ lớp của tôi xuống một lớp cha và không muốn lưu thông số vào trong lớp con? Thực hành phổ biến ở đây là gì?

Cảm ơn!

Trả lời

8

Nếu bạn không sử dụng tham số ngoại trừ trong hàm tạo của lớp con, thông số sẽ không được lưu trữ. Nếu bạn cần tham chiếu đến tham số cha không phải là tham số hàm tạo, hãy sử dụng một tên biến khác.

Lớp học cho thấy ví dụ:

class X(val s: String) { def run=println("(X): "+s) } 
class Y(s: String) extends X("MY "+s) { override def run=println("(Y): "+s) } 
class Z(s0: String) extends X("MY "+s0) { override def run=println("(Z): "+s) } 

Bytecode thấy thiếu dung lượng lưu trữ (chỉ các nhà thầu):

// Note putfield to store s 
public X(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield #11; //Field s:Ljava/lang/String; 
    5: aload_0 
    6: invokespecial #43; //Method java/lang/Object."<init>":()V 
    9: return 

// Note putfield to store new s (then eventually calls X's constructor) 
public Y(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield #29; //Field s:Ljava/lang/String; 
    5: aload_0 
    6: new #16; //class scala/collection/mutable/StringBuilder 
    9: dup 
    10: invokespecial #19; //Method scala/collection/mutable/StringBuilder."<init>":()V 
    13: ldC#40; //String MY 
    15: invokevirtual #25; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    18: aload_1 
    19: invokevirtual #25; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    22: invokevirtual #33; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 
    25: invokespecial #44; //Method X."<init>":(Ljava/lang/String;)V 
    28: return 

// Note - no putfield! 
public Z(java.lang.String); 
    Code: 
    0: aload_0 
    1: new #14; //class scala/collection/mutable/StringBuilder 
    4: dup 
    5: invokespecial #17; //Method scala/collection/mutable/StringBuilder."<init>":()V 
    8: ldC#39; //String MY 
    10: invokevirtual #23; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    13: aload_1 
    14: invokevirtual #23; //Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    17: invokevirtual #32; //Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 
    20: invokespecial #43; //Method X."<init>":(Ljava/lang/String;)V 
    23: return 
+0

Cảm ơn bạn đã giải thích chi tiết! –

+0

Tham số lớp s trong Y đổ bóng các giá trị s được định nghĩa trong X. – mkneissl

1

Thật vậy, tham số của bóng tham số lớp cha. Điểm quan trọng là phạm vi của tham số lớp (tức là tham số của hàm tạo chính) là toàn bộ lớp. Vì vậy, trong phương pháp Y.run của bạn, không có câu hỏi nào liên quan đến Y.s.

Điều đó có nghĩa là s phải được giữ sống trong một lĩnh vực, và như Rex đã cho bạn thấy, đó là chính xác những gì đang xảy ra.

Đối với một số nhà xây dựng chính, có ba lựa chọn:

  • var => làm cho lĩnh vực, phương thức getter và setter
  • val => làm cho lĩnh vực và getter
  • không => làm cho lĩnh vực nếu cần thiết (tức là tham số được sử dụng trong phương pháp), nhưng không có getter/setter
Các vấn đề liên quan