Есть ли подобный метод в Java?

Есть ли какой-либо встроенный метод в Java, чтобы найти размер любого типа данных? Есть ли способ найти размер?

17 ответов

Решение

Нет. В стандартной библиотеке классов Java SE такого метода нет.

Дизайнеры считают, что в Java это не нужно, так как язык избавляет приложение 1 от необходимости знать, сколько места нужно зарезервировать для примитивного значения, объекта или массива с заданным количеством элементов.

Вы можете подумать, что оператор sizeof будет полезен для людей, которым необходимо знать, сколько места занимают их структуры данных. Однако вы также можете получить эту информацию и многое другое, просто и надежно, используя профилировщик памяти Java, поэтому нет необходимости в методе sizeof.


Предыдущие комментаторы подчеркивали, что sizeof(someType) будет более читабельным, чем 4, Если вы примете этот аргумент читабельности, значит, лекарство в ваших руках. Просто определите класс как этот...

public class PrimitiveSizes {
    public static int sizeof(byte b) { return 1; } 
    public static int sizeof(short s) { return 2; }
    // etcetera
}

... и статически импортировать это...

import static PrimitiveSizes.*;

Или определите некоторые именованные константы; например

public static final int SIZE_OF_INT = 4;

Или (Java 8 и более поздние версии) используйте Integer.BYTES постоянный и тд.


Почему разработчики Java не реализовали это в стандартных библиотеках? Я думаю, что:

  • они не думают, что в этом есть необходимость,
  • они не думают, что есть достаточный спрос на это, и
  • они не думают, что это стоит усилий.

Существует также проблема, что следующим требованием будет sizeof(Object o) метод, который чреват техническими трудностями.

Ключевое слово в вышесказанном "они"!

Неважно, что вы или я об этом думаете. И, следовательно, обсуждение этой темы в комментариях является спорным. Пожалуйста, просто не надо.


1 - программисту может понадобиться знать, чтобы спроектировать эффективные в пространстве структуры данных. Однако я не могу представить, почему эта информация понадобится в коде приложения во время выполнения посредством вызова метода.

Из статьи в JavaWorld

Поверхностный ответ заключается в том, что Java не предоставляет ничего подобного sizeof() в C. Однако давайте рассмотрим, почему Java-программист иногда может этого захотеть.

Программист переменного тока сам управляет большинством распределений памяти структуры данных, и sizeof() необходим для знания размеров блоков памяти для распределения. Кроме того, распределители памяти C, такие как malloc(), почти ничего не делают в отношении инициализации объекта: программист должен установить все поля объекта, которые являются указателями, на дальнейшие объекты. Но когда все сказано и закодировано, распределение памяти на C/C++ достаточно эффективно.

Для сравнения, распределение и построение Java-объектов связаны между собой (невозможно использовать выделенный, но неинициализированный экземпляр объекта). Если класс Java определяет поля, которые являются ссылками на другие объекты, также обычно их устанавливают во время создания. Поэтому выделение Java-объекта часто выделяет многочисленные взаимосвязанные экземпляры объектов: граф объектов. В сочетании с автоматической сборкой мусора это слишком удобно и может дать вам ощущение, что вам никогда не придется беспокоиться о деталях выделения памяти Java.

Конечно, это работает только для простых приложений Java. По сравнению с C/C++ эквивалентные структуры данных Java имеют тенденцию занимать больше физической памяти. При разработке программного обеспечения предприятия сближение с максимально доступной виртуальной памятью на современных 32-разрядных виртуальных машинах Java является распространенным ограничением масштабируемости. Таким образом, Java-программист может извлечь выгоду из sizeof() или чего-то подобного, чтобы следить за тем, становятся ли его структуры данных слишком большими или содержат узкие места в памяти. К счастью, отражение Java позволяет вам написать такой инструмент довольно легко.

Прежде чем продолжить, я обойдусь без частых, но неправильных ответов на вопрос этой статьи. Ошибка: Sizeof () не требуется, потому что размеры основных типов Java являются фиксированными

Да, Java int имеет 32 бита во всех JVM и на всех платформах, но это только требование спецификации языка для воспринимаемой программистом ширины этого типа данных. Такой тип int по существу является абстрактным типом данных и может быть зарезервирован, скажем, 64-битным словом физической памяти на 64-битной машине. То же самое относится и к не примитивным типам: спецификация языка Java ничего не говорит о том, как поля классов должны быть выровнены в физической памяти или что массив булевых переменных не может быть реализован как компактный битовый вектор внутри JVM. Ошибка: Вы можете измерить размер объекта, сериализовав его в поток байтов и посмотрев на полученную длину потока

Причина, по которой это не работает, заключается в том, что макет сериализации является лишь удаленным отражением истинного макета в памяти. Один из простых способов увидеть это - посмотреть, как строки сериализуются: в памяти каждый символ имеет по крайней мере 2 байта, но в сериализованной форме строки кодируются в кодировке UTF-8, поэтому любое содержимое ASCII занимает вдвое меньше места.

Существует современный способ сделать это для примитивов. использование BYTES типов.

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

Это приводит к,

byte 1
char 2
int 4
long 8
short 2
double 8
float 4

Библиотека Java Native Access обычно используется для вызова собственных общих библиотек из Java. В этой библиотеке существуют методы для определения размера объектов Java:

getNativeSize(Class cls) Метод и его перегрузки обеспечат размер для большинства классов.

В качестве альтернативы, если ваши классы наследуются от класса Structure JNA, calculateSize(boolean force) метод будет доступен.

Вы можете делать битовые манипуляции, как показано ниже, чтобы получить размер примитивов:

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

Как упомянуто здесь, есть возможности получить размер примитивных типов через их оболочки.

например для long это могло быть Long.SIZE / Byte.SIZE из Java 1.5 (как уже упоминалось в Zeodtr) или Long.BYTES как из Java 8

Вы можете использовать Integer.SIZE / 8, Double.SIZE / 8 и т. Д. Для примитивных типов из Java 1.5.

Класс Instrumentation имеет метод getObjectSize(), однако вам не нужно использовать его во время выполнения. Самый простой способ проверить использование памяти - использовать профилировщик, который предназначен для отслеживания использования памяти.

EhCache предоставляет класс SizeOf, который будет пытаться использовать агент Instrumentation и будет использовать другой подход, если агент не загружен или не может быть загружен ( подробности здесь).

Также смотрите агент из Хайнц Кабуц.

Попробуйте java.lang.Instrumentation.getObjectSize (Object). Но учтите, что

Возвращает зависящее от реализации приблизительное количество памяти, используемой указанным объектом. Результат может включать некоторые или все накладные расходы объекта и, таким образом, полезен для сравнения внутри реализации, но не между реализациями. Оценка может измениться в течение одного вызова JVM.

Я решил создать enum без соблюдения стандартных соглашений Java. Возможно, вам это нравится.

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

Вот класс, который я использовал для оценки поведения памяти в моем приложении.

https://github.com/BeatEngine/java-sizeof-object/blob/main/MemoryObjectSizeCalculation.java

Он анализирует объекты и суммирует размер (собственных) простых типов.

      private void parse(final Object someObject) {
        boolean couldBeNative = true;
        for (Field field : getAllFields(someObject)) {
            Object value;
            try {
                field.setAccessible(true);
                value = field.get(someObject);
                couldBeNative = false;
            } catch (IllegalAccessException | InaccessibleObjectException e) {
                continue;
            }
            if (value != null) {
                if (visitedObjects.add(value)) {
                    if (addSizeNeedToParse(value)) {
                        parse(value);
                    }
                }
            }
        }
        if (couldBeNative) {
            addSizeNeedToParse(someObject);
        }
    }

Просто немного тестирования:

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

Не уверен для более старых версий, но поскольку версия 1.8 java sdk предоставляет.BYTESсвойства коробочных объектов примитивных типов.

      BYTES ( = SIZE / Byte.size )

import java.util.*;
import java.lang.*;
import java.io.*;

// The main method must be in a class named "Main".
class Main {
public static void main(String[] args) {
    System.out.println("size of Integer: " + Integer.BYTES);
    System.out.println("size of Character: " + Character.BYTES);
    System.out.println("size of Short: " + Short.BYTES);
    System.out.println("size of Long: " + Long.BYTES);
    System.out.println("size of Double: " + Double.BYTES);     
    System.out.println("size of Float: " + Float.BYTES);     
    
   }
}

Вот скрипка: https://www.mycompiler.io/view/0N19Y6cWL8F

На SourceForge.net есть класс / jar, который использует инструментарий Java для расчета размера любого объекта. Вот ссылка на описание: java.sizeOf

Я не думаю, что это в API Java. но большинство типов данных, которые имеют ряд элементов, имеют size() метод. Я думаю, что вы можете легко написать функцию для проверки размера самостоятельно?

Да .. в JAVA

System.out.println(Integer.SIZE/8);  //gives you 4.
System.out.println(Integer.SIZE);   //gives you 32.

//Similary for Byte,Long,Double....
Другие вопросы по тегам