2010-08-05 40 views
54

Giả sử tôi có một lớp cơ sở có tên là Entity. Trong lớp học đó, tôi có một phương pháp tĩnh để truy xuất tên lớp:Lấy tên của một phân lớp từ trong một siêu lớp

class Entity { 
    public static String getClass() { 
     return Entity.class.getClass(); 
    } 
} 

Bây giờ tôi có một lớp khác mở rộng.

class User extends Entity { 
} 

Tôi muốn có được tên lớp của người dùng:

System.out.println(User.getClass()); 

Mục tiêu của tôi là để xem "com.packagename.User" đầu ra để giao diện điều khiển, nhưng thay vào đó tôi sẽ kết thúc với "com.packagename.Entity" vì lớp Entity đang được tham chiếu trực tiếp từ phương thức tĩnh.

Nếu đây không phải là phương pháp tĩnh, điều này có thể dễ dàng được giải quyết bằng cách sử dụng từ khóa this trong lớp Entity (ví dụ: return this.class.getClass()). Tuy nhiên, tôi cần phương pháp này để tĩnh. Bất kỳ đề xuất về cách tiếp cận này?

Trả lời

36

Không thể. Các phương thức tĩnh không phải là đa hình thời gian chạy theo bất kỳ cách nào. Hoàn toàn không thể phân biệt các trường hợp này:

System.out.println(Entity.getClass()); 
System.out.println(User.getClass()); 

Chúng biên dịch thành cùng một mã byte (giả định rằng phương thức được xác định trong Entity).

Bên cạnh đó, làm cách nào bạn gọi phương thức này theo cách có ý nghĩa cho nó là đa hình?

+1

Cảm ơn bạn đã làm rõ, tôi đoán tôi không biết đủ về cách các phương thức tĩnh biên dịch. Điều này giúp mọi thứ rõ ràng, tôi sẽ phải làm việc trên một giải pháp thay thế. –

+2

+1, chính xác. Toàn bộ câu hỏi này được sinh ra từ một sự hiểu lầm về cách thức các phương thức tĩnh hoạt động. –

2

Tại sao bạn muốn triển khai phương thức getClass() của riêng mình? Bạn chỉ có thể sử dụng

System.out.println(User.class); 

Sửa (để xây dựng một chút): Bạn muốn phương pháp này để được tĩnh. Trong trường hợp đó, bạn phải gọi phương thức trên lớp có tên lớp bạn muốn, có thể là lớp con hoặc siêu lớp. Sau đó, thay vì gọi số MyClass.getClass(), bạn chỉ có thể gọi MyClass.class hoặc MyClass.class.getName().

Ngoài ra, bạn đang tạo phương thức static có cùng chữ ký với phương thức thể hiện Object.getClass() không được biên dịch.

+1

Tôi đã cố ý viết câu hỏi để nó trở nên rất sơ sài trên StackOverflow và đi thẳng đến điểm của câu hỏi. Nó thực sự là vì tôi đang xây dựng một phương pháp tĩnh mạnh mẽ hơn nhiều, sử dụng tên lớp của bất kỳ lớp con nào mở rộng lớp cơ sở trừu tượng này. –

+1

Có vẻ như bạn muốn đa hình thông qua phương pháp 'tĩnh', điều này là không thể. Ngoài ra, bạn có thể giải thích lý do tại sao ở trên không đủ mạnh không? – samitgaur

+0

Nó không đủ mạnh bởi vì tôi sẽ phải xác định lại phương thức tĩnh trong mỗi lớp kế thừa duy nhất thay vì chỉ có thể định nghĩa phương thức tĩnh một lần. –

67

Không đặt phương thức tĩnh. Vấn đề là khi bạn gọi getClass() bạn đang gọi phương thức trong lớp siêu - các phương thức tĩnh không được kế thừa. Ngoài ra, về cơ bản, bạn có tên là shadowing Object.getClass(), điều này gây nhầm lẫn.

Nếu bạn cần phải đăng nhập classname trong lớp cha, sử dụng

return this.getClass().getName(); 

này sẽ trở lại "Entity" khi bạn có một Entity dụ, "Thành viên" khi bạn có một trường hợp User vv

+1

'this' không tồn tại trong một phương thức tĩnh. –

+24

@Matt Huggins, đó là lý do tại sao câu đầu tiên trong câu trả lời của tôi nói 'Không làm cho phương thức tĩnh' –

+2

@ matt b - đó là lý do câu thứ hai cho câu cuối của tôi nói 'Tuy nhiên, tôi cần phương pháp này static.' –

0

Phương pháp tĩnh được liên kết với một lớp, không phải với một đối tượng cụ thể.

Hãy xem xét cách điều này sẽ hoạt động nếu có nhiều lớp con - ví dụ: Quản trị viên cũng là một Thực thể. Phương thức Entity tĩnh của bạn như thế nào, chỉ liên kết với lớp Entity, bạn biết lớp con nào bạn muốn?

Bạn có thể:

  • Sử dụng getClass hiện phương pháp().
  • Vượt qua một đối số cho phương thức getClass() tĩnh của bạn và gọi một phương thức cá thể trên đối tượng đó.
  • Làm cho phương pháp của bạn không tĩnh và đổi tên nó.
0

Nếu tôi hiểu câu hỏi của bạn một cách chính xác, tôi nghĩ rằng cách duy nhất bạn có thể đạt được những gì bạn muốn là để tái thực hiện các phương pháp tĩnh trong mỗi lớp con, ví dụ:

class Entity { 
    public static String getMyClass() { 
     return Entity.class.getName(); 
    } 
} 

class Derived extends Entity { 
    public static String getMyClass() { 
     return Derived.class.getName(); 
    } 
} 

này sẽ in gói .Entity và package.Derived như bạn yêu cầu. Lộn xộn nhưng hey, nếu đó là những khó khăn của bạn ...

6

Câu hỏi của bạn là mơ hồ nhưng theo như tôi có thể nói bạn muốn biết lớp hiện tại từ một phương pháp tĩnh. Thực tế là các lớp kế thừa từ mỗi khác là không liên quan nhưng vì lợi ích của cuộc thảo luận, tôi đã thực hiện nó theo cách này.

 
class Parent { 
    public static void printClass() { 
     System.out.println(Thread.currentThread().getStackTrace()[2].getClassName()); 
    } 
} 

public class Test extends Parent { 
    public static void main(String[] args) { 
     printClass(); 
    } 
} 
+0

Ouch, rằng * stacktrace-hack * bị bẩn. Có gì sai với 'System.out.println (Parent.class.getName());'? – whiskeysierra

+2

Như tôi đã nói, câu hỏi của Matt là mơ hồ và tôi đã cung cấp một trong những câu trả lời có thể có. Rõ ràng phiên bản của bạn không cung cấp cho đầu ra giống như mã của tôi vì vậy không có so sánh - bạn đang nói về một giải pháp khác. Và đọc ngăn xếp thread không phải là một hack, đó là một cách bình thường để kiểm tra hệ thống phân cấp cuộc gọi của một người (tất nhiên tôi bỏ qua kiểm tra sanity vì đây là một ví dụ). – Gilead

+0

Đây là một hack khá buồn cười, nhưng có rất ít để làm với các hành vi yêu cầu. Hàm này in tên của lớp * gọi * phương thức (tức là, nếu bạn loại bỏ 'extends Parent' và thay đổi lời gọi thành' Parent.printClass() ', nó vẫn in" Test "). – nemetroid

3

Siêu lớp thậm chí không biết về sự tồn tại của phân lớp, hoạt động kém hơn nhiều dựa trên tên đầy đủ của lớp con. Nếu bạn cần phải hoạt động dựa trên những gì lớp chính xác là, và không thể thực hiện các chức năng cần thiết bằng cách thừa kế, bạn nên làm một cái gì đó dọc theo những dòng:

public class MyClassUtil 
{ 
    public static String doWorkBasedOnClass(Class<?> clazz) 
    { 
     if(clazz == MyNormalClass.class) 
     { 
      // Stuff with MyNormalClass 
      // Will not work for subclasses of MyNormalClass 
     } 

     if(isSubclassOf(clazz, MyNormalSuperclass.class)) 
     { 
      // Stuff with MyNormalSuperclass or any subclasses 
     } 

     // Similar code for interface implementations 
    } 

    private static boolean isSubclassOf(Class<?> subclass, Class<?> superclass) 
    { 
     if(subclass == superclass || superclass == Object.class) return true; 

     while(subclass != superclass && subclass != Object.class) 
     { 
      subclass = subclass.getSuperclass(); 
     } 
     return false; 
    } 
} 

(đang chưa được kiểm tra)

này lớp doesn không biết về các lớp con của riêng nó, mà là sử dụng lớp Class để thực hiện các hoạt động. Nhiều khả năng, nó sẽ vẫn được liên kết chặt chẽ với việc triển khai (thường là một điều xấu, hoặc nếu không xấu nó không đặc biệt là tốt), nhưng tôi nghĩ rằng một cấu trúc như thế này tốt hơn một siêu phân lớp để tìm hiểu tất cả các lớp con của nó là gì .

-4

nó rất đơn giản được thực hiện bởi

User.getClass(). GetSuperclass()

+2

Điều này ngược lại với câu hỏi được yêu cầu. Tôi muốn tên của một lớp con từ bên trong một siêu lớp. Câu trả lời của bạn cung cấp tên của siêu lớp từ bên trong một lớp con. –

2
  1. Tạo một thành viên Chuỗi biến trong lớp cha.
  2. Thêm this.getClass(). GetName() vào một hàm tạo lưu trữ giá trị trong biến chuỗi thành viên.
  3. Tạo bộ thu thập để trả lại tên.

Mỗi khi lớp mở rộng được khởi tạo, tên của nó sẽ được lưu trữ trong chuỗi và có thể truy cập được với bộ khởi động.

0

Nếu tôi đang dùng nó phải bạn muốn sử dụng lớp phụ của bạn trong lớp cơ sở trong phương pháp tĩnh Tôi nghĩ bạn có thể làm điều này bằng cách thông qua một tham số lớp phương pháp

class Entity { 
    public static void useClass(Class c) { 
     System.out.println(c); 
     // to do code here 
    } 
} 

class User extends Entity { 
} 

class main{ 
    public static void main(String[] args){ 
     Entity.useClass(Entity.class); 
    } 
} 
0

bối cảnh của tôi: Entity lớp cha với các lớp con cho các đối tượng XML. Giải pháp của tôi: Tạo một biến lớp trong lớp cha

Class<?> claz; 

Sau đó, trong lớp con tôi sẽ đặt biến của lớp cha trong constructor

public class SubClass { 
    public SubClass() { 
    claz = this.getClass(); 
    } 
} 
3

này làm việc cho tôi

this.getClass().asSubclass(this.getClass()) 

Nhưng tôi không chắc nó hoạt động như thế nào.

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