Introduction
Previously I discussed one of the major differences between C# and Java - method overriding. Because of it Java and C# code, which look almost identical, can have very different semantics. Similarly, C# and Java generics differ significantly in terms of the underlying semantics, which can be quite confusing for a Java programmer.
Example
Let us consider the following seemingly analogous code snippets implemented in both languages.
C# code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Animal { }
public class Lion:Animal { }
public class Bear:Animal { }
public class Cage<T>;
{
private static int instanceCount = 0;
public Cage()
{
instanceCount++;
}
public void PrintInstanceCount()
{
System.Console.WriteLine(instanceCount);
}
}
Java code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Animal { }
public class Lion extends Animal { }
public class Bear extends Animal { }
public class Cage<T>;
{
private static int instanceCount = 0;
public Cage()
{
instanceCount++;
}
public void PrintInstanceCount()
{
System.out.println(instanceCount);
}
}
Now let us consider the following invocations:
1
2
3
4
5
6
Cage <Animal> ca = new Cage<Animal>();
Cage <Lion> cl = new Cage<Lion>();
Cage <Bear> cb = new Cage<Bear>();
ca.PrintInstanceCount();
cl.PrintInstanceCount();
cb.PrintInstanceCount();
Many will be surprised to see that the results are different, as per the following table:
Command / Language | C# | Java |
---|---|---|
ca.PrintInstanceCount(); | 1 | 3 |
cl.PrintInstanceCount(); | 1 | 3 |
cb.PrintInstanceCount(); | 1 | 3 |
Java implements type erasure, which means that type parameters are erased at compile time and at a runtime there is a single class for each template. Thus, in the previous example at runtime there is a single static member variable for all instances of Cage, independent of the type parameter.
Conversely, the C# compiler (i.e. the Just In Time compiler - JIT) ensures that all closed types
(e.g. Cage
Consequences
As a result C# does not let you access the static members of a template class without specifying the template parameters:
1
2
3
Cage.instanceCount = 5; // Invalid in C#, Valid in Java
Cage<Lion>.instanceCount = 5; // Valid in C#, Invalid in Java
Cage<Bear>.instanceCount = 5; // Valid in C#, Invalid in Java
Also, C# does not let you have an entry point (i.e. a Main method) in a template class.