Вопрос

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

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

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

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

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

Это было полезно?

Решение

И 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# обрабатывает «типы значений, допускающие значение NULL», путем введения Nullable<T> тип обертки.Кроме того, C#, как и Java, имеет неявные преобразования типа значения. T к Nullable<T>, с тем ограничением, что T сам по себе не является типом, допускающим значение NULL.

// 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<T>.Однако для него по-прежнему требуется больше памяти, чем для типа, не допускающего значения NULL, поскольку он должен помнить, является ли значение нулевым или нет.В зависимости от проблем с выравниванием и реализации виртуальной машины это может быть или не быть значительно меньше, чем «полный» объект.Кроме того, поскольку значения в C#/CLR конкретизированы, рассмотрите любые операции подъема, которые необходимо выполнить:

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

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

Однако объекту требуется только небольшой фиксированный размер, чтобы поддерживать «ссылку» на него в слоте переменных.Переменный слот типа Nullable<LargeStruct> с другой стороны, должно быть место для LargeStruct+Nullable (сам слот может находиться в куче).Видеть Концепции С#:Значение и ссылочные типы.Обратите внимание, что в приведенном выше примере «подъема» переменная имеет тип 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# лучший способ разделить объекты — это «Типы значений», которые похожи на примитивы — intс, bools и т. д. и «Ссылочные типы» — классы и т. д.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top