2017-10-19 20 views
8

Mam następujące klasy:Java - parametr Zastosowanie metody klasy w parametrze

public class Publisher<T> { 

    private static final Class[] SUPPORTED_CLASSES = new Class[]{T1.class, T2.class}; 

    public Publisher() { 
     if(Arrays.asList(SUPPORTED_CLASSES).contains(T)) { // error: expression expected! 
      System.out.println("Class not supported!"); 
     } 
    } 
} 

Jak mogę sprawdzić, czy parametr klasa jest zgodny z realizacji?
W powyższym przykładzie nie można użyć parametru klasy T jako parametru.

+0

Sprawdź ten wątek https://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-ruime –

+3

Dlaczego tego chcesz, jeśli mogę zapytać? –

+0

@MCEmperor Chciałem sprawdzić, czy klasa jest obsługiwana iw razie potrzeby wyświetlać komunikat ostrzegawczy. – FazoM

Odpowiedz

13

Dlaczego to nie działa

Próbujesz uzyskać dostęp do typu rodzajowego w czasie wykonywania, który nie działa w tym przypadku, ze względu na type erasure.

Jak naprawić

Najprostszym sposobem, aby naprawić ten ma podjąć Class<T> w konstruktorze, który daje typ w czasie wykonywania, można następnie sprawdzić, czy lista zawiera wartość, którą zostały podane .

przykładowy kod

public Publisher(Class<T> clazz) { 
    if(!SUPPORTED_CLASSES.contains(clazz)) { 
     System.out.println("Class not supported!"); 
    } 
} 

Możliwe problemy

Twój kod nie obsługuje obecnie podtypy, które mogą powodować problemy, chyba że jesteś ok z tego (może pracować na listach, ale niekoniecznie ArrayLists) , to jednak dziób LSP.

+0

Powiedziałbym, że jeszcze bardziej podstawowym powodem, dla którego kod OP nie działa, są argumenty typu, takie jak' T' desygnować * typy * , nie obiekty.W szczególności nie są one takie same jak i nie reprezentują obiektów typu 'java.lang.Class', takich jak te, które zawiera tablica OP. Typy nie są prawidłowymi zwykłymi argumentami. –

+0

LSP jest problemem tylko wtedy, gdy klasa OP ma być kowariancyjna w T. Jeśli jest to przeciwieństwo lub niezmiennik, jest to całkowicie legalny (jeśli dziwny i nie-OOP) sposób robienia rzeczy. – Kevin

4

Musisz zdać z klasy do konstruktora:

public Publisher(Class<T> clazz) { 
    if(!SUPPORTED_CLASSES.contains(clazz)) { 
     System.out.println("Class not supported!"); 
    } 
} 

ponieważ T nie jest dostępna w czasie wykonywania: dokładnie ten sam kod będzie wykonywany dla new Publisher<T1>() i new Publisher<T3>().

6

Chociaż niektóre inne odpowiedzi są dość dobre, chciałbym zaproponować inną obejście:

Można by utworzyć pusty interfejs MyInterface, i mają wszystkie zajęcia w liście wdrożyć ten interfejs. Następnie możesz zmienić deklarację swojej klasy na:

public class Publisher<T extends S, MyInterface> 

, która spełni twoje zadanie.

+1

To jest lepsze rozwiązanie, jeśli masz kontrolę nad wszystkimi klasami, które potrzebujesz obsługiwać, ale jeśli potrzebujesz wspierać klasy, których nie napisałeś, być może będziesz musiał zrobić to w inny sposób. – jrtapsell

+1

@jrtapsell w najgorszym przypadku, jeśli nie musisz obsługiwać zbyt wielu klas, używając mostu dla każdej klasy, której potrzebujesz (prosty wrapper w rzeczywistości) implementującej interfejs – AxelH

+0

Kiedy twoje rozwiązanie działa tylko z klasami, które implementują konkretną interfejs, nie potrzebujesz już tej listy kompatybilnych klas i możesz po prostu zadeklarować klasę jako 'public public Publisher ' – Philipp

Powiązane problemy