What are the differences between Generic Types in C # and Java?

35

I've studied Java for a long time and I'm well acquainted with the working of generic types in this language: I know there are only compile-time, type type erasure end of it (so that at runtime this information is not available), and I have a certain sense of difficulties in applying polymorphism in generic types .

Now I'm learning C #, and I noticed that although this language uses similar notation ( Tipo<TipoGenerico> ) the semantics does not seem to be the same. For example, when viewing this question I understood that the C # runtime holds generic type information instead of discarding it, unlike Java, is this correct? Also, I have never seen an example in C # that uses wildcards as Tipo<? extends TipoGenerico> . Is this possible (or even necessary) in this language?

Finally, does C # support generic (and not just generic) methods? If so, what is the equivalent syntax of this construct in Java:

public <T> void metodo(T parametro1, List<T> parametro2) {

If there is any additional detail worth highlighting, or perhaps some reference material to learn more, you will also be welcome.

    
asked by mgibsonbr 21.03.2014 в 10:57

4 answers

31

Comparison C # vs Java

  

C # saves generic type information instead of discarding it, unlike Java, this is correct

Yes, in C # there is no Type Erasure that occurs in Java. In Java, internally, the compiler discards the fact that it is MinhaClasseEspecifica and treats as Object , making the casts needed for its specific class.

In C #, the Just-In-Time (JIT) compiler internally builds a specific class with the type T used. If you use a Tipo<string> object, for example, internally it creates a class where all T is string.

From a performance standpoint, what C # is doing is more performative, as it does not need casts back and forth.

According to Anders Hejlsberg himself:

  

For example, with generics in Java, you do not actually get the running efficiency I've commented on, because when you compile a generic class in Java, the compiler removes the type parameter and replaces it with Object. >      

...

     

The IL and the metadata contain additional information that there is a type parameter , of course, but in principle, a generic type compiles in the same way as any other compile type. At runtime, when your application makes the first reference to a List<int> , for example, the system looks if someone has already asked for a List<int> . If no one did, it feeds the JIT with the IL and the metadata for type List<T> and the argument of type int . JITer produces the native code specific to that type at the time it is needed. In Runtime.

Source: link

(Free Translation)

Wildcards / Type Constraints in Generics

  

Also, I've never seen an example in C # that used wildcards as Tipo<? extends TipoGenerico>

In C # it would look like this:

class Classe<T> where T : TipoEspecifico

There are several Type Constraints , follow the link to view. (It's in English)

Generic Methods

  

Finally, does C # support generic (and not just generic) methods? If so, what is the equivalent syntax of this construct in Java:

Basically change the <T> of place

T FazerAlgoComT<T>(T obj) { ... }

Remembering that you can use Type Constraints (where blablabla) in the methods as well.     

21.03.2014 / 13:20
19
  

Also, I've never seen an example in C # that used "jokers"   (wildcards) as Tipo<? extends TipoGenerico> . This is possible (or   even necessary) in that language?

Yes, you can limit the generic parameter to a specific type as follows:

public class MinhaClasse<TEntidade> where TEntidade : MinhaClassePai{}
  

Finally, C # supports individual methods (not just classes)   generic If yes, what is the equivalent syntax of this   Java:

You can use generic methods as long as the generic parameters are present in the Class or method, as in the example below:

public TEntidade MeuMetodo<TEntidade>(TEntidade meuObjeto){}

If you do not want to set the generic parameter in your method, you can use that of the class:

 public class MinhaClasse<TEntidade> where TEntidade : MinhaClassePai
{
    public TEntidade MeuMetodo(TEntidade meuObjeto){}
}

As for your first question, @ConradClark answered it in a clear and objective way.

    
21.03.2014 в 13:14
15

The questions were answered in the two responses posted so far. I'll add something extra that has not been said yet.

In C # the type realization occurs in runtime and not at compile time as is the case with C ++, for example. In C ++ the compiler generates a concrete implementation whenever a different type is used.

One of the things that is strongly complained in C ++ is that if the code uses many concrete types with a template you will have a huge code bloat because each concrete type will generate a code different from the class or method. Java does not suffer from this problem because basically everything is object and then there is only one concrete implementation for this type.

Distributed C # code works in much the same way as Java. Implementation will only take place in memory. It's already a gain. But it would still have a lot of duplicate implementations in memory. Note that CLR, the .Net virtual machine, understands the generic code that the compiler issues. The JVM does not know how to do this.

But the CLR is smarter than this. It creates concrete implementations for each type by value, the structs calls - which Java does not yet have, and for this reason the primitive types need to be boxed - but for reference types only an instance of this is created to hold a reference. After all, all these concrete implementations need to be created because of the semantic difference of value or reference and because of the size of the data. The reference types all work identically, and the size is always the size of the pointer, so there is no reason for an instance of the implementation to exist for each type by reference.

In C ++ it is not possible to do the same because template is more flexible and each implementation can be different, including having specialized behaviors.

Another point that has been talked about is the polymorphism. Some even consider that the genericity allows to dispense the polymorphism if the language is cut for this. Check this out:

T Metodo<T>(T obj) where T : TipoPai {
    return obj.ChamaAlgo(); //Qual "ChamaAlgo()" será executado?
}

The ChamaAlgo() method to call will depend on the type of obj . And this type can be TipoPai or it can be TipoFilho1 , TipoFilho2 , TipoNeto , etc., ie any descending type of TipoPai . Note that ChamarAlgo() would not have to be virtual for this to work in this hypothetical language.

Another thing that should be mentioned is that one of the reasons Java
27.03.2015 в 18:35
10

From my point of view, the main difference is that in Java, you can understand that the purpose of generic classes is to only provide a certain level of security at the time of compilation, "ensuring" to some extent that your program will not generate an exception related to the type mismatch at runtime. At the same time, this leverages code reuse.

In other languages, such as C #, we could understand that the purpose is to generate "concrete" class variations from a base class.

Furthermore, some comparisons made in other responses are not exactly "fair". On performance, for example, in Java you do not gain or lose virtually nothing in performance when using a generic class. The difference is that by not using generics you need to make casts explicit.

In theory, Java would always be "slower" at this point, in the sense that it does not have that specific optimization. The only way to optimize would be to replicate the code into non-generic classes. But if it is to make a comparison between languages, several other criteria should be considered. For example, not having this specific type of optimization does not mean that, just for example, Java cast might be faster than direct calling in C #.

A trade-off that was only implicitly mentioned in other languages, is that Java does not consume more memory for generic classes. I do not think it's a very delicate point, but C # will consume more memory in proportion to the number of generic classes you implement.

Finally, one of the major drawbacks to any developments at this point in the Java language is that there is usually a major concern with compatibility. It's a design decision that does not appeal to a lot of people, but keeping the code in runtime unchanged saved a lot of money to companies that did not have to rewrite applications to adapt them to new versions of the Java Virtual Machine. >     

09.04.2015 в 20:22