São diferentes tipos primitivos em Java e C#?
-
22-09-2019 - |
Pergunta
Eu sou manualmente conversão de código de Java para C# e a lutar com os (que eu chamo) de tipos primitivos (ver, por exemplo, Fazer o autoboxing e unboxing se comportam de maneira diferente em Java e C#).A partir das respostas eu entendo que double
(C#) e Double
(C#) são equivalentes e double
(C#) pode também ser usado em recipientes, por exemplo,como uma chave em um Dicionário.No entanto, double
(Java) não pode ser usado em recipientes como HashMap é por isso que é auto-box para Double
(Java).
- É
double
(C#) primitivo ou um objeto? - Se é uma primitiva que o faz comportar-se de forma diferente a partir de
double
(Java)?
double
(C#) não pode ser definido como null, a menos que ela é feita nullable
.
- É
double?
(C#), equivalente aDouble
(Java)?São ambos referidos como objetos?
(É o uso do termo "primeira-classe de objeto" útil nesta discussão?)
Solução
C# e Java primitivos (ou "valor") tipos:int, double, float, etc...
No entanto, após isso, C# e Java tendem a dividir-se.
Java tem Classe de wrapper tipos de todos os tipos primitivos (que é um pequeno conjunto finito em Java) que lhes permite ser tratado como Objeto.double/Double
, int/Integer
, bool/Boolean
, etc.Estes wrapper tipos de referência-tipos (leia:Classes) e, como tal, null
é um valor válido para atribuir a tais digitado expressões/variáveis.Versões mais recentes de Java (1.5/5+) adicionar na implícito coerções do primitivos correspondentes wrapper.
// 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# não fornece um tal direta de moldagem1 - em parte, porque o C# suporta um conjunto infinito de tipos de valor via estruturas;ao invés, C# alças "de valor nulo tipos" pela introdução de um Nullable<T>
wrapper tipo.Além de C#, como Java, tem implícito conversões de tipo de valor T
para Nullable<T>
, com a restrição de que T não é "um tipo anulável" em si.
// 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
Note que Nullable<T>
também é um tipo de valor e, portanto, segue a estrutura padrão de regras para quando/se o valor for "na pilha" ou não.
Em resposta ao comentário:
Absolutamente correto, Anulável sendo um tipo de valor não lhe permitem ter um mais compacto espaço de memória em certos casos, como ele pode evitar a sobrecarga de memória de um tipo de referência: O que é o espaço de memória de um Nullable<T>.No entanto, ele ainda requer mais memória do que o tipo não-Nulo, porque ela tem que se lembrar se o valor é, também, nulo, ou não.Dependendo de problemas de alinhamento e de implementação de VM, isso pode ou não pode ser significativamente menor do que um objeto "completa".Também, uma vez que os valores em C#/CLR são reificadas, considere quaisquer operações de içamento que devem ser executadas:
// C#
object x = null;
x = (bool?)true;
(x as bool?).Value // true
O artigo Java Dica 130:Você conhece o seu tamanho de dados? fala sobre o tipo de referência do consumo de memória (em Java).Uma coisa a notar é que a JVM tem versões especializadas de Matrizes internamente, um para cada tipo primitivo, e para Objetos (no entanto, por favor note que este artigo contém algumas declarações enganosas).Observe como os Objetos (vs.primitivos) implicam sobrecarga de memória e o alinhamento de byte problemas.C# no entanto, pode estender as otimizado-matriz de caso para Nullable<T>
tipos de vs.o especial limitada-casos a JVM tem porque Nullable<T>
é só por si um tipo de estrutura (ou "primitivos").
No entanto, um Objeto, requer apenas um pequeno tamanho fixo para manter uma "referência" a-lo em uma variável de fenda.Uma variável de fenda do tipo Nullable<LargeStruct>
por outro lado, deve ter espaço para LargeStruct+Nullable
(o entalhe em si, pode ser no heap).Ver C# Conceitos:Valor vs Tipos de Referência.Note-se como a "elevação" exemplo acima, a variável é do tipo object
: object
é o "tipo de raiz" em C# (pai de tipos de referência e tipos de valor) e não especializado tipo de valor.
1 A linguagem C# suporta um conjunto fixo de aliases para o primitivo/tipos comuns que permitem o acesso a "amigável minúsculas" nomes de tipo.Por exemplo, double
é um alias para System.Double
e int
é um alias para System.Int32
.A menos que o Double
tipo de importados no escopo, double
e Double
vai se referir ao mesmo tipo em C#.Eu recomendo o uso de aliases, a menos que haja uma razão para fazer o contrário.
Outras dicas
Nullable<double>
(também conhecido como double?
) em C# é não o mesmo que um Double
em java.
Antes de Java ter autoboxing/unboxing, você precisava converter manualmente entre primitivos e objetos de primeira classe:
Double dblObj = new Double(2.0);
double dblPrim = dblObj.doubleValue();
No Java 1.5, isso mudou, para que você possa fazer:
Double dblObj = 2.0;
double dblPrim = dblObj;
E Java inseriria o código para refletir o exemplo acima automaticamente.
C# é diferente porque há um número ilimitado de tipos "primitivos" (o que o CLR chama Tipos de valor). Estes se comportam principalmente como os primitivos de Java, usando semântica de valor. Você pode criar novos tipos de valor usando o struct
palavra -chave. C# possui autoboxing/unboxing para tudo tipos de valor e também faz com que todos os tipos de valor derivem de Object
.
Então você pode usar um tipo de valor (como double
) onde você usaria qualquer referência de objeto (por exemplo, como uma chave em um Dictionary
) e será encaixotado, se necessário, ou apenas usado diretamente. (A implementação dos genéricos de C#é boa o suficiente para evitar o boxe na maioria das circunstâncias.)
Em C#, a melhor maneira de separar objetos é por "tipos de valor" que são como primitivos - int
s, bool
s, etc e "tipos de referência" - aulas etc.