2013-04-28 11 views
6

Oto przykład:Czy int.class.isInstance (Object) jest sprzecznością?

public boolean check(Class<?> clazz, Object o) 
{ 
    return clazz.isInstance(o); 
} 

check(int.class, 7); // returns false 

Od isInstance akceptuje Object, to nie będzie działać z int, ponieważ int to prymitywny typ i dostaje autoboxed do Integer. Czy istnieje zatem możliwość napisania ogólnej metody sprawdzania? Czy powinienem się upewnić, że clazz ma typ Class<? extends Object>?

+4

Zamiast używać niezbyt znaczących tagów, takich jak 'int',' types' czy nawet 'isintance', powinieneś oznaczyć pytanie językiem, którego używasz. To przyciągnie więcej widzów, a tym samym zwiększy szansę otrzymania satysfakcjonującej odpowiedzi. –

+1

Sry, zupełnie o tym zapomniałem. ... Domyślam się, że java stała się dla mnie naturalna: D – mike

+2

Czy przeczytałeś [tę odpowiedź] (http://stackoverflow.com/a/7083456/516433) jeszcze? – Lucas

Odpowiedz

6

Nie wszystkie obiekty Class reprezentują klasy/typy odniesienia; istnieją również obiekty Class reprezentujące typy pierwotne. Jest to użyteczne, ponieważ podczas korzystania z odbicia z polami i metodami często trzeba określać ich typ i może to być typ pierwotny. Tak więc Class jest używany do reprezentowania wszystkich takich typów pre-generics.

Jednak wiele metod z klasy Class nie ma sensu dla typów pierwotnych. Na przykład niemożliwe jest, aby obiekt był instanceof int. Dlatego analogiczna metoda .isInstance() zawsze zwróci false. Ponieważ parametr tej metody jest typu Object, z punktu widzenia języka jest po prostu niemożliwe, aby to, co tam przekazałeś, było typu pierwotnego.

Jasne, Java 5+ kiedy przechodzą prymitywne do parametru typu Object, ulega autoboxing, ale fakt, że przeszedł autoboxing oznacza że to, co zostało przekazane w rzeczywistości jest odniesienie do obiektu. Typy referencyjne i typy pierwotne są różne. Parametr jest typem referencyjnym lub typem pierwotnym. W związku z tym nie można napisać metody, która może przyjąć "referencję lub prymityw".

W twoim przykładzie możesz zadać pytanie, czy obiekt był automatyczny z prymitywu i porównać go z typem pierwotnym. Jednak nie jest możliwe wykrycie, czy osoba dzwoniąca wykonała autoboxing, ponieważ autoboxing to operacja całkowicie wywołująca połączenie, która ma miejsce przed wywołaniem.

Jednak zakładając, że był on autoboxed, wiesz, do jakiego typu powinien był. Jeśli spodziewasz się int, i jest on autoboxed i przekazywane do twojej metody, to powinno być instancją Integer.Tak więc, co można zrobić, gdy clazz reprezentuje typ pierwotny, zamiast tego wykonaj sprawdzenie jego klasy opakowania. Tak więc, gdy widzi, że clazz jest int.class, należy go zastąpić przez Integer.class, a następnie wykonać kontrolę. Zauważ, że w ten sposób nadal nie wiadomo, co zostało przekazane jako parametr o.

+0

Zrobiłem kilka badań, wydaje się, że nie ma ogólnej metody, aby uzyskać klasę opakowania typu pierwotnego lub ogólny sposób na uzyskanie pola TYPE klasy otoki. Chyba muszę mocno zakodować mapę i wykonać na niej odnośnik. – mike

+1

@mike Jeśli używasz Guava, obsługuje klasę ['Prymitywne'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/primitives/Primitives.html) te przypadki użycia już. –

+0

Dzięki, ale metody guawy opierają się również na mapach zakodowanych na sztywno. W każdym razie, świetne odpowiedzi i komentarze tutaj, wiele się nauczyłem! – mike

2

W języku Java nie ma klasy int. Jego klasa Integer. 7 jest konwertowane na Integer.valueOf(7), a int.class zostanie przekonwertowane na Integer.class zgodnie z JLS.

Jeśli p to nazwa prymitywny typ, niech B być type wypowiedzi typu p po konwersji boksu. Następnie typ z .

Od Integer jest obiektem klasy, a int jest typem pierwotnym. Tak więc większość metod z Class, takich jak isInstance, isAssignableFrom itp., Które działają na obiektach, jest nieważnych w kontekście int.class, dlatego widzisz tę sprzeczność.

check(Integer.class, 7); 

powinien dać oczekiwany wynik.

+0

Używam formularza metody sprawdzania w kontekście ustawnika generycznego, w którym wyodrębniam informacje o typie z atrybutu, aby ustawić i porównać go z typem parametru ustawiającego. Więc powinienem zabronić typom pierwotnym atrybutów, które chcę ustawić? – mike

+0

Byłoby użyteczne pokazanie kodu dla tego generycznego ustawiacza. Jeśli jest to podobne do ' void setSomething (T theThing)', nie będziesz w stanie bezpośrednio używać prymitywów - zawsze będą one autoboxed, ponieważ typy ogólne mogą być tylko obiektami, nigdy prymitywami. – BeeOnRope

+0

Możesz zobaczyć kod w innym pytaniu, które zadałem na SO http://stackoverflow.com/questions/16225623/how-to-avoid-getters- setters-inasses-with-many-instance-variables – mike

Powiązane problemy