The C# language is an object-oriented language that is aimed at enabling programmers to quickly build a wide range of applications for the Microsoft .NET platform. The goal of C# and the .NET platform is to shorten development time by freeing the developer from worrying about several low level plumbing issues such as memory management, type safety issues, building low level libraries, array boundschecking , etc. thus allowing developers to actually spend their time and energy working on their application and business logic instead. As a Java developer the previous sentence could be described as "a short description of the Java language and platform" if the words C# and the .NET platform were replaced with words Java and the Java platform.
What follows is an overview of similarities and differences between the language features and libraries of the C# and Java programming languages based on my experience using both languages. All code snippets below were tested on Microsoft's .NET Framework version 2.0 for C# snippets and Java Platform, Standard Edition version 6 for the Java snippets.
Quick Index















Just like Java, C# has a single rooted class hierarchy where
all classes in C# are subclasses of System.Object
the same way all Java classes are subclasses of
java.lang.Object. The methods of the two languages'
Object classes share some similarities (e.g.
System.Object's ToString() to
java.lang.Object's toString()) and differences
(System.Object does not have analogs to wait(),
notify() or notifyAll() in
java.lang.Object).
NOTE: In C#, the object class can either be written as
object or Object. The lower case "object" is a
C# keyword which is replaced with the class name
"System.Object" during compilation.
There are a large number of syntactic similarities between Java and C#, similarly almost every Java keyword has a C# equivalent except for a few like transient, throws and strictfp. Below is a table of Java and C# keywords with the Java keywords in red while the equivalent C# keywords are in blue.
|
C# keyword |
Java keyword |
C# keyword |
Java keyword |
C# keyword |
Java keyword |
C# keyword |
Java keyword |
|
abstract |
abstract |
extern |
native |
operator |
N/A |
throw |
throw |
|
as |
N/A |
false |
false |
out |
N/A |
true |
true |
|
base |
super |
finally |
finally |
override |
N/A |
try |
try |
|
bool |
boolean |
fixed |
N/A |
params |
... |
typeof |
N/A |
|
break |
break |
float |
float |
partial |
N/A |
uint |
N/A |
|
byte |
N/A |
for |
for |
private |
private |
ulong |
N/A |
|
case |
case |
foreach |
for |
protected |
N/A |
unchecked |
N/A |
|
catch |
catch |
get |
N/A |
public |
public |
unsafe |
N/A |
|
char |
char |
goto |
goto1 |
readonly |
N/A |
ushort |
N/A |
|
checked |
N/A |
if |
if |
ref |
N/A |
using |
import |
|
class |
class |
implicit |
N/A |
return |
return |
value |
N/A |
|
const |
const1 |
in |
N/A |
sbyte |
byte |
virtual |
N/A |
|
continue |
continue |
int |
int |
sealed |
final |
void |
void |
|
decimal |
N/A |
interface |
interface |
set |
N/A |
volatile |
volatile |
|
default |
default |
internal |
protected |
short |
short |
where |
extends |
|
delegate |
N/A |
is |
instanceof |
sizeof |
N/A |
while |
while |
|
do |
do |
lock |
synchronized |
stackalloc |
N/A |
yield |
N/A |
|
double |
double |
long |
long |
static |
static |
: |
extends |
|
else |
else |
namespace |
package |
string |
N/A |
: |
implements |
|
enum |
N/A |
new |
new |
struct |
N/A |
N/A |
strictfp |
|
event |
N/A |
null |
null |
switch |
switch |
N/A |
throws |
|
explicit |
N/A |
object |
N/A |
this |
this |
N/A |
transient2 |
NOTE: Although goto and const are Java
language keywords they are unused in the Java language.
NOTE: The [NonSerialized] attribute in C# is
equivalent to the transient keyword in Java.
Just like Java is typically compiled to Java byte code which
then runs in managed execution environment (the Java Virtual
Machine or JVM) so also is C# code compiled to an Intermediate
Language (IL) which then runs in the Common Language Runtime
(CLR). Both platforms support native compilation via
Just In Time compilers.
NOTE: While the Java platform supports interpretation of byte
code or byte code being JITed then run natively, the .NET
platform only supports native execution of C# code because the
IL code is always natively compiled before running.
In Java objects are created on the heap using the
new keyword. Most classes in C# are created on the heap
by using the new keyword. Also just as the JVM
manages the destruction of objects so also does the CLR via a
Mark and Compact garbage collection algorithm
NOTE: C# also supports stack-based classes, called value types,
which are discussed further below.
In languages like C and C++, each subarray of a multidimensional array must have the same dimensions. In Java and C# arrays do not have to be uniform because jagged arrays can be created as one-dimensional arrays of arrays. In a jagged array the contents of the array are arrays which may hold instances of a type or references to other arrays. For this reason the rows and columns in a jagged array need not have uniform length as can be seen from the following code snippet:
int [][]myArray = new int[2][];
myArray[0] = new int[3];
myArray[1] = new int[9];
The above code snippet is valid for both C# and Java. Just like Java and unlike C++, methods in C# have to be part of a class either as member or static methods.
C#, like Java, supports the concept of an interface which is akin to a pure abstract class. Similarly C# and Java both allow only single inheritance of classes but multiple inheritance (or implementation) of interfaces.
C# has a System.String class which is analogous to the java.lang.String class. Both classes are immutable meaning that the values of the strings cannot be changed once the strings have been created. In both instances methods that appear to modify the actual content of a string actually create a new string to return, leaving the original string unchanged. Thus the following C# and Java code does not modify the string in either case
C# Code
String csString = "Apple Jack";
csString.ToLower(); /* Does not modify string, instead returns lower case copy of string */
Java Code
String jString = "Grapes";
jString.toLowerCase(); /* Does not modify string, instead returns lower case copy of string */
To create a string-like object that allows modification in C#
it is advisable to use the System.Text.StringBuilder class
whereas in Java one would use the java.lang.StringBuffer
class.
string or String. Both Java and C# provide mechanisms to specify that a class
should be the last one in an inheritance hierarchy and cannot
be used as a base class. In Java this is done by preceding the
class declaration with the final keyword while in
C# this is done by preceding the class declaration with the
sealed keyword. Below are examples of classes that
cannot be extended in either language
C# Code
sealed class Student {
string fname;
string lname;
int uid;
void attendClass() {}
}
Java Code
final class Student {
String fname;
String lname;
int uid;
void attendClass() {}
}
NOTE: Although exceptions in both languages support methods for getting a stack trace, only Java exceptions have methods that allow one to alter the stack trace.
C# Code
using System;
using System.IO;
class MyException: Exception{
public MyException(string message): base(message){ }
public MyException(string message, Exception innerException):
base(message, innerException){ }
}
public class ExceptionTest {
static void DoStuff(){
throw new FileNotFoundException();
}
public static void Main(string[] args){
try{
try{
DoStuff();
return; //won't get to execute
}catch(IOException ioe){ /* parent of FileNotFoundException */
throw new MyException("MyException occured", ioe); /* rethrow new exception with inner exception specified */
}
}finally{
Console.WriteLine("***Finally block executes even though MyException not caught***");
}
}//Main(string[])
} // ExceptionTest
Java Code
class MyException extends Exception{
public MyException(String message){ super(message); }
public MyException(String message, Exception innerException){ super(message, innerException); }
}
public class ExceptionTest {
static void doStuff(){
throw new ArithmeticException();
}
public static void main(String[] args) throws Exception{
try{
try{
doStuff();
return; //won't get to execute
}catch(RuntimeException re){ /* parent of ArithmeticException */
throw new MyException("MyException occured", re); /* rethrow new exception with cause specified */
}
}finally{
System.out.println("***Finally block executes even though MyException not caught***");
}
}//main(string[])
} // ExceptionTest
Instance and static variables can be initialized at their point of definition in both C# and Java. If the member variable is an instance variable, then initialization occurs just before the constructor is called. Static members are initialized sometime before the first usage of the member and before the first creation of an instance of the class. It is also possible to specify a block of code that should run before the class is used either via creation of an instance variable or invocation of a static method. These code blocks are called are called static constructors in C# and static initialization blocks in Java. Static constructors are invoked before the first invocation of a static method in the class and before the first time an instance of the class is created.
C# Code
using System;
class StaticInitTest{
string instMember = InitInstance();
string staMember = InitStatic();
StaticInitTest(){
Console.WriteLine("In instance constructor");
}
static StaticInitTest(){
Console.WriteLine("In static constructor");
}
static String InitInstance(){
Console.WriteLine("Initializing instance variable");
return "instance";
}
static String InitStatic(){
Console.WriteLine("Initializing static variable");
return "static";
}
static void DoStuff(){
Console.WriteLine("Invoking static DoStuff() method");
}
public static void Main(string[] args){
Console.WriteLine("Beginning main()");
StaticInitTest.DoStuff();
StaticInitTest sti = new StaticInitTest();
Console.WriteLine("Completed main()");
}
}
Java Code
class StaticInitTest{
String instMember = initInstance();
String staMember = initStatic();
StaticInitTest(){
System.out.println("In instance constructor");
}
static{
System.out.println("In static constructor");
}
static String initInstance(){
System.out.println("Initializing instance variable");
return "instance";
}
static String initStatic(){
System.out.println("Initializing static variable");
return "static";
}
static void doStuff(){
System.out.println("Invoking static DoStuff() method");
}
public static void main(String[] args){
System.out.println("Beginning main()");
StaticInitTest.doStuff();
StaticInitTest sti = new StaticInitTest();
System.out.println("Completed main()");
}
}
OUTPUT FROM BOTH EXAMPLES:
In static constructor
Beginning main()
Invoking static DoStuff() method
Initializing instance variable
Initializing static variable
In instance constructor
Completed main()
In situations where value types need to be treated as
objects, the .NET and Java runtimes automatically converts value
types to objects by wrapping them within a heap-allocated
reference type in a process called boxing. The process of
automatically convert an object to its corresponding value type
such as converting an instance of java.lang.Integer to an
int is known as unboxing. Below are examples of various situations
where boxing occurs in both runtimes.
C# Code
using System;
using System.Collections;
//stack allocated structs also need to be boxed to be treated as objects
struct Point{
//member fields
private int x;
private int y;
public Point (int x, int y){
this.x = x;
this.y = y;
}
public override string ToString(){
return String.Format("({0}, {1})", x, y);
}
}//Point
class Test{
public static void PrintString(object o){
Console.WriteLine(o);
}
public static void Main(string[] args){
Point p = new Point(10, 15);
ArrayList list = new ArrayList();
int z = 100;
PrintString(p); //p boxed to object when passed to PrintString
PrintString(z); //z boxed to object when passed to PrintString
// integers and float boxed when stored in collection
// therefore no need for Java-like wrapper classes
list.Add(1);
list.Add(13.12);
list.Add(z);
for(int i =0; i < list.Count; i++)
PrintString(list[i]);
}
}
Java Code
import java.util.*;
class Test{
public static void PrintString(Object o){
System.out.println(o);
}
public static void PrintInt(int i){
System.out.println(i);
}
public static void main(String[] args){
Vector list = new Vector();
int z = 100;
Integer x = new Integer(300);
PrintString(z); //z boxed to object when passed to PrintString
PrintInt(x); //x unboxed to int when passed to PrintInt
// integers and float boxed when stored in collection
// therefore no need for Java wrapper classes
list.add(1);
list.add(13.12);
list.add(z);
for(int i =0; i < list.size(); i++)
PrintString(list.elementAt(i));
}
}
Main
method in C# begins with an uppercase "M" (as do all
.NET Framework method names, by convention) while the
main method in Java begins with a lowercase
"m" (as do all Java method names, by convention). The
declaration for the main method is otherwise the same in both
cases except for the fact that parameter to the Main() method
in C# can have a void parameter.
C# Code
using System;
class A{
public static void Main(String[] args){
Console.WriteLine("Hello World");
}
}
Java Code
class B{
public static void main(String[] args){
System.out.println("Hello World");
}
}
It is typically recommended that one creates a main method
for each class in an application to test the functionality of
that class besides whatever main method actually drives the
application. For instance it is possible to have two classes, A
and B, which both contain main methods. In Java, since a class
is the unit of compilation then all one has to do is invoke the
specific class one wants run via the command line to run its
main method. In C# one can get the same effect by compiling the
application with the /main switch to specify which main should
be used as the starting point of the application when the
executable is created. Using test mains in combination with
conditional compilation via
preprocessor directives is a powerful testing
technique.
Java Example
C:\CodeSample> javac A.java B.java
C:\CodeSample> java A
Hello World from class A
C:\CodeSample> java B
Hello World from class B
C# Example
C:\CodeSample> csc /main:A /out:example.exe A.cs B.cs
C:\CodeSample> example.exe
Hello World from class A
C:\CodeSample> csc /main:B /out:example.exe A.cs B.cs
C:\CodeSample> example.exe
Hello World from class B
So in Java's favor, one doesn't have to recompile to change which main is used by the application while a recompile is needed in a C# application. However, On the other hand, Java doesn't support conditional compilation, so the main method will be part of even your released classes.
C# uses C++ syntax for inheritance, both for class
inheritance and interface implementation as opposed to the
extends and implements keywords.
C# Code
using System;
class B:A, IComparable{
int CompareTo(){}
public static void Main(String[] args){
Console.WriteLine("Hello World");
}
}
Java Code
class B extends A implements Comparable{
int compareTo(){}
public static void main(String[] args){
System.out.println("Hello World");
}
}
Since C# is aimed at transitioning C++ developers the above syntax is understandable although Java developers may pine for the Java syntax especially since it is clear from looking at the class declaration in the Java version whether the class is subclassing a class or simply implementing an interface while it isn't in the C# version without intimate knowledge of all the classes involved. Although it should be noted that in .NET naming conventions, interface names have an upper-case "I" prepended to their names (as in IClonable), so this isn't an issue for programs that conform to standard naming conventions.
is operator is completely analogous to
Java's instanceof operator. The two code
snippets below are equivalent.
C# Code
if(x is MyClass)
MyClass mc = (MyClass) x;
Java Code
if(x instanceof MyClass)
MyClass mc = (MyClass) x;
A C# namespace is a way to group a collection of classes and
is used in a manner similar to Java's package
construct. Users of C++ will notice the similarities between
the C# namespace syntax and that in C++. In Java, the package
names dictate the directory structure of source files in an
application whereas in C# namespaces do not dictate the
physical layout of source files in directories only their
logical structure. Examples below:
C# Code
namespace com.carnage4life{
public class MyClass {
int x;
void doStuff(){}
}
}
Java Code
package com.carnage4life;
public class MyClass {
int x;
void doStuff(){}
}
C# namespace syntax also allows one to nest
namespaces in the following way
C# Code
using System;
namespace Company{
public class MyClass { /* Company.MyClass */
int x;
void doStuff(){}
}
namespace Carnage4life{
public class MyOtherClass { /* Company.Carnage4life.MyOtherClass */
int y;
void doOtherStuff(){}
public static void Main(string[] args){
Console.WriteLine("Hey, I can nest namespaces");
}
}// class MyOtherClass
}// namespace Carnage4life
}// namespace Company
The syntax and semantics for constructors in C# is identical to that in Java. C# also has the concept of destructors which use syntax similar to C++ destructor syntax but have the mostly the same semantics as Java finalizers. Although finalizers exist doing work within them is not encouraged for a number of reasons including the fact that there is no way to control the order of finalization which can lead to interesting problems if objects that hold references to each other are finalized out of order. Finalization also causes more overhead because objects with finalizers aren't removed after the garbage collection thread runs but instead are eliminated after the finalization thread runs which means they have to be maintained in the system longer than objects without finalizers. Below are equivalent examples in C# and Java.
NOTE: In C#, destructors(finalizers) automatically call the base class finalizer after executing which is not the case in Java.
C# Code
using System;
public class MyClass {
static int num_created = 0;
int i = 0;
MyClass(){
i = ++num_created;
Console.WriteLine("Created object #" + i);
}
~MyClass(){
Console.WriteLine("Object #" + i + " is being finalized");
}
public static void Main(string[] args){
for(int i=0; i < 10000; i++)
new MyClass();
}
}
Java Code
public class MyClass {
static int num_created = 0;
int i = 0;
MyClass(){
i = ++num_created;
System.out.println("Created object #" + i);
}
public void finalize(){
System.out.println("Object #" + i + " is being finalized");
}
public static void main(String[] args){
for(int i=0; i < 10000; i++)
new MyClass();
}
}
lock statement which is semantically
identical to the synchronized statement in Java.
C# Code
public void WithdrawAmount(int num){
lock(this){
if(num < this.amount)
this.amount -= num;
}
}
Java Code
public void withdrawAmount(int num){
synchronized(this){
if(num < this.amount)
this.amount -= num;
}
}
Both C# and Java support the concept of synchronized
methods. Whenever a synchronized method is called, the thread
that called the method locks the object that contains the
method. Thus other threads cannot call a synchronized method on
the same object until the object is unlocked by the first
thread when it finishes executing the synchronized method.
Synchronized methods are marked in Java by using the
synchronized keyword while in C# it is done by
annotating the method with the
[MethodImpl(MethodImplOptions.Synchronized)] attribute.
Examples of synchronized methods are shown below
C# Code
using System;
using System.Runtime.CompilerServices;
public class BankAccount{
[MethodImpl(MethodImplOptions.Synchronized)]
public void WithdrawAmount(int num){
if(num < this.amount)
this.amount - num;
}
}//BankAccount
Java Code
public class BankAccount{
public synchronized void withdrawAmount(int num){
if(num < this.amount)
this.amount - num;
}
}//BankAccount
Below is a table mapping C# access modifiers to Java's.
C++ fans who were disappointed when Sun changed the semantics
of the protected keyword in Java 2 will be happy
to note that the C# protected keyword has the same
semantics as the C++ version. This means that a
protected member can only be accessed by member methods
in that class or member methods in derived classes but is
inaccessible to any other classes. The internal
modifier means that the member can be accessed from other
classes in the same assembly as the
class. The internal protected modifier means that
a member can be accessed from classes that are in the same
assembly or from derived classes.
| C# access modifier | Java access modifier |
| private | private |
| public | public |
| internal | protected |
| protected | N/A |
| internal protected | N/A |
NOTE: The default accessibility of a C# field or method when
no access modifier is specified is private while
in Java it is protected (except that derived
classes from outside the package cannot inherit the field).
C# Code
using System;
using System.Xml;
using System.Reflection;
using System.IO;
class ReflectionSample {
public static void Main( string[] args){
Assembly assembly=null;
Type type=null;
XmlDocument doc=null;
try{
// Load the requested assembly and get the requested type
assembly = Assembly.LoadFrom("C:\\WINNT\\Microsoft.NET\\Framework\\v1.0.2914\\System.XML.dll");
type = assembly.GetType("System.Xml.XmlDocument", true);
//Unfortunately one cannot dynamically instantiate types via the Type object in C#.
doc = Activator.CreateInstance("System.Xml","System.Xml.XmlDocument").Unwrap() as XmlDocument;
if(doc != null)
Console.WriteLine(doc.GetType() + " was created at runtime");
else
Console.WriteLine("Could not dynamically create object at runtime");
}catch(FileNotFoundException){
Console.WriteLine("Could not load Assembly: system.xml.dll");
return;
}catch(TypeLoadException){
Console.WriteLine("Could not load Type: System.Xml.XmlDocument from assembly: system.xml.dll");
return;
}catch(MissingMethodException){
Console.WriteLine("Cannot find default constructor of " + type);
}catch(MemberAccessException){
Console.WriteLine("Could not create new XmlDocument instance");
}
// Get the methods from the type
MethodInfo[] methods = type.GetMethods();
//print the method signatures and parameters
for(int i=0; i < methods.Length; i++){
Console.WriteLine ("{0}", methods[i]);
ParameterInfo[] parameters = methods[i].GetParameters();
for(int j=0; j < parameters.Length; j++){
Console.WriteLine (" Parameter: {0} {1}", parameters[j].ParameterType, parameters[j].Name);
}
}//for (int i...)
}
}
Java Code
import java.lang.reflect.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;
class ReflectionTest {
public static void main(String[] args) {
Class c=null;
Document d;
try{
c = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().getClass();
d = (Document) c.newInstance();
System.out.println(d + " was created at runtime from its Class object");
}catch(ParserConfigurationException pce){
System.out.println("No document builder exists that can satisfy the requested configuration");
}catch(InstantiationException ie){
System.out.println("Could not create new Document instance");
}catch(IllegalAccessException iae){
System.out.println("Cannot access default constructor of " + c);
}
// Get the methods from the class
Method[] methods = c.getMethods();
//print the method signatures and parameters
for (int i = 0; i < methods.length; i++) {
System.out.println( methods[i]);
Class[] parameters = methods[i].getParameterTypes();
for (int j = 0; j < parameters.length; j++) {
System.out.println("Parameters: " + parameters[j].getName());
}
}
}
}
One might notice from the above code samples that there is slightly more granularity in the C# Reflection API than the Java Reflection API as can be seen by the fact that C# has a ParameterInfo class which contains metadata about the parameters of a Method while Java uses Class objects for that which lose some information such as the name of the parameter.
Sometimes there is a need to obtain the metadata of a
specific class encapsulated as an object. This object is the
java.lang.Class object in Java and the
System.Type object in C#. To retrieve this metadata
class from an instance of the target class, the getClass()
method is used in Java while the GetType() method is used in
C#. If the name of the class is known at compile time then one
can avoid creating an instance of the class just to obtain the
metadata class by doing the following
C# Code
Type t = typeof(ArrayList);
Java Code
Class c = java.util.Arraylist.class; /* Must append ".class" to fullname of class */
To declare constants in Java the final keyword
is used. Final variables can be set either at compile time or
run time. In Java, when the final is used on a
primitive it makes the value of the primitive immutable while
when used on object references it makes the reference constant
meaning that the reference can only point to only one object
during its lifetime. Final members can be left uninitialized
when declared but then must be defined in the constructor.
To declare constants in C# the const keyword is
used for compile time constants while the readonly
keyword is used for runtime constants. The semantics of
constant primitives and object references in C# is the same as
in Java.
Unlike C++, it is not possible to specify an immutable class via language constructs in either C# or Java. Neither is it possible to create a reference through which it's impossible to modify a mutable object.
C# Code
using System;
public class ConstantTest{
/* Compile time constants */
const int i1 = 10; //implicitly a static variable
// code below won't compile because of 'static' keyword
// public static const int i2 = 20;
/* run time constants */
public static readonly uint l1 = (uint) DateTime.Now.Ticks;
/* object reference as constant */
readonly Object o = new Object();
/* uninitialized readonly variable */
readonly float f;
ConstantTest() {
// unitialized readonly variable must be initialized in constructor
f = 17.21f;
}
}
Java Code
import java.util.*;
public class ConstantTest{
/* Compile time constants */
final int i1 = 10; //instance variable
static final int i2 = 20; //class variable
/* run time constants */
public static final long l1 = new Date().getTime();
/* object reference as constant */
final Vector v = new Vector();
/* uninitialized final */
final float f;
ConstantTest() {
// unitialized final variable must be initialized in constructor
f = 17.21f;
}
}
NOTE: The Java language also supports having
final parameters to a method. This functionality is
non-existent in C#.
The primary use of final parameters is to allow arguments to a
method to be accessible from within inner
classes declared in the method body.
byte). The
byte type in Java is signed and is thus analagous
to the sbyte type in C# and not the
byte type.C# also has unsigned versions of some
primitives such as ulong, uint, ushort and
byte . The only significantly different primitive in C#
is the decimal type, a type which stores decimal
numbers without rounding errors (at the cost of more space and
less speed).
C# Code
decimal dec = 100.44m; //m is the suffix used to specify decimal numbers
double dbl = 1.44e2d; //e is used to specify exponential notation while d is the suffix used for doubles
C# Code
int[] iArray = new int[100]; //valid, iArray is an object of type int[]
float fArray[] = new float[100]; //ERROR: Won't compile
Java Code
int[] iArray = new int[100]; //valid, iArray is an object of type int[]
float fArray[] = new float[100]; //valid, but isn't clear that fArray is an object of type float[]
C# and Java automatically call base class constructors, and both provide a way to call the constructor of the base class with specific parameters. Similarly both languages enforce that the call to the base class constructor occurs before any initializations in the derived constructor which prevents the derived constructor from using members that are yet to be initialized. The C# syntax for calling the base class constructor is reminiscent of the C++ initializer list syntax.
Both languages also provide a way to call a constructor from another which allows one to reduce the amount of code duplication that can occur in constructors. This practice is typically called constructor chaining.
C# Code
using System;
class MyException: Exception
{
private int Id;
public MyException(string message): this(message, null, 100){ }
public MyException(string message, Exception innerException):
this(message, innerException, 100){ }
public MyException(string message, Exception innerException, int id):
base(message, innerException){
this.Id = id;
}
}
Java Code
class MyException extends Exception{
private int Id;
public MyException(String message){
this(message, null, 100);
}
public MyException(String message, Exception innerException){
this(message, innerException, 100);
}
public MyException( String message,Exception innerException, int id){
super(message, innerException);
this.Id = id;
}
}
In C and C++ it is possible to specify that a function takes
a variable number of arguments. This functionality is used
extensively in the printf and scanf family of functions. Both C#
and Java allow one to define a parameter that indicates that a
variable number of arguments are accepted by a method. In C#, the
mechanism for specifying that a method accepts a variable
number of arguments is by using the params keyword
as a qualifier to the last argument to the method which should
be an array. In Java, the same effect is achieved by appending the
string "..." to the typename of the last argument to the method.
C# Code
using System;
class ParamsTest{
public static void PrintInts(string title, params int[] args){
Console.WriteLine(title + ":");
foreach(int num in args)
Console.WriteLine(num);
}
public static void Main(string[] args){
PrintInts("First Ten Numbers in Fibonacci Sequence", 0, 1, 1, 2, 3, 5, 8, 13, 21, 34);
}
}
Java Code
class Test{
public static void PrintInts(String title, Integer... args){
System.out.println(title + ":");
for(int num : args)
System.out.println(num);
}
public static void main(String[] args){
PrintInts("First Ten Numbers in Fibonacci Sequence", 0, 1, 1, 2, 3, 5, 8, 13, 21, 34);
}
}
Both C# and Java provide a mechanism for creating strongly typed data
structures without knowing the specific types at compile time. Prior to
the existence of the Generics feature set, this capability was achieved
by specifying the type of the objects within the data structure as
Object then casting to specific types at runtime. This
technique had several drawbacks including lack of type safety, poor
performance and code bloat.
The following code sample shows how one would calculate the sum of all the integers in a collection using generics and using a collection of Objects so that both approaches can be compared.
C# Code
using System;
using System.Collections;
using System.Collections.Generic;
class Test{
public static Stack GetStackB4Generics(){
Stack s = new Stack();
s.Push(2);
s.Push(4);
s.Push(5);
return s;
}
public static Stack<int> GetStackAfterGenerics(){
Stack<int> s = new Stack<int>();
s.Push(12);
s.Push(14);
s.Push(50);
return s;
}
public static void Main(String[] args){
Stack s1 = GetStackB4Generics();
int sum1 = 0;
while(s1.Count != 0){
sum1 += (int) s1.Pop(); //cast
}
Console.WriteLine("Sum of stack 1 is " + sum1);
Stack<int> s2 = GetStackAfterGenerics();
int sum2 = 0;
while(s2.Count != 0){
sum2 += s2.Pop(); //no cast
}
Console.WriteLine("Sum of stack 2 is " + sum2);
}
}
Java Code
import java.util.*;
class Test{
public static Stack GetStackB4Generics(){
Stack s = new Stack();
s.push(2);
s.push(4);
s.push(5);
return s;
}
public static Stack<Integer> GetStackAfterGenerics(){
Stack<Integer> s = new Stack<Integer>();
s.push(12);
s.push(14);
s.push(50);
return s;
}
public static void main(String[] args){
Stack s1 = GetStackB4Generics();
int sum1 = 0;
while(!s1.empty()){
sum1 += (Integer) s1.pop(); //cast
}
System.out.println("Sum of stack 1 is " + sum1);
Stack<Integer> s2 = GetStackAfterGenerics();
int sum2 = 0;
while(!s2.empty()){
sum2 += s2.pop(); //no cast
}
System.out.println("Sum of stack 2 is " + sum2);
}
}
Although similar in concept to templates in C++, the Generics feature in C#
and Java is not implemented similarly. In Java, the generic functionality is
implemented using type erasure. Specifically the generic type
information is present only at compile time, after which it is erased by the
compiler and all the type declarations are replaced with Object.
The compiler then automatically inserts casts in the right places. The
reason for this approach is that it provides total interoperability between
generic code and legacy code that doesn't support generics. The main
problem with type erasure is that the generic type information is not
available at run time via reflection or run time type identification. Another
consequence of this approach is that generic data structures types must
always be declared using objects and not primitive types. Thus one must
create Stack<Integer>
instead of Stack<int> when working integers.
In C#, there is explicit support for generics in the .NET runtime's
instruction language (IL). When the generic type is compiled, the
generated IL contains place holders for specific types. At runtime, when
an initial reference is made to a generic type (e.g.
List<int>) the system looks to see if anyone already
asked for the type or not. If the type has been previously requested, then
the previously generated specific type is returned. If not, the JIT
compiler instantiates a new type by replacing the generic type parameters
in the IL with the specific type (e.g. replacing List<T>
with List<int>). 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.
In certain cases, one may need create a method that can operate on data structures containing any type as opposed to those that contain a specific type (e.g. a method to print all the objects in a data structure) while still taking advantage of the benefits of strong typing in generics. The mechanism for specifying this in C# is via a feature called generic type inferencing while in Java this is done using wildcard types. The following code samples show how both approaches lead to the same result.
C# Code
using System;
using System.Collections;
using System.Collections.Generic;
class Test{
//Prints the contents of any generic Stack by
//using generic type inference
public static void PrintStackContents<T>(Stack<T> s){
while(s.Count != 0){
Console.WriteLine(s.Pop());
}
}
public static void Main(String[] args){
Stack<int> s2 = new Stack<int>();
s2.Push(4);
s2.Push(5);
s2.Push(6);
PrintStackContents(s2);
Stack<string> s1 = new Stack<string>();
s1.Push("One");
s1.Push("Two");
s1.Push("Three");
PrintStackContents(s1);
}
}
Java Code
import java.util.*;
class Test{
//Prints the contents of any generic Stack by
//specifying wildcard type
public static void PrintStackContents(Stack<?> s){
while(!s.empty()){
System.out.println(s.pop());
}
}
public static void main(String[] args){
Stack <Integer> s2 = new Stack <Integer>();
s2.push(4);
s2.push(5);
s2.push(6);
PrintStackContents(s2);
Stack<String> s1 = new Stack<String>();
s1.push("One");
s1.push("Two");
s1.push("Three");
PrintStackContents(s1);
}
}
Both C# and Java provide mechanisms for specifying constraints on generic types. In C# there are three types of constraints that can be applied to generic types
C# Code
using System;
using System.Collections;
using System.Collections.Generic;
public class Mammal {
public Mammal(){;}
public virtual void Speak(){;}
}
public class Cat : Mammal{
public Cat(){;}
public override void Speak(){
Console.WriteLine("Meow");
}
}
public class Dog : Mammal{
public Dog(){;}
public override void Speak(){
Console.WriteLine("Woof");
}
}
public class MammalHelper<T> where T: Mammal /* derivation constraint */,
new() /* default constructor constraint */{
public static T CreatePet(){
return new T();
}
public static void AnnoyNeighbors(Stack<T> pets){
while(pets.Count != 0){
Mammal m = pets.Pop();
m.Speak();
}
}
}
public class Test{
public static void Main(String[] args){
Stack<Mammal> s2 = new Stack<Mammal>();
s2.Push(MammalHelper<Dog>.CreatePet());
s2.Push(MammalHelper<Cat>.CreatePet());
MammalHelper<Mammal>.AnnoyNeighbors(s2);
}
}
Java Code
import java.util.*;
abstract class Mammal {
public abstract void speak();
}
class Cat extends Mammal{
public void speak(){
System.out.println("Meow");
}
}
class Dog extends Mammal{
public void speak(){
System.out.println("Woof");
}
}
public class Test{
//derivation constraint applied to pets parameter
public static void AnnoyNeighbors(Stack<? extends Mammal> pets){
while(!pets.empty()){
Mammal m = pets.pop();
m.speak();
}
}
public static void main(String[] args){
Stack<Mammal> s2 = new Stack<Mammal>();
s2.push(new Dog());
s2.push(new Cat());
AnnoyNeighbors(s2);
}
}
C# also includes the default operator which returns the
default value for a type. The default value for reference types is
null, and the default value for value types (such as integers,
enum, and structures) is a zero whitewash (filling the structure with zeros).
This operator is very useful when combined with generics. The following
code sample excercises the functionality of this operator.
C# Code
using System;
public class Test{
public static T GetDefaultForType(){
return default(T); //return default value of type T
}
public static void Main(String[] args){
Console.WriteLine(GetDefaultForType<int>());
Console.WriteLine(GetDefaultForType<string>());
Console.WriteLine(GetDefaultForType<float>());
}
}
The for-each loop is an iteration construct that
is popular in a number of scripting languages (e.g. Perl, PHP,
Tcl/Tk), build tools (GNU Make) and function libraries
(e.g. for_each in <algorithm> in C++).
The for-each loop is a less verbose way to iterate
through arrays or classes that implement the the
System.Collections.IEnumerable interface in C# or the
java.lang.Iterable interface in Java.
In C#, the keywords foreach and in
are used when creating the for-each loop while in Java the
keyword for and the operator : are
used.
C# Code
string[] greek_alphabet = {"alpha", "beta", "gamma", "delta", "epsilon"};
foreach(string str in greek_alphabet)
Console.WriteLine(str + " is a letter of the greek alphabet");
Java Code
String[] greek_alphabet = {"alpha", "beta", "gamma", "delta", "epsilon"};
for(String str : greek_alphabet)
System.out.println(str + " is a letter of the greek alphabet");
Metadata annotations provide a powerful way to extend the capabilities of a programming language and the language runtime. These annotations can be directives that request the runtime to perform certain additional tasks, provide extra information about an item or extend the abilities of a type. Metadata annotations are common in a number of programming environments including Microsoft's COM and the Linux kernel.
C# attributes provide a way to add annotations (i.e. metadata) to a module, type, method, parameter or member variable. Below are descriptions of a few attributes that are intrinsic to .NET and how they are used to extend the capabilities of the C#.
[MethodImpl(MethodImplOptions.Synchronized)]: is used
to specify that a access to a method by multiple threads is
protected by a lock to prevent concurrent access to the
method and is similar to the synchronized in
Java.[Serializable]: is used to mark a class as
serializable and is similar to a Java class implementing the
Serializable interface.[FlagsAttribute]: is used to specify that an
enum should support bitwise operations. This is
particularly important for enumerations where the target
can have multiple values.
C# Code
//declaration of bit field enumeration
[Flags]
enum ProgrammingLanguages{
C = 1,
Lisp = 2,
Basic = 4,
All = C | Lisp | Basic
}
aProgrammer.KnownLanguages = ProgrammingLanguages.Lisp; //set known languages ="Lisp"
aProgrammer.KnownLanguages |= ProgrammingLanguages.C; //set known languages ="Lisp C"
aProgrammer.KnownLanguages &= ~ProgrammingLanguages.Lisp; //set known languages ="C"
if((aProgrammer.KnownLanguages & ProgrammingLanguages.C) > 0){ //if programmer knows C
//.. do something
}
[WebMethod]: is used in combination with
ASP.NET to specify that a method should be available over the
web as a web service automatically. Doing the same in Java
involves
configuring JAXP, UDDI, and J2EE as well as have to create an
Enterprise Java Bean which involves at least two
interfaces and one implementation class plus setting up the
deployment descriptor. For more information on webservices in
C#, examine the
Your First C# Web Service page on CodeProject. It is possible to access the attributes of a module, class,
method or field via reflection. This
is particularly useful for seeing if a class supports certain
behavior at runtime or for extracting metadata about a class
for usage by others. Developers can create their own custom
attributes by subclassing the System.Attribute
class. What follows is an example of using an attribute to
provide information about the author of a class then using
reflection to access that information.
C# Code
using System;
using System.Reflection;
[AttributeUsage(AttributeTargets.Class)]
public class AuthorInfoAttribute: System.Attribute{
string author;
string email;
string version;
public AuthorInfoAttribute(string author, string email){
this.author = author;
this.email = email;
}
public string Version{
get{
return version;
}
set{
version = value;
}
}
public string Email{
get{
return email;
}
}
public string Author{
get{
return author;
}
}
}
[AuthorInfo("Dare Obasanjo", "kpako@yahoo.com", Version="1.0")]
class HelloWorld{
}
class AttributeTest{
public static void Main(string[] args){
/* Get Type object of HelloWorld class */
Type t = typeof(HelloWorld);
Console.WriteLine("Author Information for " + t);
Console.WriteLine("=================================");
foreach(AuthorInfoAttribute att in t.GetCustomAttributes(typeof(AuthorInfoAttribute), false)){
Console.WriteLine("Author: " + att.Author);
Console.WriteLine("Email: " + att.Email);
Console.WriteLine("Version: " + att.Version);
}//foreach
}//Main
}
Java annotations provide a way to add annotations (i.e. metadata) to an package, type, method, parameter, member or local variable. There are only three built-in annotations provided in the Java language which are listed below.
@Override: is used to specify that a method is
intended to override a method in a base class. If the annotated
method does not override a method in the base class then an
error is issued during compilation.
@Deprecated: is used to indicate that a
particular method has been deprecated. If the annotated method
is used then a warning is issued during compilation.
@SuppressWarnings: is used to prevent particular
warnings from being issued by the compiler. This annotation
optionally takes the name of the specific warning to suppress
as an argument.
As in C# it is possible to access the annotations on a
module, class, method or field via
reflection. However a key difference
between C# attributes and Java annotations is that one can
create meta-annotations (i.e. annotations on annotations) in
Java but can not do the same in C#. Developers can create
their own custom annotations by creating an annotation type
which is similar to an interface except that the keyword
@interface is used to define it.
What follows is an example of using an attribute to
provide information about the author of a class then using
reflection to access that information.
Java Code
import java.lang.annotation.*;
import java.lang.reflect.*;
@Documented //we want the annotation to show up in the Javadocs
@Retention(RetentionPolicy.RUNTIME) //we want annotation metadata to be exposed at runtime
@interface AuthorInfo{
String author();
String email();
String version() default "1.0";
}
@AuthorInfo(author="Dare Obasanjo", email="kpako@yahoo.com")
class HelloWorld{
}
public class Test{
public static void main(String[] args) throws Exception{
/* Get Class object of HelloWorld class */
Class c = Class.forName("HelloWorld");
AuthorInfo a = (AuthorInfo) c.getAnnotation(AuthorInfo.class);
System.out.println("Author Information for " + c);
System.out.println("=======================================");
System.out.println("Author: " + a.author());
System.out.println("Email: " + a.email());
System.out.println("Version: " + a.version());
}
}
Enums are used to create and group together a list of user
defined named constants. Although on the surface the enumerated
types in C# and Java seem quite similar there are some
significant differences in the implementation of enumerated
types in both languages. In Java, enumerated types are a full
fledged class which means they are typesafe and can be extended
by adding methods, fields or even implementing interfaces.
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.
The following code sample highlights the differences between enums in both languages.
C# Code
using System;
public enum DaysOfWeek{
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
}
public class Test{
public static bool isWeekDay(DaysOfWeek day){
return !isWeekEnd(day);
}
public static bool isWeekEnd(DaysOfWeek day){
return (day == DaysOfWeek.SUNDAY || day == DaysOfWeek.SATURDAY);
}
public static void Main(String[] args){
DaysOfWeek sun = DaysOfWeek.SUNDAY;
Console.WriteLine("Is " + sun + " a weekend? " + isWeekEnd(sun));
Console.WriteLine("Is " + sun + " a week day? " + isWeekDay(sun));
/* Example of how C# enums are not type safe */
sun = (DaysOfWeek) 1999;
Console.WriteLine(sun);
}
}
Java Code
enum DaysOfWeek{
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY;
public boolean isWeekDay(){
return !isWeekEnd();
}
public boolean isWeekEnd(){
return (this == SUNDAY || this == SATURDAY);
}
}
public class Test{
public static void main(String[] args) throws Exception{
DaysOfWeek sun = DaysOfWeek.SUNDAY;
System.out.println("Is " + sun + " a weekend? " + sun.isWeekEnd());
System.out.println("Is " + sun + " a week day? " + sun.isWeekDay());
}
}
In Java and C# it is possible to nest class declarations within each other. In Java there are two kinds of nested classes; non-static nested classes also known as inner classes and static nested classes. 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. On the other hand a Java static nested class is a similar to nesting a class decaration within another where the nested class has access to the static members and methods of the enclosing class.
C# has the equivalent of Java's static nested classes but has nothing analogous to Java's inner classes. The following nested class declarations below are equivalent
C# Code
public class Car{
private Engine engine;
private class Engine{
string make;
}
}
Java Code
public class Car{
private Engine engine;
private static class Engine{
String make;
}
}
NOTE: In Java a nested class can be declared in any block of code including methods, this is not the case in C#. The ability to create nested classes in methods in Java may seem unnecessary but combined with anonymous inner classes can provide a means of creating powerful design patterns.
A thread is a sequential flow of control within a program. A program or process can have multiple threads running concurrently all of which may share data or run independently while performing tasks. Threads are powerful in that they allow a developer to perform multiple tasks at once in a single program or process. Advantages of threads include exploiting parallelism in multiprocessor architectures, reducing execution time by being able to perform tasks while waiting on a blocking system calls (such as printing or other I/O), and avoiding freezing in GUI applications.
Java threads are created by subclassing the
java.lang.Thread class and overriding its run() method
or by implementing the java.lang.Runnable
interface and implementing the run() method. Whereas in C#, one
creates a thread by creating a new
System.Threading.Thread object and passing it a
System.Threading.ThreadStart
delegate which is initialized with the method that is to be
run as a thread. Thus, in Java a method that shall run in a
multithreaded context is designed up front specifically with
that in mind. On the other hand, in C# any method can be passed
to a ThreadStart object and run in a multithreaded
scenario.
In Java, every class inherits the wait(), notify() and
notifyAll() from java.lang.Object which are used
for thread operations. The equivalent methods in C# are the
Wait(), Pulse() and PulseAll() methods in the
System.Threading.Monitor class.
The example below shows a scenario where worker threads are dispatched in a specific order and must be processed in the same order upon return. Due to the non-deterministic nature of threads, on some runs the threads finish working in the order they were dispatched in and in other runs they appear out of order and thus each thread must wait until its turn comes up.
C# Code
using System;
using System.Threading;
using System.Collections;
public class WorkerThread{
private int idNumber;
private static int num_threads_made = 1;
private ThreadSample owner;
public WorkerThread(ThreadSample owner){
idNumber = num_threads_made;
num_threads_made++;
this.owner = owner;
}/* WorkerThread() */
//sleeps for a random amount of time to simulate working on a task
public void PerformTask(){
Random r = new Random((int) DateTime.Now.Ticks);
int timeout = (int) r.Next() % 1000;
if(timeout < 0)
timeout *= -1;
//Console.WriteLine(idNumber + ":A");
try{
Thread.Sleep(timeout);
} catch (ThreadInterruptedException e){
Console.WriteLine("Thread #" + idNumber + " interrupted");
}
//Console.WriteLine(idNumber + ":B");
owner.workCompleted(this);
}/* performTask() */
public int getIDNumber() {return idNumber;}
} // WorkerThread
public class ThreadSample {
private static Mutex m = new Mutex();
private ArrayList threadOrderList = new ArrayList();
private int NextInLine(){
return (int) threadOrderList[0];
}
private void RemoveNextInLine(){
threadOrderList.RemoveAt(0);
//all threads have shown up
if(threadOrderList.Count == 0)
Environment.Exit(0);
}
public void workCompleted(WorkerThread worker){
try{
lock(this){
while(worker.getIDNumber() != NextInLine()){
try {
//wait for some other thread to finish working
Console.WriteLine ("Thread #" + worker.getIDNumber() + " is waiting for Thread #" +
NextInLine() + " to show up.");
Monitor.Wait(this, Timeout.Infinite);
} catch (ThreadInterruptedException e) {}
}//while
Console.WriteLine("Thread #" + worker.getIDNumber() + " is home free");
//remove this ID number from the list of threads yet to be seen
RemoveNextInLine();
//tell the other threads to resume
Monitor.PulseAll(this);
}
}catch(SynchronizationLockException){Console.WriteLine("SynchronizationLockException occurred");}
}
public static void Main(String[] args){
ThreadSample ts = new ThreadSample();
/* Launch 25 threads */
for(int i=1; i <= 25; i++){
WorkerThread wt = new WorkerThread(ts);
ts.threadOrderList.Add(i);
Thread t = new Thread(new ThreadStart(wt.PerformTask));
t.Start();
}
Thread.Sleep(3600000); //wait for it all to end
}/* main(String[]) */
}//ThreadSample
Java Code
import java.util.*;
class WorkerThread extends Thread{
private Integer idNumber;
private static int num_threads_made = 1;
private ThreadSample owner;
public WorkerThread(ThreadSample owner){
super("Thread #" + num_threads_made);
idNumber = new Integer(num_threads_made);
num_threads_made++;
this.owner = owner;
start(); //calls run and starts the thread.
}/* WorkerThread() */
//sleeps for a random amount of time to simulate working on a task
public void run(){
Random r = new Random(System.currentTimeMillis());
int timeout = r.nextInt() % 1000;
if(timeout < 0)
timeout *= -1 ;
try{
Thread.sleep(timeout);
} catch (InterruptedException e){
System.out.println("Thread #" + idNumber + " interrupted");
}
owner.workCompleted(this);
}/* run() */
public Integer getIDNumber() {return idNumber;}
} // WorkerThread
public class ThreadSample{
private Vector threadOrderList = new Vector();
private Integer nextInLine(){
return (Integer) threadOrderList.firstElement();
}
private void removeNextInLine(){
threadOrderList.removeElementAt(0);
//all threads have shown up
if(threadOrderList.isEmpty())
System.exit(0);
}
public synchronized void workCompleted(WorkerThread worker){
while(worker.getIDNumber().equals(nextInLine())==false){
try {
//wait for some other thread to finish working
System.out.println (Thread.currentThread().getName() + " is waiting for Thread #" +
nextInLine() + " to show up.");
wait();
} catch (InterruptedException e) {}
}//while
System.out.println("Thread #" + worker.getIDNumber() + " is home free");
//remove this ID number from the list of threads yet to be seen
removeNextInLine();
//tell the other threads to resume
notifyAll();
}
public static void main(String[] args) throws InterruptedException{
ThreadSample ts = new ThreadSample();
/* Launch 25 threads */
for(int i=1; i <= 25; i++){
new WorkerThread(ts);
ts.threadOrderList.add(new Integer(i));
}
Thread.sleep(3600000); //wait for it all to end
}/* main(String[]) */
}//ThreadSample
In many situations one cannot guarantee that the order of
execution of a program will be the same as that in the source
code. Reasons for the unexpected ordering of program execution
include compiler optimizations that reorder statements or
mulitiprocessor systems that fail to store variables in global
memory amongst others. To work around this, both C# and Java
have the concept of the volatile keyword which is
used to tell the language runtime that reordering instructions
related to accessing such fields is prohibited. There are
major differences in the semantics of volatile
in Java and C# which are illustrated in the example below taken
from
The "Double-Checked Locking is Broken"
Declaration
C# Code
/* Used to lazily instantiate a singleton class */
/* WORKS AS EXPECTED */
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
lock(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Java Code
/* Used to lazily instantiate a singleton class */
/* BROKEN UNDER CURRENT SEMANTICS FOR VOLATILE */
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Although the above code snippets seem identical save for the
substitution of the synchronized keyword with the
lock keyword, the Java version is not guaranteed
to work on all JVMs. Currently the Java Memory Model does not
prevent reordering of writes to volatile variables with writes
to other variables so it is possible that the new object is
constructed before the helper reference is made to point at the
newly created object meaning that two objects are created. Also
it is possible that the helper reference is made to point at a
block of memory while the object is still being created meaning
that a reference to an incomplete object will be returned. In
C#, the semantics of volatile prevent such
problems from occurring because reads and writes cannot be
moved backward or forward across a volatile write. Also in C#,
being marked as volatile also prevents the Just In
Time compiler from placing the variable in a register and also
ensures that the variable is stored in global memory on
multiprocessor systems.
For more information on the problems with the Java Memory Model and Double-Checked Locking, see the Double-checked locking: Clever, but broken article on Javaworld.
Operator overloading allows standard operators in a language to be given new semantics when applied in the context of a particular class or type. Operator overloading can be used to simplify the syntax of certain operations especially when they are performed very often, such as string concatenation in Java or interactions with iterators and collections in the C++ Standard Template Library.
Operator overloading is a point of contention for many
developers due to the fact that it provides a lot of
flexibility and power which makes it prone to abuse. There is a
tendency for developers to use it poorly by doings like
overloading operators in an unintuitive manner (e.g.
overloading ++ and -- to connect and
disconnect from the network) , overloading operators in a
manner inconsistent with their typical use (e.g. overloading
[ ] to return a copy of an object at a
particular index in a collection instead of a reference to the
actual object) or overloading some operators and not others
(e.g. overloading < but not
>).
Overloading operators tends to be most useful when the class
lends itself intuitively to using that operator. Examples of
situations that intuitively suggest that operator overloading
would be beneficial are overloading [ ] for use
with collections, overloading + and *
for use with matrices, overloading mathematical operators for
use with complex numbers, and overloading the ==
and != operators for classes that have some means
to measure equality. Below is an example that shows how
operator overloading works in C#.
NOTE: Unlike C++, C# does not allow the overloading of the
following operators; new, ( ),
||, &&, =, or any
variations of compound assignments such as +=,
-=, etc. However, compound assignment operators
will call overloaded operators, for instance, += would call
overloaded +.
C# Code
using System;
class OverloadedNumber{
private int value;
public OverloadedNumber(int value){
this.value = value;
}
public override string ToString(){
return value.ToString();
}
public static OverloadedNumber operator -(OverloadedNumber number){
return new OverloadedNumber(-number.value);
}
public static OverloadedNumber operator +(OverloadedNumber number1, OverloadedNumber number2){
return new OverloadedNumber(number1.value + number2.value);
}
public static OverloadedNumber operator ++(OverloadedNumber number){
return new OverloadedNumber(number.value + 1);
}
}
public class OperatorOverloadingTest {
public static void Main(string[] args){
OverloadedNumber number1 = new OverloadedNumber(12);
OverloadedNumber number2 = new OverloadedNumber(125);
Console.WriteLine("Increment: {0}", ++number1);
Console.WriteLine("Addition: {0}", number1 + number2);
}
} // OperatorOverloadingTest
switch
statement in C# versus that in Java. In C#, switch
statements support the use of string literals and do not allow
fall-through unless the label contains no statements.
Fall-throughs are explicitly disallowed because they are a
leading cause of hard-to-find bugs in software.
C# Code
switch(foo){
case "A":
Console.WriteLine("A seen");
break;
case "B":
case "C":
Console.WriteLine("B or C seen");
break;
/* ERROR: Won't compile due to fall-through at case "D" */
case "D":
Console.WriteLine("D seen");
case "E":
Console.WriteLine("E seen");
break;
}
C# assemblies share a lot in common with Java JAR files. An assembly is the fundamental unit of code packaging in the .NET environment. Assemblies are self contained and typically contain the intermediate code from compiling classes, metadata about the classes, and any other files needed by the packaged code to perform its task.
Since assemblies are the fundamental unit of code packaging, several actions related to interacting with types must be done at the assembly level. For instance, granting of security permissions, code deployment, and versioning are done at the assembly level. Java JAR files perform a similar task in Java with most differences being in the implementation. Assemblies are usually stored as EXEs or DLLs while JAR files are stored in the ZIP file format.
A number of popular programming languages contain a collections framework which typically consists of a number of data structures for holding multiple objects as well as algorithms for manipulating the objects within the aforementioned data structures. The primary advantage of a collections framework is that it frees developers from having to write data structures and sort algorithms every time one is needed and instead frees them up to work on the actual application logic. A secondary benefit is that collections frameworks lead to consistency across projects which means the learning curve for new developers using applications that use a collections framework is less steep when compared to a situation where one was not used.
The C# collections framework consists of the classes in the
System.Collections and the
System.Collections.Generic namespaces. The
Systems.Collections namespace contains interfaces and
abstract classes that represent abstract data types such as
IList, IEnumerable, IDictionary, ICollection, and
CollectionBase which enable developers to manipulate data
structures independently of how they are actually implemented
as long as the data structures inherit from the abstract data
types. The System.Collections namespace also
contains some concrete implementations of data structures such
as ArrayList, Stack, Queue, HashTable and SortedList. All four of the
concrete data structure implementations enable one to obtain
synchronized wrappers to the collection which allows for access
in a thread-safe manner. The
System.Collections.Generic namespace has generic
implementations of the key data structures in the
System.Collections namespace including generic
List<T>, Stack<T>,Queue<T>, Dictionary<K,T>
and SortedDictionary<K,T> classes .
The Java collections framework consists of a large number of
the classes and interfaces in the java.util
package. Instead of having a separate namespace
for generic collections, the collections in the java.util
package have been retrofitted to support generics.
The Java collection framework is similar to that in C#
except for the fact that it can be considered a superset of the
C# collection framework since it contains a number of extra
features. The Java collection framework contains data
structures that are missing from those in C# such as sets and
linked lists. Also the Java collections framework not only has
methods that enable one to access unsafe collections in a
thread safe manner but contains thread-safe versions of most of
the data structures as well. Finally, the Java collections
framework has a number of algorithms for manipulating the
elements within the data structures including algorithms that
can do the following; find the largest element based on some
Comparator, find the smallest element, find sublists within a
list, reverse the contents of a list, shuffle the contents of a
list, creates immutable versions of a colection, performs
sorts, and binary searches.
At the current time, the Java collections framework is more sophisticated than that available in .NET via C#.
Unlike Java, C# contains the goto statement
which can be used to jump directly from a point in the code to
a label. Although much derided, gotos can be used in certain
situations to reduce code duplication while enhancing
readability. A secondary usage of the goto
statement is the ability to mimic resumeable exceptions like
those in Smalltalk, as long as the exception thrown does not
cross method boundaries.
NOTE: In C#, one cannot jump into a statement block
using the goto statement;
C# Code
using System;
using System.Net.Sockets;
class GotoSample{
public static void Main(string[] args){
int num_tries = 0;
retry:
try{
num_tries++;
Console.WriteLine("Attempting to connect to network. Number of tries =" + num_tries);
//Attempt to connect to a network times out
//or some some other network connection error that
//can be recovered from
throw new SocketException();
}catch(SocketException){
if(num_tries < 5)
goto retry;
}
}/* Main(string[]) */
}//GotoSample
One of the tenets of object oriented programming is polymorphism. Polymorphism enables one to interact with members of a type hierarchy as generic types instead of dealing with specific types. The means of implementing polymorphism typically involves having methods in a base class that may be overidden by derived classes. These methods can be invoked even though the client has a reference to a base class type which points to an object of the derived class. Such methods are bound at runtime instead of being bound during compilation and are typically called virtual methods.
In Java all methods are virtual methods while in C#, as in
C++, one must explicitly state which methods one wants to be
virtual since by default they are not. To mark a method as
virtual in C#, one uses the virtual keyword. Also,
implementers of a child class can decide to either explicitly
override the virtual method by using the override
keyword or explicitly choose not to by using the
new keyword instead. By default, in C#, the behavior of
methods in a derived class that have the same signature as
those in the base class is as if they were declared with the
new keyword.
It is possible to mark methods as final in Java
which means that the method cannot be overridden by derived
classes. In C# this can be done by not marking the method as
virtual. The major difference is that in C#, the
class can still define the method but the base class version is
the one that will be called if the object is used via a base
class reference. Java disallows the derived class from
containing a method that has the same signature as the final
base class method.
Below are examples that show the differences in virtual methods in both languages.
C# Code
using System;
public class Parent{
public void DoStuff(string str){
Console.WriteLine("In Parent.DoStuff: " + str);
}
}
public class Child: Parent{
public void DoStuff(int n){
Console.WriteLine("In Child.DoStuff: " + n);
}
public void DoStuff(string str){
Console.WriteLine("In Child.DoStuff: " + str);
}
}
public class VirtualTest{
public static void Main(string[] args){
Child ch = new Child();
ch.DoStuff(100);
ch.DoStuff("Test");
((Parent) ch).DoStuff("Second Test");
}
}//VirtualTest
OUTPUT:
In Child.DoStuff: 100
In Child.DoStuff: Test
In Parent.DoStuff: Second Test
Java Code
class Parent{
public void DoStuff(String str){
System.out.println("In Parent.DoStuff: " + str);
}
}
class Child extends Parent{
public void DoStuff(int n){
System.out.println("In Child.DoStuff: " + n);
}
public void DoStuff(String str){
System.out.println("In Child.DoStuff: " + str);
}
}
public class VirtualTest{
public static void main(String[] args){
Child ch = new Child();
ch.DoStuff(100);
ch.DoStuff("Test");
((Parent) ch).DoStuff("Second Test");
}
}//VirtualTest
OUTPUT:
In Child.DoStuff: 100
In Child.DoStuff: Test
In Child.DoStuff: Second Test
The C# example can be made to produce the same output as the
Java example by marking the DoStuff(string) method in the
Parent class as virtual and marking the
DoStuff(string) method in the Child class with the
override keyword.
C# Code
using System;
public class Parent{
public virtual void DoStuff(string str){
Console.WriteLine("In Parent.DoStuff: " + str);
}
}
public class Child: Parent{
public void DoStuff(int n){
Console.WriteLine("In Child.DoStuff: " + n);
}
public override void DoStuff(string str){
Console.WriteLine("In Child.DoStuff: " + str);
}
}
public class VirtualTest{
public static void Main(string[] args){
Child ch = new Child();
ch.DoStuff(100);
ch.DoStuff("Test");
((Parent) ch).DoStuff("Second Test");
}
}//VirtualTest
OUTPUT:
In Child.DoStuff: 100
In Child.DoStuff: Test
In Child.DoStuff: Second Test
The above example can be made to produce the original results by altering the signature of the DoStuff(string) method in the Child class to
public new void DoStuff(string str)
which states that although the DoStuff method is virtual in the
base class, the child class would like to treat it as a
non-virtual method. Both languages support performing I/O via Stream classes. The examples below copy the contents of a file named "input.txt" to another called "output.txt".
C# Code
using System;
using System.IO;
public class FileIOTest {
public static void Main(string[] args){
FileStream inputFile = new FileStream("input.txt", FileMode.Open);
FileStream outputFile = new FileStream("output.txt", FileMode.Open);
StreamReader sr = new StreamReader(inputFile);
StreamWriter sw = new StreamWriter(outputFile);
String str;
while((str = sr.ReadLine())!= null)
sw.Write(str);
sr.Close();
sw.Close();
}
}//FileIOTest
Java Code
import java.io.*;
public class FileIO{
public static void main(String[] args) throws IOException {
File inputFile = new File("input.txt");
File outputFile = new File("output.txt");
FileReader in = new FileReader(inputFile);
BufferedReader br = new BufferedReader(in);
FileWriter out = new FileWriter(outputFile);
BufferedWriter bw = new BufferedWriter(out);
String str;
while((str = br.readLine())!= null)
bw.write(str);
br.close();
bw.close();
}
}//FileIOTest
Object Persistence also known as Serialization is the ability to read and write objects via a stream such as a file or network socket. Object Persistence is useful in situations where the state of an object must be retained across invocations of a program. Usually in such cases simply storing data in a flat file is insufficient yet using a Database Management System (DBMS) is overkill. Serialization is also useful as a means of transferring the representation of a class in an automatic and fairly seamless manner.
Serializable objects in C# are annotated with the
[Serializabl