Frage

Ich arbeite an einer Anwendung und einem Design-Ansatz beinhaltet extrem starke Nutzung des instanceof Betreiber. Während ich weiß, dass OO-Design im Allgemeinen zu vermeiden versucht instanceof verwenden, das ist eine andere Geschichte und diese Frage ist rein im Zusammenhang mit Leistung. Ich habe mich gefragt, ob es irgendwelche Auswirkungen auf die Leistung ist? Ist genauso schnell wie ==?

Zum Beispiel habe ich eine Basisklasse mit 10 Unterklassen. In einer einzigen Funktion, die die Basisklasse nimmt, kann ich überprüft, ob die Klasse ist eine Instanz der Unterklasse und eine gewisse Routine auszuführen.

Einer der anderen Möglichkeiten, wie ich dachte, es zu lösen war eine „Typ-ID“ integer primitive stattdessen zu verwenden, und eine Bitmaske verwenden Kategorien der Unterklassen zu repräsentieren, und führen Sie dann nur einen Bitmaske Vergleich der Unterklassen „Typ-ID "auf eine konstante Maske, die die Kategorie.

Ist instanceof irgendwie durch die JVM optimiert schneller zu sein als das? Ich möchte Java bleiben, aber die Leistung der App ist kritisch. Es wäre cool, wenn jemand, der vor diesem Weg gewesen könnte einige Ratschläge anbieten. Bin ich zu viel oder die Konzentration auf die falsche Sache Erbsenzählerei zu optimieren?

War es hilfreich?

Lösung

Moderne JVM / JIC Compiler die Leistungseinbußen der meisten der entfernt werden traditionell „langsamen“ Operationen, einschließlich instanceof, Ausnahmebehandlung, Reflexion, etc.

Wie Donald Knuth schrieb: „Wir sollten über kleine Effizienz, sagen sie etwa 97% der Zeit vergessen. Vorzeitige Optimierung ist die Wurzel aller Übel“ Die Leistung von instanceof wird wahrscheinlich kein Problem sein, so vergeuden Sie nicht Ihre Zeit mit exotischen Abhilfen kommen, bis Sie sicher sind, das ist das Problem.

Andere Tipps

Ansatz

Ich schrieb ein Benchmark-Programm verschiedene Implementierungen bewerten:

  1. instanceof Implementierung (als Referenz)
  2. Objekt über eine abstrakte Klasse orientiert und @Override ein Testverfahren
  3. eine eigene Art Implementierung mit
  4. getClass() == _.class Implementierung

Ich benutzte jmh die Benchmark mit 100 Warm-up Anrufe zu laufen, 1000 Iterationen unter Messung, und mit 10 gabelt. So wurde jede Option mit 10 000-mal gemessen, den 00.18.57 dauert 1.8 die gesamte Benchmark auf meinem MacBook Pro mit macOS 10.12.4 und Java laufen. Der Benchmark misst die durchschnittliche Zeit der einzelnen Optionen. Weitere Einzelheiten finden Sie unter meine Implementierung auf GitHub .

Die Vollständigkeit halber: Es gibt eine frühere Version dieser Antwort und meinen Benchmark .

Ergebnisse

| Operation  | Runtime in nanoseconds per operation | Relative to instanceof |
|------------|--------------------------------------|------------------------|
| INSTANCEOF | 39,598 ± 0,022 ns/op                 | 100,00 %               |
| GETCLASS   | 39,687 ± 0,021 ns/op                 | 100,22 %               |
| TYPE       | 46,295 ± 0,026 ns/op                 | 116,91 %               |
| OO         | 48,078 ± 0,026 ns/op                 | 121,42 %               |

tl; dr

In Java 1.8 instanceof ist der schnellste Ansatz, obwohl getClass() ganz in der Nähe ist.

Ich habe gerade einen einfachen Test, um zu sehen, wie instanceOf Leistung ist auf eine einfache s.equals Vergleich () aufrufen zu einem String-Objekt mit nur einem Buchstaben.

in einer 10.000.000 Schleife die instanceOf gab mir 63-96ms und die Zeichenfolge ist gleich gab mir 106-230ms

Ich benutze Java JVM 6.

Also in meinem einfachen Test schneller ist eine instanceOf anstelle eines eine Zeichenfolge Vergleich zu tun.

Integer das .equals mit () anstelle von String den gab mir das gleiche Ergebnis, nur wenn ich die == verwenden i schneller war als instanceOf von 20ms (in einem 10.000.000 loop)

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

  1. Die Anzahl der möglichen Klassen, für die der Operator instanceof true zurückgeben könnte
  2. Die Verteilung der Daten - sind die meisten der instanceof-Operationen in der ersten oder zweiten Versuch gelöst? Sie wollen Ihre höchstwahrscheinlich setzen erste echte Operationen zurückzukehren.
  3. Die Implementierungsumgebung. Laufen auf einem Sun Solaris VM ist wesentlich anders als Sun Windows JVM. Solaris wird in ‚Server‘ Modus standardmäßig ausgeführt, während Windows im Client-Modus ausgeführt wird. Die JIT-Optimierungen auf Solaris, werden alle Verfahren Zugang kann das gleiche machen.

Ich habe einen -Micro für vier verschiedene Methoden der Versendung . Die Ergebnisse von Solaris sind wie folgt, wobei die kleinere Zahl ist schneller:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067 

Wir beantworten Ihre allerletzte Frage: Es sei denn, ein Profiler sagt Ihnen, dass Sie lächerliche Mengen an Zeit in einem Instanceof verbringen: Ja, Sie Erbsenzählerei

.

Bevor fragen, über etwas zu optimieren, die nie zu optimier benötigt: Schreiben Sie Ihren Algorithmus in der meisten lesbaren Weise und führen Sie es. Führen Sie es, bis der JIT-Compiler eine Chance bekommt, es selbst zu optimieren. Wenn Sie dann mit diesem Stück Code Probleme haben, verwenden Sie einen Profiler, Ihnen zu sagen, wo die meisten zu gewinnen und diese zu optimieren.

In Zeiten hochoptimierende Compiler, Ihre Vermutungen über Engpässe werden wahrscheinlich völlig falsch sein.

Und im wahren Geist dieser Antwort (was ich wholeheartly glauben.): Ich weiß absolut nicht, wie instanceof und == beziehen, wenn die JIT-Compiler eine Chance, es zu optimieren

Ich habe vergessen. Niemals den ersten Lauf messen

Ich habe diese Frage bekommt, aber weil ich nicht ‚Performance-Metriken‘ für Anwendungsfall wie bei mir gefunden haben, ich habe etwas mehr Beispielcode getan. Auf meiner Hardware und Java 6 und 7, die Differenz zwischen instanceof und schalten Sie 10mln Iterationen

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

Also, instanceof ist wirklich langsamer, vor allem auf große Anzahl von if-else-if-Anweisungen, aber Unterschied innerhalb realer Anwendung vernachlässigbar sein.

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()));
    }
}

instanceof ist wirklich schnell, wobei nur wenige CPU-Anweisungen.

Offensichtlich wenn eine Klasse X keine Subklassen hat geladen (JVM weiß) kann instanceof wie optimiert werden:

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

Die Hauptkosten sind nur ein Lesen!

Wenn X nicht Subklassen geladen haben, ein paar mehr liest erforderlich sind; sie sind wahrscheinlich co-located so die zusätzlichen Kosten zu sehr gering ist.

Gute Nachrichten alle!

instanceof wird wahrscheinlich teurer sein als eine einfache in den meisten realen Welt Implementierungen gleich (das heißt, die, wo Instanceof wirklich benötigt, und man kann es nicht nur lösen, indem eine gemeinsame Methode überschrieben, wie jeder Anfänger Lehrbuch sowie Demian oben vorschlagen).

Warum ist das so? Denn das, was wahrscheinlich passieren wird ist, dass Sie mehrere Schnittstellen haben, die einige Funktionen bieten (sagen wir mal, Schnittstellen x, y und z), und einige Objekte zu manipulieren, dass kann (oder nicht) eine dieser Schnittstellen implementieren ... aber nicht direkt. Nehmen wir zum Beispiel, ich habe:

w erstreckt x

A implementiert w

B erstreckt A

C B erstreckt, implementiert y

D C erstreckt, umsetzt z

Angenommen, ich eine Instanz von D bin Verarbeitung, das Objekt d. Computing (d Instanceof x) erfordert d.getClass zu nehmen (), eine Schleife durch die Schnittstellen implementiert, es zu wissen, ob man x == ist, und wenn nicht so tun, wieder rekursiv für alle ihre Vorfahren ... In unserem Fall, wenn Sie tun, um eine Breiten Erforschung dieses Baumes, Ausbeuten mindestens 8 Vergleiche, angenommen, y und z nichts erweitern ...

Die Komplexität eines realen Ableitungsbaum ist wahrscheinlich höher sein. In einigen Fällen kann der JIT der meisten davon optimiert weg, wenn es in der Lage ist, im Voraus d zu lösen als in allen möglichen Fällen eine Instanz von etwas, das x erstreckt. Realistisch gesehen, aber Sie gehen durch diesen Baum-Traversal gehen fast die ganze Zeit.

Wenn das ein Problem wird, würde ich vorschlagen, stattdessen eine Handler Karte unterhalten, die Verknüpfung die konkrete Klasse des Objekts zu einem Verschluss, der die Handhabung des Fall ist. Es entfernt die Baum-Traversal-Phase für eine direkte Zuordnung. Aber passen Sie auf, wenn Sie einen Handler für C.class gesetzt haben, mein Objekt d oben wird nicht erkannt.

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

‚instanceof‘ ist eigentlich ein Operator wie + oder -, und ich glaube, dass es seinen eigenen JVM Bytecode-Befehl hat. Es sollte viel schneller sein.

Ich sollte nicht, dass, wenn Sie einen Schalter, wo Sie testen, ob ein Objekt eine Instanz einer subsclass ist, dann könnte Ihr Design müssen überarbeitet werden. Betrachten Sie schieben die Unterklasse spezifisches Verhalten nach unten in die Unterklassen selbst.

Instanceof ist sehr schnell. Es läuft darauf hinaus, eine Bytecode nach unten, die für Klassenreferenz Vergleich verwendet wird. Probieren Sie ein paar Millionen instanceofs in einer Schleife und überzeugen Sie sich selbst.

Demian und Paul erwähnen einen guten Punkt; aber , die Platzierung des Codes wirklich auszuführen hängt davon ab, wie Sie wollen, um die Daten verwenden ...

Ich bin ein großer Fan von kleinen Datenobjekten, die in vielerlei Hinsicht verwendet werden können. Wenn Sie die Überschreibung (polymorphen) Ansatz folgen, können Sie Ihre Objekte nur verwendet werden, „one way“.

Dies ist, wo Muster kommen in ...

Sie können doppelt Versand verwenden (wie im Besuchermuster) jedes Objekt zu bitten, „rufen Sie“ passing selbst - dies wird die Art des Objekts lösen. Jedoch (wieder) finden Sie eine Klasse benötigen, die „Dinge tun“ kann mit allen möglichen Subtypen.

Ich ziehe eine Strategie Muster zu verwenden, wo Sie Strategien für jeden Subtyp registrieren können Sie behandeln möchten. Etwas wie folgt aus. Beachten Sie, dass dies hilft nur für genaue Art Streichhölzer, aber den Vorteil hat, dass es ist erweiterbar - Dritten, können ihre eigenen Typen und Handler hinzufügen. (Das ist gut für dynamische Frameworks wie OSGi, wo neue Bündel hinzugefügt werden können)

Dies wird hoffentlich einige andere Ideen inspirieren ...

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);
    }
}

instanceof ist sehr effizient, so dass Ihre Leistung unwahrscheinlich leiden. Allerdings schlägt mit vielen Instanceof ein Design-Problem.

Wenn Sie XClass == String.class verwenden können, ist dies schneller. . Hinweis: Sie brauchen nicht Instanceof für die endgültigen Klassen

Es ist schwer zu sagen, wie eine bestimmte JVM implementiert Instanz, aber in den meisten Fällen, Objekte sind vergleichbar mit structs und Klassen sowie sind und jedes Objekt Struktur einen Zeiger auf die die Klasse Struktur hat es eine Instanz. Also eigentlich Instanceof für

if (o instanceof java.lang.String)

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

if (objectStruct->iAmInstanceOf == &java_lang_String_class)

einen JIT-Compiler unter der Annahme vorhanden ist, und macht einen guten Job.

In Anbetracht, dass diese nur einen Zeiger Zugriff auf einen Zeiger zu einem bestimmten Offset des Zeigers auf und vergleichen diese auf einem anderen Zeiger bekommen (was im Grunde die gleichen wie Tests sind 32-Bit-Zahlen gleich), würde ich sagen, dass die Operation kann tatsächlich sehr schnell sein.

Es muss nicht, aber es viel auf der JVM abhängt. wenn dies würde jedoch erweisen sich der Engpass Betrieb in Ihrem Code sein, würde ich die JVM Implementierung eher schlecht betrachten. Auch eine, die keine JIT-Compiler hat und nur Code interpretiert der Lage sein sollte, eine instanceof-Test in praktisch keine Zeit zu machen.

InstanceOf ist eine Warnung für schlechtes Objektorientiertes Design.

Aktuelle JVMs bedeuten die instanceOf ist nicht viel von einer Leistung Sorge in sich. Wenn Sie sich selbst finden es viel verwendet, insbesondere für Kernfunktionalität, ist es wahrscheinlich Zeit bei der Gestaltung zu suchen. Die Leistung (und Einfachheit / Wartbarkeit) Gewinne von Refactoring zu einem besseren Design werden stark keine tatsächlichen Prozessorzyklen auf dem tatsächlichen ausgegeben aufwiegen instanceOf Anruf.

ein sehr kleines simplen Programmier Beispiel zu geben.

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

Ist eine schlechte Architektur eine bessere Wahl zu haben gewesen wäre Someobject die Elternklasse von zwei untergeordneten Klassen, in denen jedes Kind-Klasse überschreibt eine Methode (doSomething), so würde der Code aussehen als solche:

Someobject.doSomething();

Ich werde auf instanceof Leistung zu Ihnen zurück. Aber ein Weg Problem zu vermeiden (oder deren Fehlen) insgesamt wäre eine übergeordnete Schnittstelle zu allen Unterklassen zu erstellen, auf dem Sie instanceof tun müssen. Die Schnittstelle wird ein Super-Satz sein alle die Methoden in Unterklassen, für die Sie tun müssen, um Instanceof zu überprüfen. Wo ein Verfahren zu einer bestimmten Unterklasse gilt nicht, einfach eine Dummy-Implementierung dieses Verfahrens bereitzustellen. Wenn ich das Problem nicht falsch verstehen, das ist, wie ich habe, um das Problem in der Vergangenheit bekommen.

Im Allgemeinen ist der Grund, warum die „instanceof“ Operator auf in einem solchen Fall, dass verpönt (wo die instanceof für Subklassen dieser Basisklasse überprüft) ist, denn was sollten Sie ist tun, die Vorgänge in einem Verfahren zu bewegen und overridding es für die entsprechenden Unterklassen. Zum Beispiel, wenn Sie haben:

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

Sie können das ersetzen mit

o.doEverything();

und dann die Umsetzung des "doEverything ()" in Class1 Call "DoThis ()" und in Klasse 2 Aufruf "doThat ()", und so weiter.

In der modernen Java-Version des Operator instanceof ist schneller als ein einfacher Methodenaufruf. Das bedeutet:

if(a instanceof AnyObject){
}

ist schneller als:

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

Eine andere Sache ist, wenn Sie viele Instanceof kaskadieren müssen. Dann wird ein Schalter, der nur einmal getType () aufrufen, ist schneller.

Wenn die Geschwindigkeit Ihr einziges Ziel ist es dann int Konstanten Unterklassen zu identifizieren, scheint eine Millisekunde der Zeit zu rasieren

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;
}

schrecklich OO-Design, aber wenn Sie Ihre Performance-Analyse zeigt dies ist, wo Sie Engpass ist dann vielleicht. In meinem Code erfolgt der Versand-Code 10% der gesamten Ausführungszeit und dies trug vielleicht zu einer 1% Gesamtgeschwindigkeitsverbesserung.

Ich schreibe einen Performance-Test basiert auf jmh-java-Benchmark-Urform: 2.21. JDK ist openjdk und Version ist 1.8.0_212. Die Testmaschine ist pro mac. Testergebnis:

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, dass: getClass ist besser als instanceOf, die mit anderer Testentgegengesetzt ist. Aber ich weiß nicht, warum.

Der Testcode ist unter:

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();
}
}

Sie sollten messen / Profil, wenn es in Ihrem Projekt wirklich ein Performance-Problem ist. wenn möglich - Wenn es würde ich ein Redesign empfehlen. Ich bin mir ziemlich sicher, dass Sie nicht die Plattform native Implementierung schlagen können (geschrieben in C). Sie sollten auch die Mehrfachvererbung in diesem Fall in Betracht ziehen.

Sie sollten mehr über das Problem sagen, vielleicht könnten Sie einen assoziativen Speicher verwenden, z.B. eine Karte , wenn Sie in den konkreten Typen nur interessiert sind.

Im Hinblick auf Peter Lawrey Anmerkung, dass Sie nicht Instanceof für die endgültige Klassen brauchen und können nur einen Verweis Gleichheit verwenden, seien Sie vorsichtig! Auch wenn die letzten Klassen nicht verlängert werden können, werden sie nicht von dem gleichen Klassenlader geladen werden garantiert. Nur x.getClass verwenden () == SomeFinal.class oder seine ilk, wenn Sie absolut sicher sind, dass es für diesen Abschnitt des Codes nur ein Klassenlader im Spiel ist.

ich auch einen ENUM-Ansatz bevorzugen, aber ich würde eine abstrakte Basisklasse verwenden, um die Unterklassen zu zwingen, die getType() Methode zu implementieren.

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;
    }
  }
}

Ich dachte, es könnte sich lohnen ein Gegenbeispiel zu dem allgemeinen Konsens auf dieser Seite, dass „instanceof“ ist nicht teuer genug Vorlage zu befürchten. Ich fand ich in einer inneren Schleife einige Codes hatte, dass (in einigem historischen Versuch Optimierung) tat

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

Dabei steht Kopf () aufrufen, auf einem SingleItem unverändert den Wert zurückgibt. Ersetzen Sie den Code durch

seq = seq.head();

gibt mir ein Beschleunigungs-von 269ms bis 169ms, trotz der Tatsache, dass es einige ziemlich schwere Dinge in der Schleife passiert, wie String-to-Doppelwandler. Es ist natürlich möglich, dass die Geschwindigkeit-up mehr fällig ist die bedingte Verzweigung als zur Beseitigung des instanceof-Operators selbst zu beseitigen; aber ich dachte, es erwähnenswert.

Sie konzentriert sich auf die falsche Sache. Der Unterschied zwischen instanceof und jeder anderen Methode für die gleiche Sache Überprüfung würde wahrscheinlich auch nicht messbar sein. Wenn die Leistung entscheidend ist dann Java ist wahrscheinlich die falsche Sprache. Der Hauptgrund ist, dass Sie nicht kontrollieren können, wenn die VM entscheidet sie will Müll gehen sammeln, was die CPU auf 100% für einige Sekunden in einem großen Programm in Anspruch nehmen (MagicDraw 10 war für die). Sofern Sie die Kontrolle über jeden Computer sind dieses Programm auf Sie ausführen können nicht garantieren, welche Version von JVM wird es auf, und viele der älteren großen Geschwindigkeitsprobleme hatte. Wenn es sich um eine kleine Anwendung ist können Sie mit Java in Ordnung sein, aber wenn man ständig liest und Daten verwirft dann Sie wird Hinweis, wenn die GC Kicks in.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top