webentwicklung-frage-antwort-db.com.de

Die Auswirkungen der Verwendung von instanceof in Java auf die Leistung

Ich arbeite an einer Anwendung, und bei einem Entwurfsansatz wird der Operator instanceof sehr häufig verwendet. Ich weiß zwar, dass OO Design im Allgemeinen versucht, die Verwendung von instanceof zu vermeiden, dies ist jedoch eine andere Geschichte, und diese Frage bezieht sich lediglich auf die Leistung. Ich habe mich gefragt, ob es Auswirkungen auf die Leistung gibt. Ist genauso schnell wie ==?

Zum Beispiel habe ich eine Basisklasse mit 10 Unterklassen. In einer einzigen Funktion, die die Basisklasse übernimmt, prüfe ich, ob die Klasse eine Instanz der Unterklasse ist, und führe eine Routine aus. 

Eine der anderen Möglichkeiten, an die ich dachte, um es zu lösen, war die Verwendung eines ganzzahligen Primitivtyps "type id" und die Verwendung einer Bitmaske zur Darstellung der Kategorien der Unterklassen. Anschließend wurde nur ein Bitmaskenvergleich der Unterklassen "type id" mit a durchgeführt Konstante Maske, die die Kategorie darstellt.

Ist instanceof irgendwie von der JVM optimiert, um schneller zu sein? Ich möchte an Java festhalten, aber die Leistung der App ist kritisch. Es wäre cool, wenn jemand, der schon einmal auf dieser Straße war, Ratschläge geben könnte. Bin ich zu sehr pingelig oder konzentriere mich auf das Falsche, um es zu optimieren?

282
Josh

Moderne JVM/JIC-Compiler haben die Leistungseinbußen der meisten "langsamen" Operationen, einschließlich Instanz, Ausnahmebehandlung, Reflektion usw., beseitigt.

Wie Donald Knuth schrieb: "Wir sollten kleine Wirkungsgrade vergessen, sagen 97% der Zeit: vorzeitige Optimierung ist die Wurzel allen Übels." Die Leistung von instanceof ist wahrscheinlich kein Problem. Verschwenden Sie also keine Zeit mit exotischen Workarounds, bis Sie sicher sind, dass dies das Problem ist.

246
Steve

Ansatz

Ich schrieb ein Benchmark-Programm , um verschiedene Implementierungen zu bewerten:

  1. instanceof Implementierung (als Referenz) 
  2. objektorientiert über eine abstrakte Klasse und @Override eine Testmethode
  3. mit einer eigenen Implementierung
  4. getClass() == _.class Implementierung

Ich habe jmh verwendet, um den Benchmark mit 100 Warmup-Aufrufen, 1000 Iterationen unter Messung und mit 10 Gabeln auszuführen. Jede Option wurde also mit 10.000 gemessen, was die Ausführung des gesamten Benchmarks auf meinem MacBook Pro mit Mac OS 10.12.4 und Java 1.8 um 12:18:57 dauert. Der Benchmark misst die durchschnittliche Zeit jeder Option. Für weitere Details siehe meine Implementierung auf GitHub

Der Vollständigkeit halber: Es gibt eine vorherige Version dieser Antwort und meinen Benchmark

Ergebnisse

 | Bedienung | Laufzeit in Nanosekunden pro Operation | Relativ zu Instanz von | 
 | ------------ | ----------------------------- --------- | ------------------------ | 
 | INSTANCEOF | 39,598 ± 0,022 ns/op 100,00% | 
 | GETCLASS | 39,687 ± 0,021 ns/op | 100,22% | 
 | TYP | 46,295 ± 0,026 ns/op | 116,91% | 
 | OO | 48,078 ± 0,026 ns/op | 121,42% | 

tl; dr

In Java 1.8 ist instanceof der schnellste Ansatz, obwohl getClass() sehr nahe ist. 

230
Michael Dorner

Ich habe gerade einen einfachen Test gemacht, um zu sehen, wie die Leistung von instanceOf mit einem einfachen Aufruf von equival () eines String-Objekts mit nur einem Buchstaben verglichen wird.

in einer 10.000.000-Schleife hat die InstanzOf mir 63-96 ms und die Saite 106-230 ms ergeben

Ich habe Java jvm 6 verwendet.

In meinem einfachen Test ist es also schneller, eine Instanz von statt eines Zeichenkettenvergleichs durchzuführen.

die Verwendung von .Equals () von Integer anstelle von Zeichenfolgen führte zu demselben Ergebnis, nur wenn ich die == verwendete.

72
Dan Mihai Ile

Die Elemente, die die Auswirkungen auf die Leistung bestimmen, sind:

  1. Die Anzahl der möglichen Klassen, für die der Instanz des Operators "true" zurückgeben kann
  2. Die Verteilung Ihrer Daten - werden die meisten Operationen im ersten oder zweiten Versuch gelöst? Sie sollten Ihre wahrscheinlichen Operationen zuerst setzen.
  3. Die Implementierungsumgebung Die Ausführung unter Sun Solaris VM unterscheidet sich erheblich von der Windows-JVM von Sun. Solaris wird standardmäßig im Server-Modus ausgeführt, während Windows im Client-Modus ausgeführt wird. Durch die JIT-Optimierungen unter Solaris können alle Methoden gleich aufgerufen werden. 

Ich habe ein Mikrobankmark für vier verschiedene Versandarten erstellt . Die Ergebnisse von Solaris lauten wie folgt, wobei die kleinere Anzahl schneller ist:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 
17
brianegge

Beantwortung Ihrer letzten Frage: Wenn Ihnen nicht ein Profiler mitteilt, verbringen Sie lächerliche Zeit in einer Instanz von: Ja, Sie sind blödsinnig.

Bevor Sie sich fragen, ob etwas optimiert werden muss, das nicht optimiert werden musste: Schreiben Sie Ihren Algorithmus auf die am besten lesbare Weise und führen Sie ihn aus. Führen Sie es aus, bis der Jit-Compiler die Möglichkeit hat, ihn selbst zu optimieren. Wenn Sie dann Probleme mit diesem Code haben, verwenden Sie einen Profiler, um Ihnen mitzuteilen, wo Sie am meisten gewinnen können, und optimieren Sie dies.

In Zeiten von stark optimierenden Compilern werden Ihre Vermutungen über Engpässe wahrscheinlich völlig falsch sein.

Und im wahren Sinn dieser Antwort (an die ich von ganzem Herzen glaube): Ich weiß absolut nicht, wie sich Instanz und == beziehen, sobald der Jit-Compiler die Chance hatte, sie zu optimieren.

Ich habe vergessen: Niemals den ersten Lauf messen.

16
Olaf Kock

Ich habe dieselbe Frage, aber da ich keine Leistungskennzahlen für einen ähnlichen Anwendungsfall wie ich gefunden habe, habe ich etwas mehr Beispielcode erstellt. Auf meiner Hardware und Java 6 & 7 besteht der Unterschied zwischen instanceof und switch bei 10mln-Iterationen

for 10 child classes - instanceof: 1200ms vs switch: 470ms
for 5 child classes  - instanceof:  375ms vs switch: 204ms

Instanceof ist also sehr viel langsamer, insbesondere bei einer großen Anzahl von if-else-if-Anweisungen. Allerdings ist der Unterschied in der realen Anwendung vernachlässigbar.

import Java.util.Date;

public class InstanceOfVsEnum {

    public static int c1, c2, c3, c4, c5, c6, c7, c8, c9, cA;

    public static class Handler {
        public enum Type { Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, TypeA }
        protected Handler(Type type) { this.type = type; }
        public final Type type;

        public static void addHandlerInstanceOf(Handler h) {
            if( h instanceof H1) { c1++; }
            else if( h instanceof H2) { c2++; }
            else if( h instanceof H3) { c3++; }
            else if( h instanceof H4) { c4++; }
            else if( h instanceof H5) { c5++; }
            else if( h instanceof H6) { c6++; }
            else if( h instanceof H7) { c7++; }
            else if( h instanceof H8) { c8++; }
            else if( h instanceof H9) { c9++; }
            else if( h instanceof HA) { cA++; }
        }

        public static void addHandlerSwitch(Handler h) {
            switch( h.type ) {
                case Type1: c1++; break;
                case Type2: c2++; break;
                case Type3: c3++; break;
                case Type4: c4++; break;
                case Type5: c5++; break;
                case Type6: c6++; break;
                case Type7: c7++; break;
                case Type8: c8++; break;
                case Type9: c9++; break;
                case TypeA: cA++; break;
            }
        }
    }

    public static class H1 extends Handler { public H1() { super(Type.Type1); } }
    public static class H2 extends Handler { public H2() { super(Type.Type2); } }
    public static class H3 extends Handler { public H3() { super(Type.Type3); } }
    public static class H4 extends Handler { public H4() { super(Type.Type4); } }
    public static class H5 extends Handler { public H5() { super(Type.Type5); } }
    public static class H6 extends Handler { public H6() { super(Type.Type6); } }
    public static class H7 extends Handler { public H7() { super(Type.Type7); } }
    public static class H8 extends Handler { public H8() { super(Type.Type8); } }
    public static class H9 extends Handler { public H9() { super(Type.Type9); } }
    public static class HA extends Handler { public HA() { super(Type.TypeA); } }

    final static int cCycles = 10000000;

    public static void main(String[] args) {
        H1 h1 = new H1();
        H2 h2 = new H2();
        H3 h3 = new H3();
        H4 h4 = new H4();
        H5 h5 = new H5();
        H6 h6 = new H6();
        H7 h7 = new H7();
        H8 h8 = new H8();
        H9 h9 = new H9();
        HA hA = new HA();

        Date dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerInstanceOf(h1);
            Handler.addHandlerInstanceOf(h2);
            Handler.addHandlerInstanceOf(h3);
            Handler.addHandlerInstanceOf(h4);
            Handler.addHandlerInstanceOf(h5);
            Handler.addHandlerInstanceOf(h6);
            Handler.addHandlerInstanceOf(h7);
            Handler.addHandlerInstanceOf(h8);
            Handler.addHandlerInstanceOf(h9);
            Handler.addHandlerInstanceOf(hA);
        }
        System.out.println("Instance of - " + (new Date().getTime() - dtStart.getTime()));

        dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerSwitch(h1);
            Handler.addHandlerSwitch(h2);
            Handler.addHandlerSwitch(h3);
            Handler.addHandlerSwitch(h4);
            Handler.addHandlerSwitch(h5);
            Handler.addHandlerSwitch(h6);
            Handler.addHandlerSwitch(h7);
            Handler.addHandlerSwitch(h8);
            Handler.addHandlerSwitch(h9);
            Handler.addHandlerSwitch(hA);
        }
        System.out.println("Switch of - " + (new Date().getTime() - dtStart.getTime()));
    }
}
12
Xtra Coder

instanceof ist sehr schnell und benötigt nur wenige CPU-Anweisungen.

Wenn eine Klasse X keine Unterklassen geladen hat (JVM weiß), kann instanceof anscheinend folgendermaßen optimiert werden:

     x instanceof X    
==>  x.getClass()==X.class  
==>  x.classID == constant_X_ID

Die Hauptkosten sind nur eine Lesung!

Wenn bei X Unterklassen geladen sind, sind einige weitere Lesevorgänge erforderlich. Sie befinden sich wahrscheinlich am selben Ort, so dass auch die zusätzlichen Kosten sehr niedrig sind.

Gute Nachrichten, Leute!

8
irreputable

instanceof wird in den meisten Real-World-Implementierungen wahrscheinlich teurer sein als ein einfaches Gleiches (das heißt, diejenigen, bei denen instanceof wirklich benötigt wird, und Sie können es nicht einfach lösen, indem Sie eine gängige Methode überschreiben, wie jedes Anfänger-Lehrbuch sowie Demian oben schlagen vor).

Warum das? Wahrscheinlich wird es passieren, dass Sie über mehrere Schnittstellen verfügen, die einige Funktionen bereitstellen (z. B. Schnittstellen x, y und z), und einige zu manipulierende Objekte, die eine dieser Schnittstellen (oder auch nicht) implementieren können, aber nicht direkt. Ich habe zum Beispiel gesagt:

w erweitert x

A implementiert w

B erstreckt sich um A

C erweitert B, implementiert y

D verlängert C, implementiert z

Angenommen, ich verarbeite eine Instanz von D, das Objekt d. Zum Berechnen (d instanceof von x) müssen Sie d.getClass () verwenden, die durchgeführten Schnittstellen durchlaufen, um zu wissen, ob x == ist, und wenn dies nicht der Fall ist, falls dies nicht der Fall ist, für alle ihre Vorfahren ....... In diesem Fall ergeben sich bei einer ersten Untersuchung dieses Baums mindestens acht Vergleiche, vorausgesetzt, y und z erweitern nichts.

Die Komplexität eines realen Ableitungsbaums ist wahrscheinlich höher. In einigen Fällen kann das JIT das meiste davon weg optimieren, wenn es in der Lage ist, d in allen möglichen Fällen eine Instanz von etwas aufzulösen, das x erweitert. Realistisch gesehen werden Sie jedoch meistens diese Baumdurchquerung durchlaufen.

Wenn dies zu einem Problem wird, würde ich vorschlagen, stattdessen eine Handler-Map zu verwenden, die konkrete Klasse des Objekts mit einem Abschluss zu verknüpfen, der die Behandlung übernimmt. Es entfernt die Baumdurchlaufphase zugunsten einer direkten Zuordnung. Beachten Sie jedoch, dass mein Objekt d oben nicht erkannt wird, wenn Sie einen Handler für C.class festgelegt haben.

hier sind meine 2 Cent, ich hoffe, sie helfen ...

5
Varkhan

instanceof ist sehr effizient, so dass es unwahrscheinlich ist, dass Ihre Leistung darunter leidet.

Wenn Sie xClass == String.class verwenden können, ist dies schneller. Hinweis: Für Abschlussklassen benötigen Sie keine Instanz.

4
Peter Lawrey

Demian und Paul erwähnen einen guten Punkt; jedoch , die Platzierung des auszuführenden Codes hängt wirklich davon ab, wie Sie die Daten verwenden möchten ...

Ich bin ein großer Fan von kleinen Datenobjekten, die auf viele Arten verwendet werden können. Wenn Sie dem Überschreibungsansatz (polymorph) folgen, können Ihre Objekte nur "Einweg" verwendet werden.

Hier kommen Muster in ...

Sie können double-dispatch (wie im Besuchermuster) verwenden, um jedes Objekt aufzufordern, sich selbst anzurufen, um den Typ des Objekts aufzulösen. Allerdings (wieder) benötigen Sie eine Klasse, die mit allen möglichen Untertypen "Sachen erledigen" kann.

Ich bevorzuge die Verwendung eines Strategiemusters, in dem Sie Strategien für jeden Subtyp registrieren können, den Sie behandeln möchten. Etwas wie das Folgende. Beachten Sie, dass dies nur für exakte Typübereinstimmungen hilfreich ist, aber den Vorteil hat, dass es erweiterbar ist - Drittanbieter können eigene Typen und Handler hinzufügen. (Dies ist gut für dynamische Frameworks wie OSGi, wo neue Bundles hinzugefügt werden können.)

Hoffentlich inspiriert das einige andere Ideen ...

package com.javadude.sample;

import Java.util.HashMap;
import Java.util.Map;

public class StrategyExample {
    static class SomeCommonSuperType {}
    static class SubType1 extends SomeCommonSuperType {}
    static class SubType2 extends SomeCommonSuperType {}
    static class SubType3 extends SomeCommonSuperType {}

    static interface Handler<T extends SomeCommonSuperType> {
        Object handle(T object);
    }

    static class HandlerMap {
        private Map<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>> handlers_ =
            new HashMap<Class<? extends SomeCommonSuperType>, Handler<? extends SomeCommonSuperType>>();
        public <T extends SomeCommonSuperType> void add(Class<T> c, Handler<T> handler) {
            handlers_.put(c, handler);
        }
        @SuppressWarnings("unchecked")
        public <T extends SomeCommonSuperType> Object handle(T o) {
            return ((Handler<T>) handlers_.get(o.getClass())).handle(o);
        }
    }

    public static void main(String[] args) {
        HandlerMap handlerMap = new HandlerMap();

        handlerMap.add(SubType1.class, new Handler<SubType1>() {
            @Override public Object handle(SubType1 object) {
                System.out.println("Handling SubType1");
                return null;
            } });
        handlerMap.add(SubType2.class, new Handler<SubType2>() {
            @Override public Object handle(SubType2 object) {
                System.out.println("Handling SubType2");
                return null;
            } });
        handlerMap.add(SubType3.class, new Handler<SubType3>() {
            @Override public Object handle(SubType3 object) {
                System.out.println("Handling SubType3");
                return null;
            } });

        SubType1 subType1 = new SubType1();
        handlerMap.handle(subType1);
        SubType2 subType2 = new SubType2();
        handlerMap.handle(subType2);
        SubType3 subType3 = new SubType3();
        handlerMap.handle(subType3);
    }
}
4

'instanceof' ist eigentlich ein Operator wie + oder - und ich glaube, dass es eine eigene JVM-Bytecode-Anweisung hat. Es sollte schnell genug sein.

Ich sollte nicht sagen, dass wenn Sie einen Schalter haben, bei dem Sie testen, ob ein Objekt eine Instanz einer Unterklasse ist, Ihr Entwurf möglicherweise überarbeitet werden muss. Ziehen Sie in Betracht, das subklassenspezifische Verhalten in die Unterklassen selbst zu verschieben.

4

Instanzof ist sehr schnell. Es läuft auf einen Bytecode hinaus, der für den Vergleich von Klassenreferenzen verwendet wird. Probieren Sie einige Millionen Instanzen in einer Schleife aus und überzeugen Sie sich selbst.

4
Apocalisp

Es ist schwer zu sagen, wie eine bestimmte JVM eine Instanz von implementiert, aber in den meisten Fällen sind Objects mit Strukturen und Klassen vergleichbar, und jede Objektstruktur hat einen Zeiger auf die Klassenstruktur, deren Instanz es ist. Also eigentlich beispielof für

if (o instanceof Java.lang.String)

könnte so schnell sein wie der folgende C-Code

if (objectStruct->iAmInstanceOf == &Java_lang_String_class)

vorausgesetzt, ein JIT-Compiler ist vorhanden und macht ordentliche Arbeit.

Wenn man bedenkt, dass hier nur auf einen Zeiger zugegriffen wird, ein Zeiger an einem bestimmten Versatz abgerufen wird, auf den der Zeiger zeigt, und diesen mit einem anderen Zeiger vergleicht (was im Grunde dasselbe ist wie das Testen bei 32-Bit-Zahlen, die gleich sind), würde ich sagen, die Operation kann tatsächlich sei sehr schnell.

Es muss jedoch nicht unbedingt von der JVM abhängen. Wenn sich dies jedoch als Engpass in Ihrem Code herausstellen würde, würde ich die Implementierung der JVM für eher schlecht halten. Sogar einer, der über keinen JIT-Compiler verfügt und nur Code interpretiert, sollte in der Lage sein, innerhalb von kürzester Zeit eine Testinstanz durchzuführen.

3
Mecki

InstanceOf ist eine Warnung vor schlechtem objektorientiertem Design.

Aktuelle JVMs bedeuten, dass instanceOf an sich keine große Leistungsbeeinträchtigung darstellt. Wenn Sie es häufig verwenden, insbesondere für die Kernfunktionen, ist es wahrscheinlich an der Zeit, sich das Design anzusehen. Die Leistungsgewinne (und die Einfachheit/Wartungsfreundlichkeit) des Refactorings auf ein besseres Design werden die tatsächlichen Prozessorzyklen, die für den eigentlichen instanceOf - Aufruf aufgewendet werden, bei weitem überwiegen.

Um ein sehr kleines vereinfachtes Programmierbeispiel zu geben.

if (SomeObject instanceOf Integer) {
  [do something]
}
if (SomeObject instanceOf Double) {
  [do something different]
}

Ist eine schlechte Architektur die bessere Wahl, wäre SomeObject die übergeordnete Klasse von zwei untergeordneten Klassen, in denen jede untergeordnete Klasse eine Methode (doSomething) überschreibt, sodass der Code so aussieht:

Someobject.doSomething();
3
Demian Krige

Ich melde mich bei Ihnen. Eine Möglichkeit, Probleme (oder deren Fehlen) insgesamt zu vermeiden, besteht jedoch darin, eine übergeordnete Schnittstelle zu allen Unterklassen zu erstellen, für die Sie instanceof ausführen müssen. Die Schnittstelle wird aus einer Supermenge von all - Methoden in Unterklassen bestehen, für die Sie eine Instanzprüfung durchführen müssen. Wenn eine Methode nicht für eine bestimmte Unterklasse gilt, stellen Sie einfach eine Dummy-Implementierung dieser Methode bereit. Wenn ich das Problem nicht missverstanden habe, bin ich auf diese Weise in der Vergangenheit an das Problem herangegangen. 

3
Jose Quijada

Im Allgemeinen wird der Operator "instanceof" in einem solchen Fall (in dem die Instanz nach Unterklassen dieser Basisklasse sucht) nicht gern gesehen, weil die Operationen in eine Methode verschoben und für das entsprechende Verfahren überschrieben werden Unterklassen. Zum Beispiel, wenn Sie:

if (o instanceof Class1)
   doThis();
else if (o instanceof Class2)
   doThat();
//...

Sie können das durch ersetzen

o.doEverything();

und haben dann die Implementierung von "doEverything ()" in Class1 den Aufruf "doThis ()" und in Class2 den Aufruf "doThat ()" und so weiter.

2
Paul Tomblin

In einer modernen Java-Version ist der Instanzoperator schneller als ein einfacher Methodenaufruf. Das heisst:

if(a instanceof AnyObject){
}

ist schneller als:

if(a.getType() == XYZ){
}

Eine andere Sache ist, wenn Sie viele Instanzen kaskadieren müssen. Dann ist ein Switch, der nur einmal getType () anruft, schneller.

2
Horcrux7

Ich schreibe einen Leistungstest basierend auf jmh-Java-Benchmark-Archetyp: 2.21. JDK ist openjdk und die Version ist 1.8.0_212. Die Testmaschine ist Mac Pro. Testergebnis ist:

Benchmark                Mode  Cnt    Score   Error   Units
MyBenchmark.getClasses  thrpt   30  510.818 ± 4.190  ops/us
MyBenchmark.instanceOf  thrpt   30  503.826 ± 5.546  ops/us

Das Ergebnis zeigt: getClass ist besser als instanceOf, was im Gegensatz zu anderen Tests steht. Ich weiß jedoch nicht warum.

Der Testcode ist unten:

public class MyBenchmark {

public static final Object a = new LinkedHashMap<String, String>();

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean instanceOf() {
    return a instanceof Map;
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean getClasses() {
    return a.getClass() == HashMap.class;
}

public static void main(String[] args) throws RunnerException {
    Options opt =
        new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).warmupIterations(20).measurementIterations(30).forks(1).build();
    new Runner(opt).run();
}
}
1
salexinx

Wenn Geschwindigkeit Ihr einziges Ziel ist, scheint die Verwendung von int-Konstanten zur Identifizierung von Unterklassen eine Millisekunde der Zeit zu reduzieren

static final int ID_A = 0;
static final int ID_B = 1;
abstract class Base {
  final int id;
  Base(int i) { id = i; }
}
class A extends Base {
 A() { super(ID_A); }
}
class B extends Base {
 B() { super(ID_B); }
}
...
Base obj = ...
switch(obj.id) {
case  ID_A: .... break;
case  ID_B: .... break;
}

schreckliches OO -Design, aber wenn Ihre Leistungsanalyse darauf hinweist, liegt hier möglicherweise ein Engpass. In meinem Code benötigt der Versandcode 10% der gesamten Ausführungszeit, was möglicherweise zu einer Verbesserung der Gesamtgeschwindigkeit um 1% beigetragen hat.

1
Salix alba

Ich bevorzuge auch einen Enum-Ansatz, aber ich würde eine abstrakte Basisklasse verwenden, um die Unterklassen zur Implementierung der getType()-Methode zu zwingen.

public abstract class Base
{
  protected enum TYPE
  {
    DERIVED_A, DERIVED_B
  }

  public abstract TYPE getType();

  class DerivedA extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_A;
    }
  }

  class DerivedB extends Base
  {
    @Override
    public TYPE getType()
    {
      return TYPE.DERIVED_B;
    }
  }
}
0
mike

Ich dachte, es könnte sich lohnen, ein Gegenbeispiel für den allgemeinen Konsens auf dieser Seite vorzulegen, dass "instanceof" nicht teuer genug ist, um sich darüber Sorgen zu machen. Ich fand, dass ich etwas Code in einer inneren Schleife hatte, der (in einem historischen Optimierungsversuch) war

if (!(seq instanceof SingleItem)) {
  seq = seq.head();
}

wobei der Aufruf von head () für ein SingleItem den Wert unverändert zurückgibt. Ersetzen des Codes durch

seq = seq.head();

gibt mir eine Beschleunigung von 269 ms auf 169 ms, trotz der Tatsache, dass einige recht schwere Dinge in der Schleife passieren, wie beispielsweise die Umwandlung von Strings in Doppel. Es ist natürlich möglich, dass die Beschleunigung mehr auf die Beseitigung des bedingten Zweigs als auf die Instanz des Operators selbst zurückzuführen ist. aber ich hielt es für erwähnenswert. 

0
Michael Kay

In Bezug auf Peter Lawreys Hinweis, dass Sie für letzte Kurse keine Instanz benötigen und nur eine Referenzgleichheit verwenden können, seien Sie vorsichtig! Obwohl die finalen Klassen nicht erweitert werden können, können sie nicht von demselben Classloader geladen werden. Verwenden Sie x.getClass () == SomeFinal.class oder dessen Klasse, wenn Sie absolut sicher sind, dass für diesen Codeabschnitt nur ein Classloader im Spiel ist.

0
Miles Elam

Sie sollten messen/profilen, wenn es in Ihrem Projekt tatsächlich ein Leistungsproblem darstellt. Wenn ja, würde ich ein Redesign empfehlen - wenn möglich. Ich bin mir ziemlich sicher, dass Sie die native Implementierung der Plattform (in C geschrieben) nicht überbieten können. In diesem Fall sollten Sie auch die Mehrfachvererbung berücksichtigen.

Sie sollten mehr über das Problem erzählen, vielleicht könnten Sie einen assoziativen Laden verwenden, z. eine Karte <Klasse, Objekt>, wenn Sie nur an den konkreten Typen interessiert sind.

0
Karl