Gibt es in Java eine integrierte Methode, um die Größe eines Datentyps zu ermitteln? Gibt es eine Möglichkeit, Größe zu finden?
Gibt es in Java eine integrierte Methode, um die Größe eines Datentyps zu ermitteln? Gibt es eine Möglichkeit, Größe zu finden?
Antworten:
Nein. In der Standard-Java SE-Klassenbibliothek gibt es keine solche Methode.
Nach Ansicht der Designer wird es in Java nicht benötigt, da die Sprache die Notwendigkeit beseitigt, dass eine Anwendung 1 weiß, wie viel Speicherplatz für einen primitiven Wert, ein Objekt oder ein Array mit einer bestimmten Anzahl von Elementen reserviert werden muss.
Sie könnten denken, dass ein Operator sizeof für Personen nützlich wäre, die wissen müssen, wie viel Speicherplatz ihre Datenstrukturen beanspruchen. Sie können diese und weitere Informationen jedoch auch einfach und zuverlässig mit einem Java-Speicherprofiler abrufen, sodass keine sizeof-Methode erforderlich ist.
Frühere Kommentatoren machten den Punkt, sizeof(someType)der lesbarer wäre als 4. Wenn Sie dieses Argument der Lesbarkeit akzeptieren, liegt das Mittel in Ihren Händen. Definieren Sie einfach eine Klasse wie diese ...
public class PrimitiveSizes {
public static int sizeof(byte b) { return 1; }
public static int sizeof(short s) { return 2; }
// etcetera
}
... und statisch importieren ...
import static PrimitiveSizes.*;
Oder definieren Sie einige benannte Konstanten. z.B
public static final int SIZE_OF_INT = 4;
Oder (Java 8 und höher) verwenden Sie die Integer.BYTESKonstante und so weiter.
Warum haben die Java-Designer dies nicht in Standardbibliotheken implementiert? Meine Vermutung ist, dass:
Es gibt auch das Problem, dass die nächste Nachfrage nach einer sizeof(Object o)Methode wäre, die mit technischen Schwierigkeiten behaftet ist.
Das Schlüsselwort oben ist "sie"!
1 - Ein Programmierer muss möglicherweise wissen, um platzsparende Datenstrukturen zu entwerfen. Ich kann mir jedoch nicht vorstellen, warum diese Informationen zur Laufzeit über einen Methodenaufruf im Anwendungscode benötigt werden.
Aus dem Artikel in JavaWorld
Eine oberflächliche Antwort ist, dass Java nichts wie Cs sizeof () liefert. Lassen Sie uns jedoch überlegen, warum ein Java-Programmierer dies gelegentlich möchte.
Der AC-Programmierer verwaltet die meisten Speicherzuordnungen für die Datenstruktur selbst, und sizeof () ist für die Kenntnis der zuzuweisenden Speicherblockgrößen unverzichtbar. Darüber hinaus tun C-Speicherzuordnungen wie malloc () bei der Objektinitialisierung fast nichts: Ein Programmierer muss alle Objektfelder festlegen, die Zeiger auf weitere Objekte sind. Aber wenn alles gesagt und codiert ist, ist die C / C ++ - Speicherzuweisung ziemlich effizient.
Im Vergleich dazu sind Java-Objektzuweisung und -Konstruktion miteinander verbunden (es ist unmöglich, eine zugewiesene, aber nicht initialisierte Objektinstanz zu verwenden). Wenn eine Java-Klasse Felder definiert, die auf weitere Objekte verweisen, werden diese häufig auch zur Erstellungszeit festgelegt. Durch das Zuweisen eines Java-Objekts werden daher häufig zahlreiche miteinander verbundene Objektinstanzen zugewiesen: ein Objektdiagramm. In Verbindung mit der automatischen Speicherbereinigung ist dies allzu praktisch und kann dazu führen, dass Sie sich nie um Details zur Java-Speicherzuweisung kümmern müssen.
Dies funktioniert natürlich nur für einfache Java-Anwendungen. Im Vergleich zu C / C ++ belegen äquivalente Java-Datenstrukturen tendenziell mehr physischen Speicher. In der Entwicklung von Unternehmenssoftware ist die Annäherung an den maximal verfügbaren virtuellen Speicher der heutigen 32-Bit-JVMs eine häufige Einschränkung der Skalierbarkeit. Ein Java-Programmierer könnte daher von sizeof () oder ähnlichem profitieren, um zu beobachten, ob seine Datenstrukturen zu groß werden oder Speicherengpässe enthalten. Glücklicherweise können Sie mit Java Reflection ein solches Tool ganz einfach schreiben.
Bevor ich fortfahre, werde ich auf einige häufige, aber falsche Antworten auf die Frage dieses Artikels verzichten. Irrtum: Sizeof () wird nicht benötigt, da die Größen der Java-Basistypen festgelegt sind
Ja, ein Java-Int ist 32 Bit in allen JVMs und auf allen Plattformen, aber dies ist nur eine Sprachspezifikationsanforderung für die vom Programmierer wahrnehmbare Breite dieses Datentyps. Ein solches int ist im Wesentlichen ein abstrakter Datentyp und kann beispielsweise durch ein physisches 64-Bit-Speicherwort auf einer 64-Bit-Maschine gesichert werden. Gleiches gilt für nicht primitive Typen: Die Java-Sprachspezifikation sagt nichts darüber aus, wie Klassenfelder im physischen Speicher ausgerichtet werden sollen oder dass ein Array von Booleschen Werten nicht als kompakter Bitvektor in der JVM implementiert werden kann. Irrtum: Sie können die Größe eines Objekts messen, indem Sie es in einen Byte-Stream serialisieren und die resultierende Stream-Länge anzeigen
Der Grund, warum dies nicht funktioniert, ist, dass das Serialisierungslayout nur eine Fernreflexion des tatsächlichen In-Memory-Layouts ist. Eine einfache Möglichkeit, dies zu erkennen, besteht darin, zu untersuchen, wie Strings serialisiert werden: Im Speicher beträgt jedes Zeichen mindestens 2 Byte, in serialisierter Form sind Strings jedoch UTF-8-codiert, sodass jeder ASCII-Inhalt halb so viel Speicherplatz beansprucht
Die Java Native Access- Bibliothek wird normalerweise zum Aufrufen nativer gemeinsam genutzter Bibliotheken aus Java verwendet. Innerhalb dieser Bibliothek gibt es Methoden zum Bestimmen der Größe von Java-Objekten:
Die getNativeSize(Class cls)Methode und ihre Überladungen geben die Größe für die meisten Klassen an.
Wenn Ihre Klassen von der Strukturklasse von JNA erben, ist die calculateSize(boolean force)Methode alternativ verfügbar.
Sie können Bitmanipulationen wie unten ausführen, um die Größe der Grundelemente zu erhalten:
public int sizeofInt() {
int i = 1, j = 0;
while (i != 0) {
i = (i<<1); j++;
}
return j;
}
public int sizeofChar() {
char i = 1, j = 0;
while (i != 0) {
i = (char) (i<<1); j++;
}
return j;
}
i<<8stattdessen verwenden, wird die Anzahl der Bytes angegeben.
Es gibt einen zeitgemäßen Weg, dies für Primitive zu tun. Verwendung BYTESvon Typen.
System.out.println("byte " + Byte.BYTES);
System.out.println("char " + Character.BYTES);
System.out.println("int " + Integer.BYTES);
System.out.println("long " + Long.BYTES);
System.out.println("short " + Short.BYTES);
System.out.println("double " + Double.BYTES);
System.out.println("float " + Float.BYTES);
Es fuehrt zu,
byte 1
char 2
int 4
long 8
short 2
double 8
float 4
Die Instrumentation-Klasse verfügt über eine getObjectSize () -Methode. Sie sollten sie jedoch nicht zur Laufzeit verwenden müssen. Der einfachste Weg, die Speichernutzung zu untersuchen, ist die Verwendung eines Profilers, mit dem Sie die Speichernutzung verfolgen können.
EhCache bietet eine SizeOf- Klasse, die versucht, den Instrumentation- Agenten zu verwenden, und auf einen anderen Ansatz zurückgreift, wenn der Agent nicht geladen ist oder nicht geladen werden kann ( Details hier ).
Siehe auch den Agenten von Heinz Kabutz .
Ich habe beschlossen, eine Aufzählung zu erstellen, ohne die Standard-Java-Konventionen zu befolgen. Vielleicht gefällt dir das.
public enum sizeof {
;
public static final int FLOAT = Float.SIZE / 8;
public static final int INTEGER = Integer.SIZE / 8;
public static final int DOUBLE = Double.SIZE / 8;
}
Versuchen Sie es mit java.lang.Instrumentation.getObjectSize (Object) . Aber bitte beachten Sie das
Es gibt eine implementierungsspezifische Annäherung an die vom angegebenen Objekt verbrauchte Speichermenge zurück. Das Ergebnis kann einen Teil oder den gesamten Overhead des Objekts enthalten und ist daher für den Vergleich innerhalb einer Implementierung nützlich, jedoch nicht zwischen Implementierungen. Die Schätzung kann sich während eines einzelnen Aufrufs der JVM ändern.
Auf SourceForge.net ist eine Klasse / JAR verfügbar, die Java-Instrumente verwendet, um die Größe eines Objekts zu berechnen. Hier ist ein Link zur Beschreibung: java.sizeOf
Nur ein paar Tests darüber:
public class PrimitiveTypesV2 {
public static void main (String[] args) {
Class typesList[] = {
Boolean.class , Byte.class, Character.class, Short.class, Integer.class,
Long.class, Float.class, Double.class, Boolean.TYPE, Byte.TYPE, Character.TYPE,
Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE
};
try {
for ( Class type : typesList ) {
if (type.isPrimitive()) {
System.out.println("Primitive type:\t" + type);
}
else {
boolean hasSize = false;
java.lang.reflect.Field fields[] = type.getFields();
for (int count=0; count<fields.length; count++) {
if (fields[count].getName().contains("SIZE")) hasSize = true;
}
if (hasSize) {
System.out.println("Bits size of type " + type + " :\t\t\t" + type.getField("SIZE").getInt(type) );
double value = type.getField("MIN_VALUE").getDouble(type);
long longVal = Math.round(value);
if ( (value - longVal) == 0) {
System.out.println("Min value for type " + type + " :\t\t" + longVal );
longVal = Math.round(type.getField("MAX_VALUE").getDouble(type));
System.out.println("Max value for type " + type + " :\t\t" + longVal );
}
else {
System.out.println("Min value for type " + type + " :\t\t" + value );
value = type.getField("MAX_VALUE").getDouble(type);
System.out.println("Max value for type " + type + " :\t\t" + value );
}
}
else {
System.out.println(type + "\t\t\t type without SIZE field.");
}
} // if not primitive
} // for typesList
} catch (Exception e) {e.printStackTrace();}
} // main
} // class PrimitiveTypes