instance of와 Class.isAssignableFrom(...)의 차이점은 무엇입니까?
다음 중 어느 것이 더 좋습니까?
a instanceof B
또는
B.class.isAssignableFrom(a.getClass())
제가 아는 유일한 차이점은 'a'가 늘일 경우 첫 번째가 false를 반환하고 두 번째가 예외를 발생시킨다는 것입니다.그 외에는 항상 같은 결과를 얻을 수 있습니까?
「」를 사용하고 instanceof를 알아야 B★★★★★★★★★★를 사용하는 경우isAssignableFrom()동적이며 런타임 중에 변경될 수 있습니다.
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) 를 참조해 주세요.
퍼포먼스 측면에서의 설명:
TL;DR
유사한 성능을 가진 isInstance 또는 인스턴스를 사용합니다.isAssignableFrom은 약간 느립니다.
퍼포먼스별 정렬:
- 인스턴스
- 인스턴스(+0.5%)
- isAssignableFrom(+2.7%)
JAVA 8 Windows x 64 에서의 2,000회의 반복 벤치마크에 근거해, 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);
각 연산자가 사용하는 바이트 코드 명령의 수를 측정하면 isAssignableFrom보다 instance of 및 isInstance가 더 빠를 것으로 예상할 수 있습니다.그러나 실제 성능은 바이트 코드가 아니라 머신 코드(플랫폼에 따라 다름)에 따라 결정됩니다.각 연산자에 대해 마이크로 벤치마크를 실시합니다.
벤치마크
크레딧: @alexandr-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
경고
- 벤치마크는 JVM 및 플랫폼에 의존합니다.각 조작에 큰 차이가 없기 때문에 Solaris, Mac, Linux 등의 다른 Java 버전 및/또는 플랫폼에서 다른 결과(및 순서가 다를 수 있습니다!)를 얻을 수 있습니다.
- 벤치마크는 "B extension A"가 직접 사용될 때 "B가 A의 인스턴스인가"의 성능을 비교합니다.클래스 계층이 더 깊고 복잡할 경우(B가 X를 확장하면 Y가 확장되고 Z가 확장되면 A가 확장됨) 결과는 다를 수 있습니다.
- 보통 코드를 먼저 작성하고 (가장 편리한) 연산자 중 하나를 선택한 후 코드 프로파일을 작성하여 성능 병목 현상이 있는지 확인하는 것이 좋습니다.이 연산자는 코드상 무시해도 될 정도일 수도 있고...
- 점에
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 덕분에 코드는 어느 시점에서 최적화되어 다음과 같은 이점을 얻을 수 있습니다.
- 인스턴스 수: 6 ms
- isInstance: 12ms
- isAssignableFrom : 15ms
메모
원래 이 게시물은 원시 JAVA에서 for 루프를 사용하여 자체 벤치마크를 수행했는데, Just In Time과 같은 최적화로 루프를 제거할 수 있기 때문에 신뢰할 수 없는 결과를 얻었습니다.JIT 컴파일러가 루프를 최적화하는 데 걸리는 시간을 측정하는 것이 대부분이었습니다.자세한 내용은 반복 횟수에 관계없이 퍼포먼스 테스트를 참조하십시오.
관련 질문
- instance of 연산자가 많은 오버헤드를 생성합니까? 이유는 무엇입니까?
- JAVA 내부에서는 인스턴스(instance)를 참조해 주세요.
- Java에서 인스턴스 사용이 성능에 미치는 영향
a instanceof B하고 있다
B.class.isInstance(a)
이것은, 다음의 경우에 기능합니다(false 반환).anull
위에서 설명한 기본적인 차이 외에 클래스의 instance of operator와 isAssignableFrom 메서드 사이에는 핵심적인 미묘한 차이가 있습니다.
★★★★★★★★★를 읽어 주세요.instanceof입니까, 이()의 서브클래스의 인스턴스입니까?'라고 말하고, '이(는)는(는) 아(는) 아(는) 아(는)아(는) 아(는)로 읽습니다.라고 말하고 읽습니다.x.getClass().isAssignableFrom(Y.class)라고 쓰면 되나요?X x = new Y()한지 여부를 하고, instance of operator는 instance of operator가 오른쪽 클래스의 서브클래스를 체크합니다.isAssignableFrom는 메서드가 호출된 클래스의 참조에 파라미터 클래스의 오브젝트(from)를 할당할 수 있는지 여부를 확인합니다.
둘 다 참조 유형이 아닌 실제 인스턴스를 고려한다는 점에 유의하십시오.
C가 B를 확장하고 B가 A를 확장하는 3개의 클래스 A, B 및 C의 예를 생각해 봅시다.
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.
또 다른 차이점도 있습니다.
X 인스턴스는 X' null입니다.false가 어떤
null.getClass().isAssignableFrom(X)은 NullPointer를 슬로우합니다.예외.
또 다른 차이가 있다.테스트 대상 유형(클래스)이 메서드 매개 변수로 전달되는 등 동적인 경우 instanceof는 이를 잘라내지 않습니다.
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
}
아, 이 답변은 이미 기재되어 있군요.아마도 이 예가 누군가에게 도움이 될 것이다.
해야 할지 알 수 있었다.instanceof는 isAssignableFrom그래서 저만의 무언가를 공유하려고 했어요.
나는 그것을 사용하여 발견했다.isAssignableFrom비교 대상이 되는 클래스가 없는 경우, 한 클래스의 참조가 다른 클래스의 인스턴스를 취할 수 있는지 여부를 자문할 수 있는 유일한 방법(유일한 방법은 아니지만 아마도 가장 쉬운 방법)이다.
때문에 저는 '아까', '아까', 'I/O'를 instanceof오퍼레이터는 클래스 중 하나에서 인스턴스를 만드는 것을 고려하지 않는 한, 내가 가진 모든 것이 클래스일 때 할당성을 비교하는 것이 좋은 아이디어입니다.저는 이것이 엉성하다고 생각했습니다.
instance of는 원시 유형이나 일반 유형에도 사용할 수 없습니다.다음 코드와 같습니다.
//Define Class< T > type ...
Object e = new Object();
if(e instanceof T) {
// Do something.
}
오류: 유형 매개 변수 T에 대해 인스턴스 오브 체크를 수행할 수 없습니다.실행 시 추가 일반 유형 정보가 지워지므로 대신 해당 삭제 개체를 사용하십시오.
형식 삭제로 인해 컴파일되지 않으며 런타임 참조가 제거됩니다.다만, 다음의 코드는 컴파일 됩니다.
if( type.isAssignableFrom(e.getClass())){
// Do something.
}
다음 상황을 고려해보세요.타입 A가 타입의 obj의 슈퍼 클래스인지 아닌지를 체크하는 경우는, 다음의 어느쪽인가를 실행할 수 있습니다.
... A.class.isAssignableFrom(obj.getClass())...
또는
... A의 obj 인스턴스...
그러나 isAssignableFrom 솔루션에서는 여기서 obj 유형을 확인할 수 있어야 합니다.그렇지 않은 경우(예를 들어 obj 유형이 개인 내부 클래스일 수 있음), 이 옵션은 제외됩니다.그러나 솔루션의 인스턴스는 항상 작동합니다.
isAssignableFrom(A, B) =
if (A == B) return true
else if (B == java.lang.Object) return false
else return isAssignableFrom(A, getSuperClass(B))
위의 의사 코드는 유형/클래스 A의 참조가 유형/클래스 B의 참조에서 할당 가능한 경우 정의입니다.이것은 재귀적 정의입니다.어떤 사람에게는 도움이 될 수도 있고 어떤 사람에게는 혼란스러울 수도 있습니다.누군가 유용하다고 생각할 때를 대비해서 덧붙입니다.이것은 단지 나의 이해를 얻기 위한 시도일 뿐, 공식적인 정의는 아닙니다.특정 Java VM 구현에서 사용되며 많은 예제 프로그램에서 작동하기 때문에 isAssignableFrom의 모든 측면을 캡처할 수는 없지만 완전히 꺼진 것은 아닙니다.
퍼포먼스 「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()의 instance는 멀지 않은 곳에 있습니다(+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. 이것은 많은 요소에서 체크해야 하는 경우에 매우 유용합니다.
언급URL : https://stackoverflow.com/questions/496928/what-is-the-difference-between-instanceof-and-class-isassignablefrom
'programing' 카테고리의 다른 글
| 대신 프로펠러 값을 기반으로 데이터 또는 계산된 속성을 사용하십시오.Vue JS (0) | 2022.07.18 |
|---|---|
| 슈퍼 하이 퍼포먼스 C/C++ 해시 맵(표, 사전) (0) | 2022.07.18 |
| TypeScript를 사용하여 Vue 컴포넌트를 프로그래밍 방식으로 생성합니다. (0) | 2022.07.17 |
| v-model이 jQuery 트리거 이벤트의 변경 사항을 감지하지 못함 (0) | 2022.07.17 |
| 유형 'Vue'에 속성 'x'가 없습니다. (0) | 2022.07.17 |