Получение имени подкласса из суперкласса - PullRequest
65 голосов
/ 05 августа 2010

Допустим, у меня есть базовый класс с именем 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()). Однако мне нужно, чтобы этот метод оставался статичным. Любые предложения о том, как подойти к этому?

Ответы [ 12 ]

85 голосов
/ 05 августа 2010

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

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

return this.getClass().getName();

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

40 голосов
/ 05 августа 2010

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

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

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

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

6 голосов
/ 05 августа 2010

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

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();
    }
}
5 голосов
/ 01 августа 2017

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

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

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

3 голосов
/ 05 августа 2010

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

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 для выполнения операций.Скорее всего, он все еще будет тесно связан с реализациями (как правило, это плохо, или, если не плохо, это не особенно хорошо ), но я думаю, что такая структура лучше, чем суперкласс, выясняющий, чтоего подклассы.

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

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

2 голосов
/ 05 августа 2010

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

System.out.println(User.class);

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

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

0 голосов
/ 26 июля 2016

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

Class<?> claz;

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

public class SubClass {
   public SubClass() {
     claz = this.getClass();
   }
}
0 голосов
/ 18 декабря 2014

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

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 голосов
/ 10 октября 2012

это очень просто сделать с помощью

User.getClass (). GetSuperclass ()

...