Отличаются ли примитивные типы в Java и C#?

Я вручную конвертирую код из Java в C# и борюсь с (что я называю) примитивными типами (см., Например, автобокс и распаковка ведут себя по-разному в Java и C#). Из ответов я понимаю, что double (C#) и Double (C#) эквивалентны и double (C#) также может использоваться в контейнерах, например, как ключ в словаре. Тем не мение, double (Java) нельзя использовать в контейнерах, таких как HashMap, поэтому он автоматически упакован в Double (Джава).

  1. Является double (C#) примитив или объект?
  2. Если это примитив, что заставляет его вести себя иначе, чем double (Джава)?

double (C#) не может быть установлен в ноль, если это не сделано nullable,

  1. Является double? (C#) эквивалентно Double (Джава)? Они оба упоминаются как объекты?

(Полезно ли использовать термин "первоклассный объект" в этом обсуждении?)

3 ответа

Решение

И C#, и Java имеют примитивные (или "значения") типы: int, double, float и т. Д.

Однако после этого C# и Java имеют тенденцию делиться.

В Java есть типы классов-оболочек для всех примитивных типов (что является небольшим конечным набором в Java), что позволяет рассматривать их как объект. double/Double, int/Integer, bool/Boolean и т. д. Эти типы-оболочки являются ссылочными типами (читай: классы) и, как таковые, null является допустимым значением для присваивания таким типизированным выражениям / переменным. В последних версиях Java (1.5/5+) добавлены неявные приведения из примитивов в их соответствующие оболочки.

// Java
Boolean b = true; // implicit conversion boolean -> Boolean (Java 5+)
Boolean b = null; // okay, can assign null to a reference type
boolean n = null; // WRONG - null is not a boolean!

C# не обеспечивает такую ​​прямую упаковку 1 - отчасти потому, что C# поддерживает бесконечный набор типов значений через структуры; Скорее всего, C# обрабатывает "типы значений, допускающие обнуляемость", Nullable<T> тип обертки. Кроме того, C#, как и Java, имеет неявные преобразования из типа значения T в Nullable<T> с ограничением на то, что T сам по себе не является "обнуляемым типом".

// C#
Nullable<bool> b = true; // implicit conversion bool -> bool?
bool? b = true;          // short type syntax, implicit conversion
bool? b = null;          // okay, can assign null as a Nullable-type
bool b = null;           // WRONG - null is not a bool

Обратите внимание, что Nullable<T> также является типом значения и, следовательно, следует стандартным правилам структуры для случая, когда значение находится в стеке или нет.

В ответ на комментарий:

Абсолютно правильно, Nullable, являющийся типом значения, в некоторых случаях позволяет ему иметь более компактный объем памяти, поскольку он может избежать накладных расходов памяти эталонного типа: каков объем памяти Nullable ;. Тем не менее, он все еще требует больше памяти, чем тип, не поддерживающий Nullable, потому что он должен помнить, равно ли это значение нулю или нет. В зависимости от проблем выравнивания и реализации VM, это может быть или не быть значительно меньше, чем "полный" объект. Кроме того, поскольку значения в C#/CLR уточнены, рассмотрим любые операции подъема, которые необходимо выполнить:

// C#
object x = null;
x = (bool?)true;
(x as bool?).Value // true

Статья Java Совет 130: знаете ли вы размер ваших данных? говорит о потреблении памяти ссылочного типа (в Java). Следует отметить, что JVM имеет специализированные версии массивов для внутренних целей, по одной для каждого типа примитива и для объектов (однако, обратите внимание, что эта статья содержит некоторые вводящие в заблуждение утверждения). Обратите внимание, как Объекты (против примитивов) влекут за собой дополнительные затраты памяти и проблемы с выравниванием байтов. C#, однако, может расширить случай оптимизированного массива для Nullable<T> типы против ограниченных особых случаев JVM имеет, потому что Nullable<T> сам по себе просто тип структуры (или "примитив").

Однако объекту требуется только небольшой фиксированный размер для сохранения "ссылки" на него в переменном слоте. Переменная слот типа Nullable<LargeStruct> с другой стороны, должно быть место для LargeStruct+Nullable (сам слот может быть в куче). См. Концепции C#: Значение против Типов ссылок. Обратите внимание, что в приведенном выше примере "подъема" переменная имеет тип object: object является "корневым типом" в C# (родительский тип ссылочных типов и типов значений), а не специализированным типом значений.


1 Язык C# поддерживает фиксированный набор псевдонимов для примитивных / общих типов, которые разрешают доступ к "дружественным строчным" именам типов. Например, double это псевдоним для System.Double а также int это псевдоним для System.Int32, Если не другой Double тип импортируется в область, double а также Double будет ссылаться на тот же тип в C#. Я рекомендую использовать псевдонимы, если нет причин поступать иначе.

Nullable<double> (ака double?) в C# не совпадает с Double на Яве.

До того, как в Java были автоматические и автоматические распаковки, вы должны были вручную преобразовать примитивы в объекты первого класса:

Double dblObj = new Double(2.0);
double dblPrim = dblObj.doubleValue();

В Java 1.5 это изменилось, так что вы можете просто сделать:

Double dblObj = 2.0;
double dblPrim = dblObj;

И Java вставит код для автоматического отражения вышеупомянутого примера.

C# отличается тем, что существует неограниченное количество "примитивных" типов (то, что CLR называет типами значений). Они ведут себя в основном как примитивы Java, используя семантику значений. Вы можете создавать новые типы значений, используя struct ключевое слово. C# имеет автобокс / распаковку для всех типов значений, а также делает все типы значений производными от Object,

Таким образом, вы можете использовать тип значения (например, double) где вы будете использовать любую ссылку на объект (например, в качестве ключа в Dictionary) и он будет упакован в случае необходимости, или просто используется напрямую. (Реализация Generics в C# достаточно хороша, чтобы в большинстве случаев избежать бокса.)

В C# лучший способ отделить объекты - это "Типы значений", которые похожи на примитивы - ints, bools и т. д. и "Типы ссылок" - классы и т. д.

Другие вопросы по тегам