2010-08-05 2 views
54

Предположим, у меня есть базовый класс с именем Entity. В этом классе у меня есть статический метод для получения имени класса:Получение имени подкласса из суперкласса

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

Теперь у меня есть еще один класс.

class User extends Entity { 
} 

Я хочу, чтобы получить имя класса пользователя:

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

Моя цель состоит, чтобы увидеть «com.packagename.User» выводится на консоль, но вместо этого я собираюсь закончить с «com.packagename.Entity», поскольку класс Entity ссылается непосредственно из статического метода.

Если это не был статический метод, это можно легко решить, используя ключевое слово this в классе Entity (то есть: return this.class.getClass()). Однако мне нужно, чтобы этот метод оставался статичным. Любые предложения о том, как подойти к этому?

ответ

36

Невозможно. Статические методы не являются полиморфными во время выполнения. Это абсолютно невозможно отличить эти случаи:

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

Они компилировать в тот же байт-код (при условии, что метод определен в Entity).

Кроме того, как бы вы назвали этот метод таким образом, чтобы иметь смысл полиморфизма?

+1

Спасибо за разъяснение, я думаю, я не знаю достаточно о том, как статические методы компилируются. Это помогает разобраться в этом, мне придется работать над альтернативным решением. –

+2

+1, точно вправо. Весь этот вопрос возникает из-за непонимания того, как работают статические методы. –

2

Почему вы хотите реализовать свой собственный метод getClass()? Вы можете просто использовать

System.out.println(User.class); 

Редактировать (разработать немного): Вы хотите, чтобы метод был статичным. В этом случае вы должны вызвать метод в классе, имя класса которого вы хотите, будь то подкласс или суперкласс. Затем вместо вызова MyClass.getClass() вы можете просто позвонить MyClass.class или MyClass.class.getName().

Также вы создаете метод static с той же подписью, что и метод экземпляра Object.getClass(), который не будет компилироваться.

+1

Я намеренно написал вопрос, так что на StackOverflow было бы очень голые кости и сразу же перейти к сути вопроса. Это действительно потому, что я создаю гораздо более надежный статический метод, который использует имя класса любого подкласса, расширяющего этот абстрактный базовый класс. –

+1

Похоже, вы хотите полиморфизм через 'статические' методы, что невозможно. Кроме того, можете ли вы объяснить, почему приведенное выше недостаточно надежное? – samitgaur

+0

Это не достаточно убедительно, потому что мне придется переопределять статический метод в каждом отдельном классе наследования вместо того, чтобы просто определять статический метод один раз. –

67

Не делайте метод статическим. Проблема в том, что при вызове getClass() вы вызываете метод в суперклассе - статические методы не наследуются. Кроме того, вы в основном затеняете имя Object.getClass(), что сбивает с толку.

Если вам необходимо войти имя класса в пределах суперкласса, используйте

return this.getClass().getName(); 

Это вернет «Entity», когда у вас есть Entity экземпляра, «User», когда у вас есть User экземпляра и т.д.

+1

'this' не существует в статическом методе. –

+24

@Matt Huggins, поэтому первое предложение в моем ответе гласит: «Не делайте метод static» –

+2

@ matt b - вот почему второе и последнее предложение моего вопроса гласит: «Однако мне нужен этот метод, чтобы остаться static.' –

0

Статический метод связан с классом, а не с конкретным объектом.

Рассмотрите, как это будет работать, если существует несколько подклассов - например, Администратор также является Сущностью. Как бы ваш статический метод Entity, связанный только с классом Entity, знал, какой подкласс вам нужен?

Вы могли:

  • Использование существующих GetClass() метод.
  • Передайте аргумент вашему статическому методу getClass() и вызовите метод экземпляра для этого объекта.
  • Сделайте свой метод нестационарным и переименуйте его.
0

Если я правильно понимаю ваш вопрос, я думаю, что единственный способ, которым Вы можете добиться того, что вы хотите, чтобы повторно реализовать статический метод в каждом подклассе, например:

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

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

Это напечатает пакет .Entity и package.Derived по мере необходимости. Веселый, но эй, если это ваши ограничения ...

6

Ваш вопрос неоднозначен, но насколько я могу судить, вы хотите знать текущий класс из статического метода. Тот факт, что классы наследуются друг от друга, не имеет значения, но ради обсуждения я его реализовал так же.

 
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, это * stacktrace-hack * грязный. Что случилось с 'System.out.println (Parent.class.getName());'? – whiskeysierra

+2

Как я уже сказал, вопрос Мэтта неоднозначен, и я дал один из возможных ответов. Очевидно, что ваша версия не дает того же результата, что и мой код, поэтому нет никакого сравнения - вы говорите о другом решении. И чтение стека нитей не является взломом, это обычный способ проверки иерархии вызовов (конечно, я пропустил проверку работоспособности, так как это пример). – Gilead

+0

Это довольно забавный взлом, но он мало связан с запрошенным поведением. Эта функция печатает имя класса * вызывает * метод (т. Е. Если вы удаляете 'extends Parent' и меняете вызов на Parent.printClass()', он все равно печатает «Test»). – nemetroid

3

Суперкласс даже не должен знать о существовании подкласса, гораздо меньше, выполнять операции, основанные на полное имя подкласса. Если вам необходимы операции на основе того, что точный класс, и не может выполнять необходимые функции по наследству, вы должны сделать что-то вдоль этих линий:

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; 
    } 
} 

(Непроверенные код)

Этот класс Безразлично Также не знаю о своих собственных подклассах, но использует класс Class для выполнения операций. Скорее всего, он все равно будет тесно связан с реализациями (как правило, это плохо, или, если не плохо, это не особенно хорошо), но я думаю, что такая структура лучше, чем суперкласс, выясняя, что все его подклассы ,

-4

это очень просто делается

User.getClass(). GetSuperclass()

+2

Это делает противоположное тому, что задал вопрос. Я хотел получить имя подкласса из суперкласса. В вашем ответе указано имя суперкласса из подкласса. –

2
  1. Создать дочернюю Струнный переменную в суперкласса.
  2. Добавьте this.getClass(). GetName() в конструктор, который сохраняет значение в переменной строки String.
  3. Создайте геттер, чтобы вернуть имя.

Каждый раз, когда экземпляр расширенного класса создается, его имя будет сохранено в Строке и доступно с помощью геттера.

0

Если я беру это право вы хотите использовать свой класс суба в базовом классе в статическом методе я думаю, что вы можете сделать это путем передачи параметра класса методы

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

Моего контекста: суперкласс Entity с подклассами для объектов XML. Мое решение: Создать переменную класса в суперкласса

Class<?> claz; 

Тогда в подклассе я бы установить переменную суперкласса в конструкторе

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

Это работает для меня

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

Но я не уверен, как это работает.

Смежные вопросы