2009-10-21 22 views
13

Estoy convirtiendo manualmente código de Java a C# y luchando con (lo que yo llamo) tipos primitivos (ver, por ejemplo, Do autoboxing and unboxing behave differently in Java and C#). De las respuestas entiendo que double (C#) y Double (C#) son equivalentes y double (C#) también se pueden usar en contenedores, p. como una clave en un diccionario. Sin embargo, double (Java) no se puede utilizar en contenedores como HashMap y es por eso que está en caja automática en Double (Java).¿Los tipos primitivos son diferentes en Java y C#?

  1. Es double (C#) una primitiva o un objeto?
  2. Si es una primitiva, ¿qué hace que se comporte de manera diferente a double (Java)?

double (C#) no se puede ajustar a nulo, a menos que se hace nullable.

  1. ¿Es double? (C#) equivalente a Double (Java)? ¿Son ambos referidos como objetos?

(es el uso de la expresión "de primera clase de objeto" útil en esta discusión?)

Respuesta

17

C# y Java tienen primitivas (o "valor") tipos: int, double, float, etc ...

Sin embargo, después de este C# y Java tienden a dividirse.

Java tiene tipos de clase de contenedor para todos los tipos primitivos (que es un pequeño conjunto finito en Java) que les permite ser tratados como Objeto. double/Double, int/Integer, bool/Boolean, etc. Estos tipos de envoltorio son tipos de referencia (leer: Clases) y, como tal, null es un valor válido para asignar a tales expresiones/variables tipadas. Las versiones recientes de Java (1.5/5 +) agregan coerciones implícitas desde primitivas a su envoltorio correspondiente.

// 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# no proporciona un una envoltura directa tales - en parte, porque C# soporta un conjunto infinito de tipos de valor través de structures; más bien, C# maneja los "tipos de valor que aceptan valores de nulo" mediante la introducción de un tipo de contenedor Nullable<T>. Además, C#, como Java, tiene conversiones implícitas del tipo de valor T a Nullable<T>, con la restricción de que T es "no un tipo anulable".

// 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 

Nota que Nullable<T> es también un tipo de valor y por lo tanto sigue las reglas de estructura estándar para cuando/si un valor es "en la pila" o no.

En respuesta al comentario:

absolutamente correcto, Anulable ser un tipo de valor hace permitir que tenga una huella de memoria más compacto en ciertos casos ya que puede evitar la sobrecarga de la memoria de una referencia tipo: What is the memory footprint of a Nullable<T>. Sin embargo, todavía requiere más memoria que el tipo que no admite valores Nullable porque debe recordar si el valor es, bueno, nulo o no. Dependiendo de los problemas de alineación y la implementación de VM, esto puede o no ser significativamente menor que un objeto "completo". Además, dado que los valores de C#/CLR están materializadas, a estudiar todas las operaciones de elevación que se deben realizar:

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

El artículo Java Tip 130: Do you know your data size? habla sobre el consumo de memoria de tipo de referencia (en Java). Una cosa a tener en cuenta es que la JVM tiene versiones especializadas de matrices internamente, una para cada tipo primitivo y para objetos (sin embargo, tenga en cuenta que este artículo contiene algunas declaraciones engañosas ). Observe cómo los Objetos (frente a las primitivas) incurren en sobrecarga de memoria adicional y problemas de alineación de bytes. C# sin embargo, puede ampliar el caso de matriz optimizada para los tipos Nullable<T> frente a los casos especiales limitados que tiene la JVM porque Nullable<T> es en sí mismo solo un tipo de estructura (o "primitivo").

Sin embargo, un objeto solo requiere un pequeño tamaño fijo para mantener una "referencia" en un espacio variable. Por otro lado, una ranura variable del tipo Nullable<LargeStruct> debe tener espacio para LargeStruct+Nullable (la ranura misma puede estar en el montón). Ver C# Concepts: Value vs Reference Types. Observe que en el ejemplo de "elevación" de arriba la variable es de tipo object: object es el "tipo de raíz" en C# (padre de ambos tipos de valores y tipos de referencia) y no es un tipo de valor especializado.


El lenguaje C# soporta un conjunto fijo de alias para los tipos primitivos/comunes que permiten el acceso a los nombres de tipo "amigable" en minúscula.Por ejemplo, double es un alias para System.Double y int es un alias para System.Int32. A menos que se importe un tipo diferente de Double en el alcance, double y Double se referirán al mismo tipo en C#. Recomiendo usar los alias a menos que haya una razón para hacer lo contrario.

+3

Argumentaría que es más que un "aparte", ya que esto tiene una gran implicación en el no boxeo, es decir, 'Nullable ' es un entero que se puede anotar, ** no encajado **, 32 bits con signo. –

+1

Usted dice "Las versiones recientes de Java (1.5) agregan coacciones explícitas" - Creo que tiene eso al revés. Java siempre ha tenido conversiones ** explícitas ** entre los tipos primitivos y sus contrapartidas de objeto, pero en Java 1.5 el lenguaje ganó ** conversiones implícitas ** en forma de autoboxing/unboxing. –

+0

@ Daniel, tienes razón. –

10

Nullable<double> (también conocido como double?) en C# es no lo mismo que un Double en Java.

Antes de Java tenía autoboxing/unboxing, había que convertir manualmente entre primitivas y objetos de primera clase:

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

En Java 1.5 que cambió, por lo que sólo se podía hacer:

Double dblObj = 2.0; 
double dblPrim = dblObj; 

Y Java insertaría código para reflejar el ejemplo anterior automáticamente.

C# es diferente porque hay un número ilimitado de tipos "primitivos" (lo que CLR llama a value types). Estos se comportan principalmente como las primitivas de Java, usando la semántica de valores . Puede crear nuevos tipos de valor utilizando la palabra clave struct. C# tiene autoboxing/unboxing para todos los tipos de valor, y también hace que todos los tipos de valores deriven de Object.

Así que puede usar un tipo de valor (como double) donde usaría cualquier referencia de objeto (por ejemplo, como una clave en Dictionary) y se encasillará si es necesario o simplemente se usará directamente. ('S C# aplicación genéricos es lo suficientemente bueno para evitar el boxeo en la mayoría de las circunstancias.)

+0

por lo que java 'int' tiene una huella más pequeña que C#' int'? como java sería 32 bits y C# sería 32 bits + cualquier otra cosa en la estructura 'System.Integer' ¿verdad? –

1

En C#, la mejor manera de separar los objetos son por 'Tipos de valor', que son un poco como los primitivos - int s, bool s, etc., y "Referencia tipos" - clases etc.

Cuestiones relacionadas