BT

A Comparison of C# to Java, Updated

| by Hartmut Wilms Follow 0 Followers on May 02, 2007. Estimated reading time: 2 minutes |

In 2001 Dare Obasanjo has written one of the most comprehensive and accurate "Comparison of Microsoft's C# Programming Language to Sun Microsystems' Java Programming Language". Now he has updated his comparison in order to reflect the changes in the current versions of both languages: Microsoft C# 2.0 and Java Standard Edition 6.

Dare Obasanjo's article is an objective comparison of the features and concepts of C# and Java. What distinguishes his work from others is that he gives a complete overview of the languages and their implementations on both platforms. Thereby his comparison also serves as a language reference and an explanation of the feature implementations as well as their pros and cons. 

The article is structured as follows:

  1. What features are the same in C# and Java?
  2. What features exist in both languages, but differ in minor manner?
  3. What concepts exist in both languages, but differ significantly?
  4. What features or concepts exist in C#, which have no counterpart in Java?
  5. What features or concepts exist in Java, which have no counterpart in C#?
  6. Conclusion

The comparison of Generics and Metadata Annotations are especially interesting, because they show and explain the apparently minor differences in the Java and C# implementation, which have some unobvious consequences when using these features in real-world projects. Another interesting aspect of the article is that Dare Obasonjo has included his conclusion from 2001 in the current version, showing the changing directions of language evolution in Java and C#:

[...] a number of features have become common across both C# and Java since 2001. These features include generics, foreach loops, enumerations, boxing, variable length parameter lists and metadata annotations. However after years of convergence it seems that C# and Java are about to go in radically different directions. The current plans for C# 3.0 are highlighted in the Language Integrated Query (LINQ) Project which encompasses integrating a number of data oriented features including query, set operations, transformations and type inferencing directly into the C# language. In combination with some of C#'s existing features like anonymous methods and nullable types, the differences between C# and Java will become more stark over the next few years in contrast to the feature convergence that has been happening over the past few years.

Dare Obasanjo's comparison offers a lot of information for developers who switch from Java to C# or vice versa as well as developers who want to get some additional information about the features and concepts of their language.

Rate this Article

Adoption Stage
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Erratum by Marko Topolnik

I was quite astonished to find that Dare managed to get confused about access modifiers in Java. In B.7. he mentions the C++ fans who were disappointed to see the semantics of protected changed in Java -- which is actually true but not in the way he describes it: "protected" in Java gives the access rights as in C++, but in union with the package-private access rigths. However, he describes "protected" as if he was describing "package-private" and does not mention "package-private" at all.

Erratum (con'td) by Stefan Wenig

this article sure is an interesting read, dare did compile a lot of information. that's really great if you know one language well and want to learn the other - the sublte differences are hard to find out in any other way. however, he got many details wrong. i just browsed over the article and found quite a lot of mistakes:

final in java is the same as readonly in c#: values cannot be modified after initialization. however, they are stored as values. const in c# is a compile-time constant, meaning that references to consts are replaced by their literal value at compile time, and not stored anywhere at runtime.


on generics: "It should be noted that if the requested type is a reference type as opposed to a value type then the generic type parameter is replaced with Object. However there is no casting done internally by the .NET runtime when accessing the type."

this is not quite the same as the correct description: JIT-generated code is shared for all reference types. static type checking is still very specific about type arguments.


"Whereas in C#, an enumerated type is simply syntactic sugar around an integral type (typically an int) meaning they cannot be extended and are not typesafe."

they are of course typesafe.


"A Java inner class can be considered as a one-to-one relationship between the inner class and its enclosing class where for each instance of the enclosing class there exists a corresponding instance of the inner class that has access to the enclosing class's instance variables and contains no static methods."

as far as my little java knowledge takes me, inner classes still have to be new'd up, they only keep an implicit reference to their owner (a "parent" field you'd have to initialize via the constructor otherwise, much like the this parameter). so there can be zero or more instances of inner classes for each outer-class object, not quite a 1:1 relationship...


the "double checked locking is broken" declaration is outdated. afaik, the current java version makes volatile work in this scenario. on the other hand, the volatile keyword is no more strictly necessary in the .net 2.0 memory model.


"Secondly one needs to define a method that accepts an instance of the delegate as a parameter. Once this is done, a method that has the same signature as the delegate [...] or has covariant return types and contravariant parameter types [...] can be created and used [...]."

covariant return types are supported by the c# language, but contravariant parameter types are not. the latter are however supported by the CLR, so a call to CreateDelegate will provide both co- and contravariance.


"(In fact, C#'s built-in types such as int are actually implemented as structs in the runtime library)."

this could lead one to think that using an int in c# leads to the creation of a System.Int32 object through standard instantiation mechanisms. however, basic types like int are of course hard coded into the CLR and not treated like user-defined value types.


"NOTE: The as operator cannot be used to convert to or from value types."

it can, using nullable value types:
object o = null;
int? i = o as int?;


"x ?? y is equivalent to x == (null ? y : x). "

ouch! ;-)


the connection between anonymous classes in java and anonymous methods in c# is completely missing, as is the concept of closures.


the conclusion fails to mention how c# is becoming more functional in version 3.0. lambda expressions and conversion of expressions to data (abstract syntax trees) are exciting features far beyond the scope of data-oriented LINQ. toghether with new features like extension methods, c#'s anonymous types (completely unlike java's) and type inference this can change the way you program quite radically. the value of continuations is quite underestimated too, they can be used for so much more interesting things that just building iterators for collection classes.

Still worth reading, I just hope those mistakes (and there are probably some i didn't spot) are corrected soon.

Re: Erratum (con'td) by David Skelly

final in java is the same as readonly in c#: values cannot be modified after initialization. however, they are stored as values. const in c# is a compile-time constant, meaning that references to consts are replaced by their literal value at compile time, and not stored anywhere at runtime.


You are correct about variables or parameters declared final in Java. However, just to confuse things static final variables in Java are compiled as in-line constants. In other words, if you change a static final value, you need to recompile everything that uses it or they will continue using the old value. That catches out every Java newbie sooner or later. So, although I don't know C#, it sounds to me as if final is the same as readonly and static final is the same as const. Is that right?

as far as my little java knowledge takes me, inner classes still have to be new'd up, they only keep an implicit reference to their owner (a "parent" field you'd have to initialize via the constructor otherwise, much like the this parameter). so there can be zero or more instances of inner classes for each outer-class object, not quite a 1:1 relationship


Correct. Also, although inner classes cannot contain static methods of their own, they can access static methods of the containing outer class.

Re: Erratum (con'td) by Stefan Wenig

That catches out every Java newbie sooner or later. So, although I don't know C#, it sounds to me as if final is the same as readonly and static final is the same as const. Is that right?


you're right: it'd have caught me, and what you describe is exactly how const works in c#. however, from the java specs i gather that a final field is treated as a constant if it is assigned a fixed literal of a basic data type. is the following correct?
class C {
final String s1 = "this is a compile-time constant";
static final MyString s2 = new MyString ("this is stored in a field");
static final string s2;
C (string suffix) {
s2 = "this is stored in a field" + suffix;
}
}

it's just usually the other way 'round.
in c# it's simple: if the value is not of a primitive type or has to be calculated at runtime, using "const" does not compile. so readonly and const always work as expected.

Re: Erratum (con'td) by Marko Topolnik

Is the following correct?
class C {
final String s1 =
"this is a compile-time constant";
static final MyString s2 =
new MyString ("this is stored in a field");
static final string s2;
C (string suffix) {
s2 = "this is stored in a field" + suffix;
}
}


Actually, in Java it IS the other way 'round: only references to a static final field can be replaced by their value calculated at compile time. A final field is an instance field and a reference to it is always left as a reference. So, your example should be corrected as follows:

class C {
final String s1 =
"this is a stored in an instance field";
static final String s1a =
"this is a compile-time constant";
static final MyString s2 =
new MyString ("this is stored in a field");
static final string s2;
C (string suffix) {
s2 = "this is stored in a field" + suffix;
}
}

Re: Erratum (con'td) by Stefan Wenig

That's exactly what David was saying. I'm by no means a Java expert, but the only reference to final fields being treated as compiled time constants in the Java specs is §4.12.4, and it seems to contradict your statements.
java.sun.com/docs/books/jls/third_edition/html/...
"We call a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28) a constant variable. Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9) and definite assignment (§16)."

Re: Erratum (con'td) by Marko Topolnik

(I am not sure which of my statements is being disputed, so I assume that it is the claim that only a reference to a static final field can be replaced by its compile-time value.)

The question is not whether something is a constant variable, but whether a REFERENCE to it is replaced by its compile-time value or it is left as a reference to a field.

A reference to a a final instance variable will always be compiled as such: the only way to refer to it is via a reference to the containing instance and in order to obtain such a reference there will always be a constructor involved, making the whole expression of referencing the final field a non-constant expression.

Re: Erratum (con'td) by Stefan Wenig

Sure, I understand so much already, and it would make perfect sense too. I'm just wondering why the specs won't say so. Maybe that's a difference between the reference implemenation and the written specs, or I didn't read the specs carefully enough. Anyway, thanks again for clearing this up.

Re: Erratum (con'td) by Marko Topolnik

As is typical of the JLS, it does specify everything and leaves almost anything open to interpretation, but much of the facts are either difficult to find or are burried deep into the implications of several disparate sections taken together. But, in this particular case you could have gotten to precisely the info you need if you followed one of the links in the passage you cited above: §13.4.9. Again, of all the links it is far from obvious which one will tell you what you need :)

Re: Erratum (con'td) by Marko Topolnik

...and leaves almost anything open to interpretation...

I meant "almost nothing", of course :)

And when rereading that section I realized that once again it is not clear from it what happens to final instance fields because it only talks about static final fields. Of course, a spec does not have the need to spell out any falsity that we mere humans are likely to assume, it only deals with how the things are.

Re: Erratum (con'td) by Stefan Wenig

I think this looks rather like a mistake. While the samples in the section use only static final fields, describing the semantics of final fields and not explicitly noting that the whole section only applies to those that are static makes little sense.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

11 Discuss
BT