|
Home > Tutorials > C# > Microsoft C# versus Java, Part I
|
|
|
|
|
| |
Microsoft C# vs. Java: A Syntactical and Functional Comparison By: Jared Miniman, Cornell University, 10-14-2001 Manager: John Nordlinger When Microsoft sought after its next universal programming language, it surveyed the competition and realized that while the future of programming languages is in object orientation, no language in existence truly fit this model. C#’s purpose is to deliver a fully OOP language, pushing beyond the limitations of Java and C++. Throughout this summary of key expression and conceptual differences between Java and C#, it will be made clear that programming in C# saves the developer a great deal of time not only in code writing but also in eliminating errors from that code.
C# empowers the user with exceptional debugging abilities through the Microsoft intermediate language viewer. This allows you to more or less see “assembly code,” MSIL, for all programming chunks created and therefore create code that is extremely efficient for a given task. Java provides no low-level debugging support.
| Microsoft C# | Java | | Even the deconstruction of a simple application like “Hello World” reveals a great deal about how the .NET runtime makes code calls. | Java bitcode is read into the Java Virtual Machine (JVM); no intermediate language of human recognition is created |
All data is treated as objects, including primitive types (called value types in C#). This is useful because all objects inherit from System.Object and therefore can use a several handy functions predefined for each value type like Equals, GetHashCode, toString, Finalize (for clean-up), etc. Reference types are all the other objects standard to Java. These can point to NULL, unlike the value types, which are required to be non-null. Converting to a reference type from a data type just takes a simple “boxing” call. Boxed objects are created by default and require the least amount of overhead. Unboxed objects provide greater pre-defined functionality.
| Microsoft C# | Java | int foo = 309; // Type value object bar = foo; // Bar is boxed foo int hash = bar.GetHashCode(); // Gets HC
| foo = new java.lang.Integer(309); int hash = foo.hashCode();
|
Multiple main methods are supported within class files.
| Microsoft C# | Java | using System; class Main1 {public static void Main() {...}} class Main2 {public static void Main() {...}} To use Main1, call “csc Fo.cs /main:Main1”
| Only one main method per class file is supported
|
The read-only access modifier allows a value to be determined at run-time in its constructor, then remains immutable throughout the application. Java only has constant (which C# also has), but this value must be determined during compilation.
| Microsoft C# | Java | … public static readonly int specialVal; static specialType() { // Code to do calculations specialVal = someValue; }
| public static int specialVal = knownValue;
|
If desired, C# gives complete control over garbage collection (supports deconstructors), but can be left to intelligently clear up memory after execution. Java forces use of its own garbage collection system.
| Microsoft C# | Java | An optional public method called suggestively Dispose or Cleanup is exposed, which a class user should call when done using an object. Several .NET framework classes use such a Dispose method. Implementation and use of these finalization methods are not required and will be handled automatically by a low-priority thread that scans for abandoned objects. | Java handles all garbage collection automatically and doesn’t suggest the use of finalization methods. |
The passing of objects with keyword “ref” into a function results in the object being written to and returned in its modified form. The “out” keyword does the same thing but does not require pre-initialization of object(s) being passed in.
| Microsoft C# | Java | // Inside main . . . int red; colorObject.getRed(ref int red); … // Now use modified/updated value of red
| // In Java, ref doesn’t exist, so int red; colorObject.getRed(red); … // Value of red won’t change (still 0)
|
Instead of being bound to a function argument list of rigidly-defined size, you can use the “params” keyword to pass in a variable-length list of arguments, more or less passing in an array of length to be determined at run time.
| Microsoft C# | Java | | public void Foo(params items[] i) { … } // Treat arguments as array so don’t // worry about argument list size
| No simple way of passing in a run-time determined number of arguments
|
Use of getter/setter methods allows you to create new objects much more naturally. This lets you treat accessor methods as properties, rather than functions.
| Microsoft C# | Java | Address addr = new Address();
addr.ZipCode = “55555”;
string zip = addr.ZipCode;
| Address addr = new Address(); Addr.SetZipCode(“55555”);
String zip = addr.getZipCode();
|
Objects in C# can be treated as arrays through the utilization of “indexers.” The benefit to this syntax is that you can manage many objects of the same type in a more systematic fashion. It lets you “box” a given number of objects into a single array-like object with very simple syntax.
| Microsoft C# | Java | class foo { public object this[int index] { … } } // Then in main . . . foo sample = new foo(); sample[0] = . . . // use getter sample[1] = . . . // use getter again . . . // Then perform something on foo, which points to // the ordered objects created
| In Java, you can manually create arrays of objects of a given class, but there is no way to do this without using inheritance, thereby creating a new type that is a class that contains several object members of its parent class.
|
Interfaces are essential because multiple inheritance isn’t supported. The “is” keyword allows you to test if a given type is compatible with another type during run time. The “as” keyword first uses the same compatibility test as “is,” but then will perform a cast to the target type if compatibility exists. NULL is returned if the types are not compatible. This is a great way to do safe casts!
| Microsoft C# | Java | if (myControl is ISerializable) { ... } // returns true if myControl implements // ISerializable. If true, you can treat // myControl as an ISerializable ISerializable i = myControl as ISerializable; // Will be non-null iff myControl implements // ISerializable
| if (myControl typeof ISerializable) {...} // Same behavior as in C# ISerializable I = if myControl is ISerializable then perform_Cast else null
|
Case statements in C# can be collapsed such that varying expression evaluations can lead to the same output.
| Microsoft C# | Java | switch (expression) { case (expressionGuess1): case (expressionGuess2): … } // Do the same thing for multiple values
| switch (expression) { case (expressionGuess1): action1; case (expressionGuess2): action1; … } // Do the same thing for multiple values
|
The “foreach” keyword allows you to traverse arrays and collections without having to setup the iteration specification! Hence, you need not define the start/end point—foreach looks at ALL items in the array or collection.
| Microsoft C# | Java | // Inside a function looking at string array foreach (string word in stringArray) {…}
| No equivalent simple keyword in Java
|
Goto is supported. This is useful in “loop-and-a-half” problems, where we can avoid reading a value twice (which means double the software maintenance work should that statement need to be changed). Here is the pseudocode that would drive your actual program snippet:
| Microsoft C# | Java | loop read in a value if value == sentinel then exit process the value end loop | read in a value while value != sentinel process the value read in a value end while |
User-defined conversions (explicit cast behavior) is easily programmed for each class. Also, like in C++, basic operators can be overloaded through user-defined implementations. This is extremely useful when a specific operation needs to be done to the same object over and over again, and intuitive syntax is sought.
| Microsoft C# | Java | Pound h = 139.0F; Ounce o = (Ounce)h; // User-defined cast // If you wish to keep cummulative grade // reports for a student, you could do: GradeReport cumm = new GradeReport(); Foreach(GradeReport report in reportArray) { cumm+= report }
| Must provide explicit toObject cast functions. Again, a matter of syntactic clarity. Basic operators cannot be overloaded, and behavior must be placed in functions.
|
Conclusion: Clearly, C# carries over the programming simplicity of Java, but strides in leaps and bounds to improve code legibility and to make class and method use much more intuitive. By treating all data types as objects, C# defines a true object-oriented programming language. Allowing the developer to make syntactical shortcuts is a proven way to reduce maintenance and testing costs, and C# makes great advances in language structure. Best of all, C# allows a developer to express complex thoughts in a natural way, not to bogged down by complicated API calls and the paranoia over improper garbage collection.
|
|
|
|