2011-02-04 60 views
40

Tôi chỉ bắt đầu với một ví dụ, giải thích nó tốt nhất:Java: Trường tĩnh trong lớp trừu tượng

public abstract class A{ 
    static String str; 
} 

public class B extends A{ 
    public B(){ 
     str = "123"; 
    } 
} 

public class C extends A{ 
    public C(){ 
     str = "abc"; 
    } 
} 

public class Main{ 

    public static void main(String[] args){ 
     A b = new B(); 
     A c = new C(); 
     System.out.println("b.str = " + b.str); 
     System.out.println("c.str = " + c.str); 
    } 
} 

này sẽ in ra:

b.str = abc

c. str = abc

Nhưng tôi muốn một giải pháp trong đó mỗi phân lớp khởi tạo lớp siêu, có biến số lớp riêng của chúng tôi, cùng lúc tôi muốn để có thể tham chiếu biến lớp đó thông qua mã định danh hoặc cuộc gọi phương thức, được định nghĩa trong lớp siêu trừu tượng.

Vì vậy, tôi muốn đầu ra là:

b.str = 123

c.str = abc

Có phải đó là doable?

Trả lời

3

Đặt varibale tĩnh trong mỗi lớp và thêm một (không tĩnh) phương pháp trừu tượng với lớp cha trừu tượng:

abstract String getStr(); 

Sau đó, thực hiện các phương pháp getStr() trong mỗi lớp bằng cách trả lại lĩnh vực tĩnh của đặc biệt này lớp con.

public class B extends A { 
private static String str; 

    @Override 
    public String getStr() { 
    return B.str; 
    } 
} 
+0

Tôi đã chỉnh sửa bài đăng của mình, đã xảy ra lỗi .. xin lỗi. Vấn đề là, tôi cần mỗi đối tượng để có một tham chiếu đến một giá trị được chia sẻ giữa tất cả các đối tượng của cùng một lớp con, nhưng không nhất thiết trong số các đối tượng của các lớp con khác nhau. – Tommy

+0

Tôi đã cập nhật câu trả lời của mình quá – Ralph

+0

Tất nhiên. Cảm ơn bạn. – Tommy

6
public abstract class A { 
    private String str; 
    public String getStr() { return str;} 
    protected void setStr(String str) { this.str = str; } 
} 

Sau đó, bạn sẽ có thể có

B b = new B(); 
b.getStr(); 

Các setter và getter là bổ sung của tôi, bạn có thể đi bằng cách đơn giản làm cho biến không tĩnh.

Cập nhật Nếu bạn muốn có lớp tĩnh mỗi, sau đó bạn có thể có:

protected static Map<Class, String> values; 
public abstract String getValue(); 

và sau đó:

public String getValue() { 
    values.get(getClass()); 
} 
public void setValue(String value) { 
    values.set(getClass(), value); 
} 

Nhưng điều này nói chung là một ý tưởng tồi.

+0

Thao tác này sẽ hoạt động, ngay cả khi không có bộ khởi động và thiết lập. Sau đó, chỉ cần chắc chắn rằng biến str là công khai, mà không được khuyến khích. –

+0

@Thijs: Tôi luôn thích một phương thức (đặc biệt là một phương thức chỉ đọc như 'getStr()' ở đây) trên truy cập trực tiếp đến một trường tĩnh. –

+0

Cảm ơn! Bạn không chắc chắn lý do tại sao bạn nghĩ đó là một ý tưởng tồi. Với giải pháp này, tôi thậm chí không phải mã hóa bất cứ điều gì trong các lớp con, mọi thứ được thực hiện trong lớp siêu. Tất nhiên có vẻ hơi lạ khi gọi phương thức trên một đối tượng để đặt biến lớp (hoặc giả mạo nó như là giải pháp của bạn, loại). Nhưng có vẻ như không có cách nào để thoát khỏi điều đó (giải pháp của Jon Skeet và Ralph). – Tommy

2

chỉ một phiên bản biến tĩnh có mặt trong hệ thống.

biến tĩnh sẽ tải vào hệ thống khi bắt đầu trước khi lớp được tải.

lý do cả thời gian abc được in là vì bạn đặt giá trị của str là abc trong lần cuối cùng.

2

này sẽ in kết quả bạn muốn:

public abstract class A{ 
} 

public class B extends A{ 
    static String str; 

    public B(){ 
     str = "123"; 
    } 
} 

public class C extends A{ 
    static String str; 

    public C(){ 
     str = "abc"; 
    } 
} 

public class Main{ 

    public static void main(String[] args){ 
     A a = new B(); 
     A c = new C(); 
     System.out.println("B.str = " + B.str); 
     System.out.println("C.str = " + C.str); 
    } 
} 
+0

Cảm ơn. Hầu như ở đó :) Xem câu trả lời của Ralph. Có thể tôi không giải thích rất rõ. – Tommy

45

Nếu bạn muốn lớp học B và C để có các biến tĩnh riêng biệt, bạn sẽ cần phải khai báo các biến trong những lớp này. Về cơ bản, các thành viên tĩnh và đa hình không đi cùng nhau.

Lưu ý rằng việc tiếp cận các thành viên tĩnh thông qua tài liệu tham khảo là một ý tưởng thực sự xấu về khả năng đọc - nó làm cho nó trông như nó phụ thuộc vào giá trị của các tài liệu tham khảo, khi nó không thực sự. Vì vậy, mã hiện tại của bạn thậm chí sẽ không biên dịch khi bạn đã chuyển str xuống B và C. Thay vào đó, bạn sẽ cần

System.out.println("b.str = " + B.str); 
System.out.println("c.str = " + C.str); 

Nếu bạn thực sự cần phải truy cập vào các giá trị polymorphically (tức là thông qua một thể hiện của A) thì một tùy chọn là tạo một bộ thu hút đa hình:

public class A { 
    public abstract String getStr(); 
} 

public class B extends A { 
    private static String str = "b"; 

    @Override public String getStr() { 
     return str; 
    } 
} 

(và tương tự cho C).

Bằng cách đó, bạn nhận được hành vi mà bạn muốn về mặt không có riêng biệt biến mỗi trường hợp, nhưng bạn vẫn có thể sử dụng nó một cách đa hình. Đó là một chút kỳ lạ cho một thành viên thể hiện để trả về một giá trị tĩnh như thế này, nhưng bạn đang sử dụng giá trị cho đa hình của loại, về cơ bản ...

+4

Kinh nghiệm của tôi là nó thậm chí còn đáng để cài đặt Eclipse để đánh dấu chúng là lỗi biên dịch. – biziclop

+7

@biziclop: Tôi cũng thế. Đó là lý do tại sao tôi yêu cầu nó trong Eclipse ở nơi đầu tiên: https://bugs.eclipse.org/bugs/show_bug.cgi?id=21109 :) –

+0

Tốt để biết điều đó. :) – biziclop

2

Vì bạn vẫn mã hóa giá trị hoặc str trong lớp con, bạn có thể làm một cái gì đó như thế này:

public abstract class A{ 
    public abstract String getStr(); 
} 

public class B extends A{ 
    public String getStr(){ 
     return "123"; 
    } 
} 

public class C extends A{ 
    public String getStr(){ 
     return "abc"; 
    } 
} 

Điều này sẽ thực hiện thủ thuật trong trường hợp của bạn.

Tất nhiên, sau đó bạn nên gọi nó bằng phương pháp, như thế này:

public class Main{ 

    public static void main(String[] args){ 
     A b = new B(); 
     A c = new C(); 
     System.out.println("b.str = " + b.getStr()); 
     System.out.println("c.str = " + c.getStr()); 
    } 
} 
0

Tôi nghĩ rằng một trong những cách tiếp cận này là sử dụng một singleton cho lớp BC để bắt chước phương pháp tĩnh và các lĩnh vực. Cả hai có thể mở rộng lớp trừu tượng A, nhưng sẽ có giá trị riêng của chúng là str ..

1

Đó là những gì tôi đã làm để tránh phải thực hiện cùng một phương thức trong mọi phân lớp. Nó dựa trên câu trả lời của Bozho. Có lẽ nó có thể giúp ai đó.

import java.util.HashMap; 
import java.util.Map; 

/** 
* 
* @author Uglylab 
*/ 
public class SandBox { 

    public static void main(String[] args) { 
     A b = new B(); 
     A c = new C(); 
     System.out.println("b.str = " + B.getStr(b.getClass())); 
     System.out.println("c.str = " + C.getStr(c.getClass())); 
    } 

} 
abstract class A{ 
    protected static Map<Class, String> values = new HashMap<>(); 


    public static String getStr(Class<? extends A> aClass) { 
     return values.get(aClass); 
    } 

    public static void setStr(Class<? extends A> aClass, String s) { 
     values.put(aClass, s); 
    } 

} 

class B extends A{ 
    public B(){ 
     setStr(this.getClass(),"123"); 
    } 
} 

class C extends A{ 
    public C(){ 
     setStr(this.getClass(),"abc"); 
    } 
} 
Các vấn đề liên quan