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

Asked

Viewed 1,166 times

37

I have studied Java for quite some time and am well acquainted with the functioning of generic types in that language: I know that only exist at compile time, that suffer type Erasure at the end of it (so that at the time of execution this information is not available), and I have a certain notion of difficulties when applying polymorphism to 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 seeing that question I understood that the C# Runtime stores the information of generic types instead of discarding it, unlike Java, is that correct? Also, I’ve never seen an example in C# that uses "wildcards" (wildcards) as Tipo<? extends TipoGenerico>. This is possible (or even necessary) in this language?

Finally, does C# support individual methods (and not only generic classes)? If so, what is the equivalent syntax of this Java construction:

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

If there are any additional details worth highlighting, or perhaps some reference material to learn more about, you are also welcome.

  • That one public <T> void metodo(T parametro1, List<T> parametro2) { is from Java... and would aim to do what?

  • @tchicotti For example, do an operation between parametro1 and parametro2 where it doesn’t matter what their type is, but it matters that they are related (e.g.: inserts parametro1 on the list parametro2).

  • @tchicotti this happens when you want to declare a generic only at the method level, i.e., the class does not declare generics

  • I understood, and it’s possible, I just didn’t answer dpois, because I already had complete answers

4 answers

34


Comparison C# vs Java

C# stores the information of generic types instead of discarding it, unlike Java, this is correct

Yes, in C# there is no Type Erasure which occurs in Java. In java, internally, the compiler discards the fact that it is MinhaClasseEspecifica and treats as Object, making the required Casts for your specific class.

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

From a performance point of view, what C# is doing is more performative, because it doesn’t need Sts back and forth.

According to Anders Hejlsberg himself :

For example, with Generics in Java, you don’t actually get the running efficiency that I mentioned, because when you build a generic Java class, the compiler removes the type parameter and replaces everything 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 that any other type would. 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, he feeds the JIT the IL and the metadata to the guy List<T> and the argument of the type int. Jiter produces the specific native code for that type at the time it is needed. In Runtime.

Source: http://www.artima.com/intv/generics2.html

(Free Translation)

Wildcards / Type Constraints in Generics

Also, I’ve never seen an example in C# that uses "wildcards" (wildcards) Tipo<? extends TipoGenerico>

In C# it would be like this:

class Classe<T> where T : TipoEspecifico

There are several Type Constraints, follow the link to see. (It is in English)

Generic Methods

Finally, does C# support individual methods (and not only generic classes)? If so, what is the equivalent syntax of this Java construction:

Basically change the <T> place

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

Remembering that you can use the Type Constraints (Where blablabla) in the methods also.

20

Besides, I’ve never seen an example in C# that uses "wild cards" (wildcards) as Tipo<? extends TipoGenerico>. This is possible (or even necessary) in that language?

Yes, it is possible to limit the generic parameter to a specific type as follows:

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

Finally, C# supports individual methods (and not only classes) generic? If yes, what is the equivalent syntax of this construction in Java:

You can use generic methods as long as 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 define the generic parameter in your method, you can use the class:

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

As for your first question, @Conradclark answered it clearly and objectively.

18

The questions have been answered in the two answers posted so far. I will add something extra that has not yet been said.

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

One of the things that is called for a lot 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 different code from the template class or method. Java does not suffer from this problem because in the background everything is object and then there is only one concrete implementation for this type.

Distributed C# code works more or less the same way as Java. Implementation will only take place in memory. It is already a gain, but it would still have a scam of duplicate implementations in memory. Note that the CLR, the virtual machine of . NET, understand the generic code that the compiler issues. JVM does not know how to do this.

But CLR is smarter than this. It creates concrete implementations for each type by value, the calls structs - that Java does not yet have, and so the primitive types need to be boxed - but for reference types only one instance of this is created to hold any 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 pointer size, so there is no reason to have an implementation instance for each type by reference.

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

Another point that has been talked about is polymorphism. Some even consider that the genericity allows to dispense with polymorphism if the language is tailored to it. See this:

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

The method ChamaAlgo() to be called will be that dependent on the type of obj. And this guy could be TipoPai or may be TipoFilho1, TipoFilho2, TipoNeto, etc., that is to say any descending type of TipoPai. Note that ChamarAlgo() it wouldn’t have to be virtual for this to work in this hypothetical language.

Another aspect that should be discussed is that one of the reasons that wildcards of Java were introduced was to allow co and counter variance of types in the use of it. In C# this is obtained in statement of the kind with in and out.

class exemplo<out T> //covariante

class exemplo<in T>  //contravariante

I put in the Github for future reference.

12

From my point of view, the main difference is that in Java, you can understand that the purpose of generic classes is only to 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 incompatibility of execution-time types. 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.

Also, some comparisons made in other responses are not exactly "fair". About performance, for example, in Java you don’t win or lose almost anything in performance when using a generic class. The difference will be that by not using generic you need to do Casts explicit.

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

A trade-off which was mentioned only implicitly in other languages, is that Java no longer consumes memory for generic classes. I don’t think it’s a very delicate point, but C# will consume more memory proportionally to the number of generic classes you implement.

Finally, one of the major obstacles to any evolution at this point in the Java language is that there is a great deal of concern about compatibility. It is a design decision that does not please many people, but keep the code in Runtime unchanged saved a lot of money for companies that didn’t need to rewrite applications to adapt them to new versions of the Java Virtual Machine.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.