Pobieranie klasy po nazwie

81

Jeśli w mojej aplikacji mam klasę Activity o nazwie TestActivity, czy istnieje sposób na pobranie jej klasy według nazwy, tak jak w tym przykładzie:

Class<?> c = getClassByName("TestActivity");
Urho
źródło

Odpowiedzi:

162

użyj zamiast tego forName ...

coś takiego..

 try {
    Class<?> act = Class.forName("com.bla.TestActivity");
 } catch (ClassNotFoundException e) {
        e.printStackTrace();
}
ngesh
źródło
30
Musisz również podać pełną nazwę pakietu. np. com.bla.TestActivity jako argument Class.forName
Richie
1
Czy możesz też coś zrobić, aby otrzymać Class<? extends SomeClass>?
Gobliins,
@Gobliins Nie - kompilator nie może zagwarantować, jaką klasę otrzymasz, więc podaje Ci klasę <?>. Jeśli wiesz, jaką klasę zdobędziesz, będziesz musiał ją rzucić (nawet nadal otrzymujesz niesprawdzone ostrzeżenia, ponieważ rzucanie nie jest bezpieczne).
Dylanthepiguy
1
@Gobliins Sprawdź moją odpowiedź, jak uzyskać podklasę określonego typu.
raphinesse
7

Możesz użyć, Class::forNameaby uzyskać obiekt klasy nieznanego typu. Jeśli chcesz uzyskać wpisaną klasę, możesz użyć Class::asSubclassna klasie zwróconej przez Class::forName:

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

Oczywiście będziesz musiał również poradzić sobie z wieloma różnymi typami wyjątków. Jak zwykle w przypadku refleksji.

raphinesse
źródło
6

Class.forName wydaje się mieć na niej wyjątki. To jest tylko rozwinięcie powyższego, aby rozwiązać ten problem.

try { t = Class.forName("com.package.classname"); } catch (Exception ignored){}
Patrick
źródło
Zwykłym sposobem udzielenia takiej odpowiedzi na SO jest edycja ich odpowiedzi. Chociaż w Javie jest mnóstwo wyjątków (a twój kod po prostu je ignoruje), komentarz byłby wystarczający, aby go rozwiązać.
tsn
7
@crazyhatfish - Wygląda na to, że Patrick mógł nie mieć przywilejów zrobienia czegokolwiek pomocnego poza zamieszczeniem własnej odpowiedzi.
amess
4
@amess Ups, masz rację, zapomniałem, że komentarze wymagają przedstawiciela. Dzięki za poprawienie mnie.
tsn
2

Miałem też podobny wymóg, miałem json pochodzący z zaplecza, który zawiera mapowanie ekranu i aktywności. Ponieważ json jest wspólny dla systemów iOS i Android, nie mogliśmy dodać takich terminów Activitydo json, więc to właśnie zrobiliśmy

  1. W json dla wszystkich Activitylub Viewcontrollersużyj prostych nazw, tj. Dla HomeActivityi HomeViewControllerużyjemy „Home” w pliku json

  2. W aplikacji analizujemy json i napisałem poniższe metody narzędziowe, aby dynamicznie uzyskać aktywność

Aby uzyskać nazwę klasy (tj. Jeśli miniemy Home, wrócimy com.package.HomeActivity)

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

Teraz, aby pobrać klasę ze stringa

        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()
        }

W ten sposób mogę łatwo zarządzać wieloma zajęciami za pomocą tej samej metody. Używam tego w widoku recyklera, w którym każda moja komórka kieruje się do innej czynności.

anoop4real
źródło
Zwróć uwagę, że twoja odpowiedź jest w Kotlinie;) Prawdopodobnie trochę ją zmodyfikuj, aby była Java?
LMD
@LMD Prawdopodobnie większość programistów Androida szukających odpowiedzi potrzebuje wersji kotlin, a nie java;)
Ruslan Berozov
@RuslanBerozov Operator oznaczył pytanie jako [java], więc spodziewałbym się przynajmniej wersji Java (oczywiście dodatkowy Kotlin też jest w porządku).
LMD
@LMD przepraszam, ale op zadał pytanie w 2012 roku. Naprawdę trudno sobie wyobrazić, że wiedział wtedy o Kotlinie. Chodzi o to, że pytanie jest również oznaczone jako [android], a obecnie oczekuję preferowanej wersji Kotlin.
Ruslan Berozov
-2

To może nie być najbardziej odpowiednia odpowiedź na twoje pytanie, ale generalnie źle jest zakodować na stałe literały nazw klas jako ciągi. Lepiej byłoby użyć

Class<?> act = TestActivity.class;

składnia.

Krivda
źródło