This is a comparison of the C# programming language with the Java programming language. As the two are both garbage-collected runtime-compiled languages with syntax derived from C and C++, there are many similarities between Java and C#. However, there are also many differences, with C# being described as a hybrid of C++ and Java, with additional new features and changes. This page documents the strong general similarities of the languages and then points out those instances where the languages differ.
Object handling
Both C# and also Java are designed from the ground up as object oriented languages using dynamic dispatch, with a syntax similar to C++. (C++ in turn is derived from C.) Neither language is a superset of C or C++, however. Both use garbage collection as a means of reclaiming memory resources, rather than explicit deallocation of memory. Both include thread synchronization mechanisms as part of their language syntax.
References
C# allows restricted use of pointers. Pointers and pointer-arithmetic are potentially unsafe in a managed environment as they can be used to bypass the strict rules for object access. C# addresses that concern by requiring that code blocks or methods that use the feature be marked with the unsafe keyword, so that all clients of such code can be aware that the code may be less secure than otherwise. The compiler requires the /unsafe switch to allow compilation of a program that uses such code. Generally, unsafe code is either used to allow better interoperability with unmanaged APIs or system calls (which are inherently "unsafe"), or for performance reasons. Java does not allow pointers or pointer-arithmetic to be used.
Data types
Both languages support the idea of primitive types (all of which, except for String, are value types in C#/.NET). C# has more primitive types than Java, with unsigned as well as signed integer types being supported, and a decimal type for decimal floating-point calculations. Java lacks unsigned types. In particular, Java lacks a primitive type for an unsigned byte, while C# bytes are unsigned by default. Strings are treated as (immutable) objects in both languages, but support for string literals provides a specialized means of constructing them. C# also allows verbatim strings for quotation without escape sequences, which also allow newlines.
Both allow automatic boxing and unboxing to translate primitive data to and from their object form. Effectively, this makes the primitive types a subtype of the Object type. In C# this also means that primitive types can define methods, such as an override of Object's ToString() method. In Java, separate primitive wrapper classes provide such functionality. In Java primitive values are not implicitly boxed when dereferenced and an explicit cast is required for an instance call on a primitive value ((Integer)42).toString() instead of a C# instance call 42.ToString(). Another difference is that Java makes heavy use of boxed types in generics (see below), and as such allows an implicit unboxing conversion (in C# this requires a cast). As these implicit unboxing conversions can potentially throw null pointer exceptions, modern integrated development environments and compilers can be configured to highlight them.
Value types
C# allows the programmer to create user-defined value types, using the struct keyword. From the programmer's perspective, they can be seen as lightweight classes. Unlike regular classes, and like the standard primitives, such value types are allocated on the stack rather than on the heap. They can also be part of an object (either as a field or boxed), or stored in an array, without the memory indirection that normally exists for class types. Structs also come with a number of limitations. Because structs have no notion of a null value and can be used in arrays without initialization, they always come with an implicit default constructor that essentially fills the struct memory space with zeroes. The programmer can only define additional constructors with one or more arguments. This also means that structs lack a virtual method table, and because of that (and the fixed memory footprint), they cannot allow inheritance (but can implement interfaces).
Enumerations
Enumerations in C# are derived from a primitive 8, 16, 32, or 64 bit integer type. Any value of the underlying primitive type is a valid value of the enumeration type, though an explicit cast may be needed to assign it. C# also supports bitmapped enumerations where an actual value may be a combination of enumerated values bitwise or'ed together. Enumerations in Java, on the other hand, are objects. The only valid values in a Java enumeration are the ones listed in the enumeration. As objects, each enumeration can contain its own fields which can be modified. Special enumeration set and map collections provide fully type-safe functionality with minimal overhead. Java enumerations allow differing method implementations for each value in the enumeration. Both C# and Java enumerations can be converted to strings and can be used in a switch statement.
Arrays
Array and collection types are also given significance in the syntax of both languages, thanks to an iterator-based foreach statement loop. In C# an array corresponds to an object of the Array class, while in Java each array is a direct subclass of the Object class (but can be cast to an array of an element type that is an ancestor of its true element type), and does not implement any of the collection interfaces. C# has true multidimensional arrays, as well as the arrays-of-arrays that are available in Java (and which in C# are commonly called jagged arrays). Multidimensional arrays can in some cases increase performance because of increased locality (as there is a single pointer dereference, instead of one for every dimension of the array as is the case for jagged arrays). Another advantage is that the entire multidimensional array can be allocated with a single application of operator new, while jagged arrays require loops and allocations for every dimension. Note, though, that Java provides a syntactic construct for allocating a multidimensional jagged array with regular lengths (a rectangular array in the C# terminology); the loops and multiple allocations are then performed by the virtual machine and need not be explicit at the source level.
Inner classes
Both languages allow inner classes, where a class is defined entirely within another class. In Java, these classes have access to both the static and non-static members of the outer class (unless the inner class is declared static, then it only has access to the static members). Local classes can be defined within a method and have access to the method's local variables declared final, and anonymous local classes allow the creation of class instances that override some of their class methods.
C# also provides inner classes, but unlike Java, requires an explicit reference to the outer class to its non-static members. Also, C# provides anonymous delegates as a construct that can provide access to local variables and members (see Event handling). Local classes and anonymous classes are not available.
Partial classes
C# allows a class definition to be split across several source files using a feature called partial classes. Each part must be marked with the keyword partial. All the parts must be presented to the compiler as part of a single compilation. Parts can reference members from other parts. Parts can implement interfaces and one part can define a base class. The feature is useful in code generation scenarios where a code generator can supply one part and the developer another part to be compiled together. The developer can thus edit their part without the risk of a code generator overwriting that code at some later time. Unlike the class extension mechanism a partial class allows "circular" dependencies amongst its parts as they are guaranteed to be resolved at compile time. Java has no corresponding concept.
Object handling
Both C# and also Java are designed from the ground up as object oriented languages using dynamic dispatch, with a syntax similar to C++. (C++ in turn is derived from C.) Neither language is a superset of C or C++, however. Both use garbage collection as a means of reclaiming memory resources, rather than explicit deallocation of memory. Both include thread synchronization mechanisms as part of their language syntax.
References
C# allows restricted use of pointers. Pointers and pointer-arithmetic are potentially unsafe in a managed environment as they can be used to bypass the strict rules for object access. C# addresses that concern by requiring that code blocks or methods that use the feature be marked with the unsafe keyword, so that all clients of such code can be aware that the code may be less secure than otherwise. The compiler requires the /unsafe switch to allow compilation of a program that uses such code. Generally, unsafe code is either used to allow better interoperability with unmanaged APIs or system calls (which are inherently "unsafe"), or for performance reasons. Java does not allow pointers or pointer-arithmetic to be used.
Data types
Both languages support the idea of primitive types (all of which, except for String, are value types in C#/.NET). C# has more primitive types than Java, with unsigned as well as signed integer types being supported, and a decimal type for decimal floating-point calculations. Java lacks unsigned types. In particular, Java lacks a primitive type for an unsigned byte, while C# bytes are unsigned by default. Strings are treated as (immutable) objects in both languages, but support for string literals provides a specialized means of constructing them. C# also allows verbatim strings for quotation without escape sequences, which also allow newlines.
Both allow automatic boxing and unboxing to translate primitive data to and from their object form. Effectively, this makes the primitive types a subtype of the Object type. In C# this also means that primitive types can define methods, such as an override of Object's ToString() method. In Java, separate primitive wrapper classes provide such functionality. In Java primitive values are not implicitly boxed when dereferenced and an explicit cast is required for an instance call on a primitive value ((Integer)42).toString() instead of a C# instance call 42.ToString(). Another difference is that Java makes heavy use of boxed types in generics (see below), and as such allows an implicit unboxing conversion (in C# this requires a cast). As these implicit unboxing conversions can potentially throw null pointer exceptions, modern integrated development environments and compilers can be configured to highlight them.
Value types
C# allows the programmer to create user-defined value types, using the struct keyword. From the programmer's perspective, they can be seen as lightweight classes. Unlike regular classes, and like the standard primitives, such value types are allocated on the stack rather than on the heap. They can also be part of an object (either as a field or boxed), or stored in an array, without the memory indirection that normally exists for class types. Structs also come with a number of limitations. Because structs have no notion of a null value and can be used in arrays without initialization, they always come with an implicit default constructor that essentially fills the struct memory space with zeroes. The programmer can only define additional constructors with one or more arguments. This also means that structs lack a virtual method table, and because of that (and the fixed memory footprint), they cannot allow inheritance (but can implement interfaces).
Enumerations
Enumerations in C# are derived from a primitive 8, 16, 32, or 64 bit integer type. Any value of the underlying primitive type is a valid value of the enumeration type, though an explicit cast may be needed to assign it. C# also supports bitmapped enumerations where an actual value may be a combination of enumerated values bitwise or'ed together. Enumerations in Java, on the other hand, are objects. The only valid values in a Java enumeration are the ones listed in the enumeration. As objects, each enumeration can contain its own fields which can be modified. Special enumeration set and map collections provide fully type-safe functionality with minimal overhead. Java enumerations allow differing method implementations for each value in the enumeration. Both C# and Java enumerations can be converted to strings and can be used in a switch statement.
Arrays
Array and collection types are also given significance in the syntax of both languages, thanks to an iterator-based foreach statement loop. In C# an array corresponds to an object of the Array class, while in Java each array is a direct subclass of the Object class (but can be cast to an array of an element type that is an ancestor of its true element type), and does not implement any of the collection interfaces. C# has true multidimensional arrays, as well as the arrays-of-arrays that are available in Java (and which in C# are commonly called jagged arrays). Multidimensional arrays can in some cases increase performance because of increased locality (as there is a single pointer dereference, instead of one for every dimension of the array as is the case for jagged arrays). Another advantage is that the entire multidimensional array can be allocated with a single application of operator new, while jagged arrays require loops and allocations for every dimension. Note, though, that Java provides a syntactic construct for allocating a multidimensional jagged array with regular lengths (a rectangular array in the C# terminology); the loops and multiple allocations are then performed by the virtual machine and need not be explicit at the source level.
Inner classes
Both languages allow inner classes, where a class is defined entirely within another class. In Java, these classes have access to both the static and non-static members of the outer class (unless the inner class is declared static, then it only has access to the static members). Local classes can be defined within a method and have access to the method's local variables declared final, and anonymous local classes allow the creation of class instances that override some of their class methods.
C# also provides inner classes, but unlike Java, requires an explicit reference to the outer class to its non-static members. Also, C# provides anonymous delegates as a construct that can provide access to local variables and members (see Event handling). Local classes and anonymous classes are not available.
Partial classes
C# allows a class definition to be split across several source files using a feature called partial classes. Each part must be marked with the keyword partial. All the parts must be presented to the compiler as part of a single compilation. Parts can reference members from other parts. Parts can implement interfaces and one part can define a base class. The feature is useful in code generation scenarios where a code generator can supply one part and the developer another part to be compiled together. The developer can thus edit their part without the risk of a code generator overwriting that code at some later time. Unlike the class extension mechanism a partial class allows "circular" dependencies amongst its parts as they are guaranteed to be resolved at compile time. Java has no corresponding concept.
C# Interview Questions and Answers
ReplyDelete