निम्नलिखित में से कौन बेहतर है?
a instanceof B
या
B.class.isAssignableFrom(a.getClass())
एकमात्र अंतर जो मुझे पता है, जब 'ए' शून्य है, पहला गलत है, जबकि दूसरा अपवाद फेंकता है। इसके अलावा, क्या वे हमेशा एक ही परिणाम देते हैं?
निम्नलिखित में से कौन बेहतर है?
a instanceof B
या
B.class.isAssignableFrom(a.getClass())
एकमात्र अंतर जो मुझे पता है, जब 'ए' शून्य है, पहला गलत है, जबकि दूसरा अपवाद फेंकता है। इसके अलावा, क्या वे हमेशा एक ही परिणाम देते हैं?
जवाबों:
उपयोग करते समय instanceof
, आपको B
संकलन समय पर कक्षा को जानना होगा । उपयोग करते समय isAssignableFrom()
यह गतिशील हो सकता है और रनटाइम के दौरान बदल सकता है।
a instanceof Bref.getClass()
। यह इतने कम स्पष्टीकरण (या इसके अभाव) के साथ स्वीकृत उत्तर कैसे हो सकता है?
a instanceof Bref
नहीं है a instanceof Bref.class
। इंस्टाफॉपर ऑपरेटर का दूसरा तर्क एक वर्ग का नाम है, न कि क्लास ऑब्जेक्ट उदाहरण के लिए हल करने वाला एक अभिव्यक्ति।
B.class.isAssignableFrom(a.getClass())
, बी ज्ञात है, और a instanceof B
बेहतर है। सही?
instanceof
केवल संदर्भ प्रकारों के साथ उपयोग किया जा सकता है, न कि आदिम प्रकारों के साथ। isAssignableFrom()
किसी भी वर्ग की वस्तुओं के साथ इस्तेमाल किया जा सकता है:
a instanceof int // syntax error
3 instanceof Foo // syntax error
int.class.isAssignableFrom(int.class) // true
देख http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) ।
प्रदर्शन के संदर्भ में बात करना:
टी एल; डॉ
उपयोग isInstance या instanceof जो इसी तरह के प्रदर्शन की है। isAignignableFrom थोड़ा धीमा है।
प्रदर्शन द्वारा क्रमबद्ध:
JAVA 8 विंडोज x64 पर 2000 पुनरावृत्तियों के एक बेंचमार्क के आधार पर, 20 वार्मअप पुनरावृत्तियों के साथ।
सिद्धांत रूप में
एक नरम जैसे बायटेकोड दर्शक का उपयोग करके हम प्रत्येक ऑपरेटर को बायटेकोड में अनुवाद कर सकते हैं।
के संदर्भ में:
package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
जावा:
b instanceof A;
बाईटकोड:
getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
जावा:
A.class.isInstance(b);
बाईटकोड:
ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Class isInstance((Ljava/lang/Object;)Z);
जावा:
A.class.isAssignableFrom(b.getClass());
बाईटकोड:
ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Object getClass(()Ljava/lang/Class;);
invokevirtual java/lang/Class isAssignableFrom((Ljava/lang/Class;)Z);
मापने कितने बाईटकोड निर्देश प्रत्येक ऑपरेटर द्वारा उपयोग किया जाता है, हम उम्मीद कर सकता है instanceof और isInstance तुलना में तेजी से होने की isAssignableFrom । हालाँकि, वास्तविक प्रदर्शन बाईटेकोड द्वारा नहीं बल्कि मशीन कोड (जो कि प्लेटफॉर्म पर निर्भर है) द्वारा निर्धारित किया जाता है। प्रत्येक ऑपरेटर के लिए एक माइक्रो बेंचमार्क करते हैं।
बेंचमार्क
क्रेडिट: जैसा कि @ aleksandr-dubinsky द्वारा सलाह दी गई है, और आधार कोड प्रदान करने के लिए @yura को धन्यवाद, यहाँ एक है JMH बेंचमार्क है (यह ट्यूनिंग गाइड देखें ):
class A {}
class B extends A {}
public class Benchmark {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(TestPerf2.class.getSimpleName())
.warmupIterations(20)
.measurementIterations(2000)
.forks(1)
.build();
new Runner(opt).run();
}
}
निम्नलिखित परिणाम दिए (स्कोर है एक समय इकाई में कई ऑपरेशन हैं , इसलिए स्कोर जितना अधिक होगा):
Benchmark Mode Cnt Score Error Units
Benchmark.testIsInstance thrpt 2000 373,061 ± 0,115 ops/us
Benchmark.testInstanceOf thrpt 2000 371,047 ± 0,131 ops/us
Benchmark.testIsAssignableFrom thrpt 2000 363,648 ± 0,289 ops/us
चेतावनी
instanceof
के संबंध में, आपके कोड के संदर्भ में isInstance
उदाहरण के लिए अधिक आसानी से अनुकूलित किया जा सकता है ...आपको एक उदाहरण देने के लिए, निम्नलिखित लूप लें:
class A{}
class B extends A{}
A b = new B();
boolean execute(){
return A.class.isAssignableFrom(b.getClass());
// return A.class.isInstance(b);
// return b instanceof A;
}
// Warmup the code
for (int i = 0; i < 100; ++i)
execute();
// Time it
int count = 100000;
final long start = System.nanoTime();
for(int i=0; i<count; i++){
execute();
}
final long elapsed = System.nanoTime() - start;
JIT के लिए धन्यवाद, कुछ बिंदु पर कोड को अनुकूलित किया गया है और हम प्राप्त करते हैं:
ध्यान दें
मूल रूप से यह पोस्ट कच्चे JAVA में लूप के लिए अपने स्वयं के बेंचमार्क का उपयोग कर रही थी , जिसने अविश्वसनीय परिणाम दिए जैसे कि जस्ट इन टाइम जैसे लूप को खत्म कर सकता है। इसलिए यह ज्यादातर माप रहा था कि लूप का अनुकूलन करने के लिए जेआईटी कंपाइलर को कितनी देर लगी: प्रदर्शन परीक्षण को पुनरावृत्तियों की संख्या से स्वतंत्र देखें अधिक विवरण के लिए देखें
संबंधित सवाल
instanceof
एक बाईटेकोड है जो अनिवार्य रूप से उसी तर्क का उपयोग करता है checkcast
(कास्टिंग के पीछे बायटेकोड)। यह JITC अनुकूलन की डिग्री की परवाह किए बिना, अन्य विकल्पों की तुलना में स्वाभाविक रूप से तेज़ होगा।
isAssignableFrom()
कि गतिशील है।
के बराबर अधिक प्रत्यक्ष a instanceof B
है
B.class.isInstance(a)
यह काम करता है (रिटर्न गलत) जब a
है null
भी।
ऊपर उल्लिखित बुनियादी अंतरों के अलावा, Instof ऑपरेटर और isAssignableFrom विधि के बीच कक्षा में एक मुख्य सूक्ष्म अंतर है।
पढ़ें instanceof
के रूप में "यह (बाएं भाग) है (दाएं भाग) इस बात का उदाहरण है या इस से किसी उपवर्ग" और पढ़ने x.getClass().isAssignableFrom(Y.class)
के रूप में "कर सकते हैं मैं लिखने X x = new Y()
"। दूसरे शब्दों में, उदाहरण के लिए ऑपरेटर यह जाँचता है कि यदि बाईं वस्तु समान है या दाएं वर्ग का उपवर्ग है, जबकि यह isAssignableFrom
जांचता है कि क्या हम उस वर्ग के संदर्भ में पैरामीटर वर्ग (से) की वस्तु को असाइन कर सकते हैं जिस पर विधि को कहा जाता है।
ध्यान दें कि ये दोनों वास्तविक उदाहरण को संदर्भ प्रकार नहीं मानते हैं।
3 वर्गों ए, बी और सी के उदाहरण पर विचार करें जहां सी का विस्तार बी और बी का विस्तार ए है।
B b = new C();
System.out.println(b instanceof A); //is b (which is actually class C object) instance of A, yes. This will return true.
System.out.println(b instanceof B); // is b (which is actually class C object) instance of B, yes. This will return true.
System.out.println(b instanceof C); // is b (which is actually class C object) instance of C, yes. This will return true. If the first statement would be B b = new B(), this would have been false.
System.out.println(b.getClass().isAssignableFrom(A.class));//Can I write C c = new A(), no. So this is false.
System.out.println(b.getClass().isAssignableFrom(B.class)); //Can I write C c = new B(), no. So this is false.
System.out.println(b.getClass().isAssignableFrom(C.class)); //Can I write C c = new C(), Yes. So this is true.
b instanceof A
A.class.isAssignableFrom(b.getClass())
(ओपी के रूप में देखा) के बराबर है । आपका उदाहरण सही है लेकिन अप्रासंगिक है।
new Y()
कानूनी नहीं है अगर Y
अमूर्त है या सार्वजनिक डिफ़ॉल्ट निर्माता के बिना है, तो आप कह सकते हैं X x = (Y)null
कि कानूनी है और अगर केवल x.getClass().isAssignableFrom(Y.class)
सच है।
एक और अंतर भी है:
null उदाहरण X false
कोई बात नहीं X क्या है
null.getClass () .AssignableFrom (X) NullPointerException को फेंक देगा
null instanceof X
(जहां X संकलन के समय ज्ञात कुछ वर्ग है) हमेशा वापस आ जाएगा false
।
X.class.isAssignableFrom(null.getClass())
चाहिए? लेकिन हां, getClass()
एक शून्य संदर्भ पर कॉल करने के परिणामस्वरूप NPE होगा।
getClass()
साथ उपयोग नहीं किया जाना चाहिए isAssignableFrom
- ऑपरेशन का मतलब वस्तुओं के न होने की स्थिति के लिए है। आप ऑब्जेक्ट संदर्भ है, तो a
, उपयोग a instanceof SomeClass
(यदि आप ऐसा प्रकार पता SomeClass
) या someObject.getClass().isInstance(a)
(यदि आप नहीं करते हैं के प्रकार पता someObject
)।
अभी एक और अंतर है। यदि परीक्षण करने के लिए टाइप (क्लास) गतिशील है, उदाहरण के लिए एक विधि पैरामीटर के रूप में पारित किया गया है, तो उदाहरण के लिए यह आपके लिए कटौती नहीं करेगा।
boolean test(Class clazz) {
return (this instanceof clazz); // clazz cannot be resolved to a type.
}
लेकिन आप कर सकते हैं:
boolean test(Class clazz) {
return (clazz.isAssignableFrom(this.getClass())); // okidoki
}
उफ़, मैं देख रहा हूं कि यह उत्तर पहले से ही कवर है। हो सकता है कि यह उदाहरण किसी के लिए सहायक हो।
this
) है, clazz.isInstance(this)
आपके उदाहरण में बेहतर होगा।
इस धागे ने मुझे कुछ जानकारी प्रदान की कि कैसे इससे instanceof
अलग हुआisAssignableFrom
कि मैं इससे हूं, इसलिए मैंने सोचा कि मैं अपना खुद का कुछ साझा करूंगा।
मैंने पाया है कि उपयोग करना isAssignableFrom
केवल स्वयं करने के लिए (शायद एकमात्र नहीं, बल्कि संभवतः सबसे आसान) तरीका है कि किसी व्यक्ति का स्वयं से पूछें कि क्या एक वर्ग का संदर्भ दूसरे का उदाहरण ले सकता है, जब किसी के पास तुलना करने के लिए न तो कक्षा के उदाहरण हैं।
इसलिए, instanceof
जब तक मेरे पास सभी वर्ग नहीं थे, तब तक मैं एक अच्छा विचार होने के लिए असाइनमेंट की तुलना करने के लिए ऑपरेटर का उपयोग नहीं कर पाया , जब तक कि मैंने कक्षाओं में से एक से एक उदाहरण बनाने पर विचार नहीं किया; मुझे लगा कि यह टेढ़ा होगा।
Instof का उपयोग आदिम प्रकार या सामान्य प्रकार के साथ नहीं किया जा सकता है। निम्नलिखित कोड के रूप में:
//Define Class< T > type ...
Object e = new Object();
if(e instanceof T) {
// Do something.
}
त्रुटि यह है: टाइप पैरामीटर के खिलाफ इंस्टाफॉफ़ चेक नहीं किया जा सकता। टी। इसके बजाय एरेस ऑब्जेक्ट का उपयोग करें क्योंकि आगे सामान्य प्रकार की जानकारी रनटाइम पर मिटा दी जाएगी।
रनटाइम संदर्भ को हटाने के प्रकार के क्षरण के कारण संकलन नहीं करता है। हालाँकि, नीचे दिया गया कोड संकलित होगा:
if( type.isAssignableFrom(e.getClass())){
// Do something.
}
निम्नलिखित स्थिति पर विचार करें। मान लीजिए कि आप जांचना चाहते हैं कि टाइप ए ओबज के प्रकार का एक सुपर क्लास है, तो आप जा सकते हैं
... A.class.isAssignableFrom (obj.getClass ()) ...
या
... obj उदाहरण ए ...
लेकिन isAssignableFrom समाधान के लिए आवश्यक है कि obj का प्रकार यहाँ दिखाई दे। यदि यह मामला नहीं है (उदाहरण के लिए, obj का प्रकार एक निजी आंतरिक वर्ग का हो सकता है), यह विकल्प बाहर है। हालांकि, इंस्टोफ़ समाधान हमेशा काम करेगा।
obj
इस उदाहरण में) का एक गैर-शून्य संदर्भ है तो आप कार्यान्वयन वर्ग के लिए प्रतिबिंब मेटाडेटा प्राप्त करने के लिए उस पर सार्वजनिक विधि को कॉल कर सकते हैं । यह तब भी सच है जब कि संकलन के समय उस स्थान पर वर्ग प्रकार लागू करना कानूनी रूप से दिखाई नहीं देगा। यह रनटाइम पर ठीक है क्योंकि, आपके पास संदर्भ रखने के लिए , कुछ कोड पथ जो अंततः कक्षा तक कानूनी पहुंच रखता था और आपको इसे लीक (लीक) कर दिया था। getClass()
obj
isAssignableFrom(A, B) =
if (A == B) return true
else if (B == java.lang.Object) return false
else return isAssignableFrom(A, getSuperClass(B))
ऊपर दिया गया छद्म कोड एक परिभाषा है, यदि प्रकार / वर्ग ए का संदर्भ प्रकार / वर्ग बी के संदर्भ से उपलब्ध है। यह एक पुनरावर्ती परिभाषा है। कुछ के लिए यह उपयोगी हो सकता है, दूसरों के लिए यह भ्रामक हो सकता है। मैं इसे उस स्थिति में जोड़ता हूं जब किसी को यह उपयोगी लगे। यह सिर्फ मेरी समझ को पकड़ने की कोशिश है, यह आधिकारिक परिभाषा नहीं है। यह एक निश्चित जावा वीएम कार्यान्वयन में उपयोग किया जाता है और कई उदाहरण कार्यक्रमों के लिए काम करता है, इसलिए जब तक मैं यह नहीं समझ सकता कि यह isAignignableFrom के सभी पहलुओं को पकड़ लेता है, यह पूरी तरह से बंद नहीं है।
प्रदर्शन के संदर्भ में बात करते हुए "2" (JMH के साथ):
class A{}
class B extends A{}
public class InstanceOfTest {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(InstanceOfTest.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(5)
.forks(1)
.build();
new Runner(opt).run();
}
}
यह देता है:
Benchmark Mode Cnt Score Error Units
InstanceOfTest.testInstanceOf avgt 5 1,972 ? 0,002 ns/op
InstanceOfTest.testIsAssignableFrom avgt 5 1,991 ? 0,004 ns/op
InstanceOfTest.testIsInstance avgt 5 1,972 ? 0,003 ns/op
ताकि हम निष्कर्ष निकाल सकें: उदाहरण के रूप में उपवास के रूप में isInstance () और isAssignableFrom () दूर नहीं (+ 0.9% निष्पादन समय)। इसलिए कोई भी वास्तविक अंतर नहीं है जो भी आप चुनते हैं
इसे एक्शन में दिखाने के लिए कुछ उदाहरणों के बारे में ...
@Test
public void isInstanceOf() {
Exception anEx1 = new Exception("ex");
Exception anEx2 = new RuntimeException("ex");
RuntimeException anEx3 = new RuntimeException("ex");
//Base case, handles inheritance
Assert.assertTrue(anEx1 instanceof Exception);
Assert.assertTrue(anEx2 instanceof Exception);
Assert.assertTrue(anEx3 instanceof Exception);
//Other cases
Assert.assertFalse(anEx1 instanceof RuntimeException);
Assert.assertTrue(anEx2 instanceof RuntimeException);
Assert.assertTrue(anEx3 instanceof RuntimeException);
}
@Test
public void isAssignableFrom() {
Exception anEx1 = new Exception("ex");
Exception anEx2 = new RuntimeException("ex");
RuntimeException anEx3 = new RuntimeException("ex");
//Correct usage = The base class goes first
Assert.assertTrue(Exception.class.isAssignableFrom(anEx1.getClass()));
Assert.assertTrue(Exception.class.isAssignableFrom(anEx2.getClass()));
Assert.assertTrue(Exception.class.isAssignableFrom(anEx3.getClass()));
//Incorrect usage = Method parameter is used in the wrong order
Assert.assertTrue(anEx1.getClass().isAssignableFrom(Exception.class));
Assert.assertFalse(anEx2.getClass().isAssignableFrom(Exception.class));
Assert.assertFalse(anEx3.getClass().isAssignableFrom(Exception.class));
}
हमारी टीम में किए गए कुछ परीक्षण बताते हैं कि इससे A.class.isAssignableFrom(B.getClass())
अधिक तेजी से काम होता है B instanceof A
। यह बहुत उपयोगी हो सकता है यदि आपको बड़ी संख्या में तत्वों की जांच करने की आवश्यकता हो।
instanceof
, तो मेरा मानना है कि आपको गंभीर डिजाइन की समस्याएं हैं ...