Получение класса по его имени

81

Если в моем приложении есть класс Activity с именем TestActivity, есть ли способ получить его класс по имени, как в этом примере:

Class<?> c = getClassByName("TestActivity");
Урхо
источник

Ответы:

162

вместо этого используйте forName ..

что-то вроде этого..

 try {
    Class<?> act = Class.forName("com.bla.TestActivity");
 } catch (ClassNotFoundException e) {
        e.printStackTrace();
}
нгеш
источник
30
Вы также должны указать полное имя пакета. например: com.bla.TestActivity в качестве аргумента для Class.forName
Ричи,
1
Можете еще что-нибудь получить Class<? extends SomeClass>?
Gobliins
@Gobliins Нет - компилятор не может гарантировать, какой класс вы собираетесь получить, поэтому он дает вам Class <?>. Если вы знаете, какой класс вы собираетесь получить, вам придется его преобразовать (даже если вы все равно получаете предупреждения о непроверенном приведении, потому что приведение небезопасно).
Dylanthepiguy
1
@Gobliins Посмотрите мой ответ о том, как получить подкласс определенного типа.
raphinesse 05
7

Вы можете использовать Class::forNameдля получения объекта класса неизвестного типа. Если вы хотите получить типизированный класс, вы можете использовать Class::asSubclassкласс, возвращаемый Class::forName:

Class<? extends Activity> activityClass = Class.forName("com.example.TestActivity")
                                               .asSubclass(Activity.class);

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

рафинез
источник
6

У Class.forName есть исключения. Это просто дополнение к вышесказанному для решения этой проблемы.

try { t = Class.forName("com.package.classname"); } catch (Exception ignored){}
Патрик
источник
Обычно SO ответить подобным образом - это отредактировать свой ответ. Хотя, поскольку в Java множество исключений (и ваш код просто игнорирует их), комментария будет достаточно, чтобы их решить.
tsn
7
@crazyhatfish - Похоже, Патрик не имел привилегии делать что-нибудь полезное, кроме публикации собственного ответа.
amess
4
@amess Ой, вы правы, я забыл, что для комментариев нужна репутация. Спасибо, что поправили меня.
tsn
2

У меня также было аналогичное требование, у меня был json, исходящий из бэкэнда, который содержит экран и отображение активности. Поскольку json является общим для iOS / Android, мы не могли добавлять такие термины, как Activityв json, поэтому вот что мы сделали

  1. В json для всех Activityили Viewcontrollersиспользуйте простые имена, т.е. for, HomeActivityи HomeViewControllerмы будем использовать "Home" в json.

  2. В приложении мы анализируем json, и я написал следующие служебные методы для динамического получения активности.

Чтобы получить имя класса (т.е. если мы пройдем Home, мы вернемся com.package.HomeActivity)

    fun getClassInfoFor(name: String, context: Context):String{
        var str = "${context.getPackageName()}.${name}Activity"
        return str
    }

Теперь, чтобы получить класс из строки

        try {
            val className = Utilties.getClassInfoFor(activityNameFromJSON, context)
            val fetchedClass = Class.forName(className)
            val showDetailsIntent = Intent(context, fetchedClass)
            context.startActivity(showDetailsIntent)
        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        }

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

anoop4real
источник
Обратите внимание, что ваш ответ на Kotlin;) Может быть, его немного переделать, чтобы он стал Java?
LMD
@LMD, наверное, большинству разработчиков Android, которые ищут ответ, нужна версия на котлине, а не на java;)
Руслан Берозов 08
@RuslanBerozov Оператор пометил вопрос как [java], так что я ожидал бы как минимум версию Java (дополнительный Kotlin, конечно, тоже подойдет).
LMD
@LMD извините, но op опубликовал вопрос в 2012 году. Трудно представить, что он знал о Kotlin в то время. Дело в том, что вопрос также помечен как [android], и в настоящее время я предпочитаю версию Kotlin.
Руслан Берозов
-2

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

Class<?> act = TestActivity.class;

синтаксис.

Кривда
источник