Equivalents were produced with the Free Edition of Java to C# Converter and the Free Edition of C# to Java Converter.
C# and Java have identical syntax for abstract methods:
Java | C# |
---|---|
public abstract class AbstractClass { public abstract void AbstractMethod(); } |
public abstract class AbstractClass { public abstract void AbstractMethod(); } |
Java | C# |
---|---|
public no access modifier (package access) private no exact equivalent protected |
public internal private protected protected internal |
There are very few direct equivalents between Java annotations and C# attributes — in some cases a Java annotation has a C# non-attribute syntax equivalent (e.g., the Java @Override annotation) and in other cases a C# attribute has a Java non-annotation syntax equivalent (e.g., the C# Serializable attribute).
Java | C# |
---|---|
@Override public void SampleOverride() { } @Deprecated public void SampleDeprecated() { } public class ImplementsSerializable implements Serializable { } |
public override void SampleOverride() { } [Obsolete] public virtual void SampleDeprecated() { } [Serializable] public class ImplementsSerializable { } |
The closest equivalent to Java anonymous inner classes in C# is to use a private class which implements the corresponding interface (but if the interface is a functional interface, then the closest equivalent is to replace the functional interface with a delegate and the anonymous inner class with a lambda).
Java | C# |
---|---|
public class TestClass { private void TestMethod() { MyInterface localVar = new MyInterface() { public void method1() { someCode(); } public void method2(int i, boolean b) { someCode(); } }; } } |
public class TestClass { private void TestMethod() { MyInterface localVar = new MyInterfaceAnonymousInnerClass(this); } private class MyInterfaceAnonymousInnerClass : MyInterface { private readonly TestClass outerInstance; public MyInterfaceAnonymousInnerClass(TestClass outerInstance) { this.outerInstance = outerInstance; } public void method1() { someCode(); } public void method2(int i, bool b) { someCode(); } } } |
Unsized Array
Java | C# |
---|---|
int[] myArray = null; | int[] myArray = null; // no change |
Sized Array
Java | C# |
---|---|
int[] myArray = new int[2]; | int[] myArray = new int[2]; // no change |
Access Array Element
Java | C# |
---|---|
x = myArray[0]; | x = myArray[0]; // no change |
Jagged Array
Java | C# |
---|---|
int[][] myArray = new int[2][]; | int[][] myArray = new int[2][]; // no change |
Rectangular Array
Java | C# |
---|---|
// small number of dimensions is easy: int[][] myArray = new int[2][3]; // the general case is more complex: int[][][] myArray = new int[2][3][4]; |
// small number of dimensions is easy: int[][] myArray = {new int[3], new int[3]}; // the general case is more complex: int[][][] myArray = RectangularArrays.RectangularIntArray(2, 3, 4); // ---------------------------------------------------------------------------------------- // Copyright © 2007 - 2024 Tangible Software Solutions Inc. // This class can be used by anyone provided that the copyright notice remains intact. // // This class includes methods to convert Java rectangular arrays (jagged arrays // with inner arrays of the same length). // ---------------------------------------------------------------------------------------- internal static class RectangularArrays { public static int[][][] RectangularIntArray(int size1, int size2, int size3) { int[][][] newArray = new int[size1][][]; for (int array1 = 0; array1 < size1; array1++) { newArray[array1] = new int[size2][]; if (size3 > -1) { for (int array2 = 0; array2 < size2; array2++) { newArray[array1][array2] = new int[size3]; } } } return newArray; } } |
C# | Java |
---|---|
// List: List<int> myList = new List<int>() {1, 2, 3}; // Dictionary: Dictionary<string, int> myD = new Dictionary<string, int>() { {string1, 80}, {string2, 85} }; |
import java.util.*; // ArrayList: (Java 9 List.of would also work here) ArrayList<Integer> myList = new ArrayList<Integer>(Arrays.asList(1, 2, 3)); // HashMap: (Map.ofEntries requires Java 9) HashMap<String, Integer> myD = new HashMap<String, Integer>(Map.ofEntries(Map.entry(string1, 80), Map.entry(string2, 85))); |
ArrayLists/Lists
Java's java.util.ArrayList collection and the .NET System.Collections.Generic.List collection are very close equivalents.
Java | C# |
---|---|
void ArrayLists() { java.util.ArrayList<Integer> myList = new java.util.ArrayList<Integer>(); myList.add(1); myList.add(1, 2); int i = 1; myList.set(0, i); i = myList.get(0); } |
using System.Collections.Generic; void ArrayLists() { List<int> myList = new List<int>(); myList.Add(1); myList.Insert(1, 2); int i = 1; myList[0] = i; i = myList[0]; } |
HashMaps/Dictionaries
Java's java.util.HashMap collection and the .NET System.Collections.Generic.Dictionary collection are very close equivalents.
Java's java.util.TreeMap collection and the .NET System.Collections.Generic.SortedDictionary collection are also very close equivalents.
Java | C# |
---|---|
void HashMaps() { java.util.HashMap<String, Integer> map = new java.util.HashMap<String, Integer>(); String s = "test"; map.put(s, 1); int i = map.get(s); i = map.size(); boolean b = map.isEmpty(); map.remove(s); } |
using System.Collections.Generic; void HashMaps() { Dictionary<string, int> map = new Dictionary<string, int>(); string s = "test"; map[s] = 1; int i = map[s]; i = map.Count; bool b = map.Count == 0; map.Remove(s); } |
Local Constant
C# | Java |
---|---|
const int myConst = 2; | final int myConst = 2; |
Class Constant
C# | Java |
---|---|
public const int myConst = 2; | public static final int myConst = 2; |
Local Variable
C# | Java |
---|---|
int myVar = 2; | int myVar = 2; |
Inferred Types
There is no inferred typing prior to Java 10, so the type is inferred by the converter:
C# | Java |
---|---|
var myVar = 2; | // prior to Java 10: int myVar = 2; // Java 10: var myVar = 2; |
Static Field
C# | Java |
---|---|
public static int S; | public static int S; |
Read-Only Field
C# | Java |
---|---|
public readonly int R = 2; | public final int R = 2; |
C# | Java |
---|---|
class Foo { public Foo() : this(0) // call to other constructor { } public Foo(int i) { } ~Foo() { } } |
class Foo { public Foo() { this(0); // call to other constructor } public Foo(int i) { } protected void finalize() throws Throwable { } } |
Java | C# |
---|---|
int boolean java.lang.String (no Java language built-in type) char float double java.lang.Object (no Java language built-in type) java.math.BigDecimal (no Java language built-in type) short long no unsigned types in Java byte (signed byte) no unsigned types in Java no unsigned types in Java no unsigned types in Java |
int bool string char float double object decimal short long byte (unsigned byte) sbyte (signed byte) ushort (unsigned short) uint (unsigned int) ulong (unsigned long) |
Simple enums in Java have simple equivalents in C#:
Java | C# |
---|---|
public enum Simple { FOO, BAR } |
public enum Simple { FOO, BAR } |
More complex enums in Java unfortunately have exceedingly complex equivalents in C#:
Java | C# |
---|---|
public enum Complex { FOO("Foo"), BAR("Bar"); private final String value; Complex(String enumValue) { this.value = enumValue; } public void InstanceMethod() { // ... } } |
using System.Collections.Generic; public sealed class Complex { public static readonly Complex FOO = new Complex("FOO", InnerEnum.FOO, "Foo"); public static readonly Complex BAR = new Complex("BAR", InnerEnum.BAR, "Bar"); private static readonly List<Complex> valueList = new List<Complex>(); static Complex() { valueList.Add(FOO); valueList.Add(BAR); } public enum InnerEnum { FOO, BAR } public readonly InnerEnum innerEnumValue; private readonly string nameValue; private readonly int ordinalValue; private static int nextOrdinal = 0; private readonly string value; internal Complex(string name, InnerEnum innerEnum, string enumValue) { this.value = enumValue; nameValue = name; ordinalValue = nextOrdinal++; innerEnumValue = innerEnum; } public void InstanceMethod() { // ... } public static Complex[] values() { return valueList.ToArray(); } public int ordinal() { return ordinalValue; } public override string ToString() { return nameValue; } public static Complex valueOf(string name) { foreach (Complex enumInstance in Complex.valueList) { if (enumInstance.nameValue == name) { return enumInstance; } } throw new System.ArgumentException(name); } } |
Java does not have any syntax which is specific to events. C# has the event keyword which allows you to declare an event to which you can easily subscribe or unsubscribe multiple listeners in addition to letting all the listeners know when the event occurs. To do this in Java, you need to replace the event's delegate type with a functional interface and replace the event declaration with a new field declaration using our generic 'Event' helper class. The 'Event' class takes care of two different listener collections and has methods for adding or removing an event subscription. Two different collections are necessary since C# allows subscribing to an event by specifying a method name or delegate instance(named listener) or subscribing by specifying a lambda.
Here's a simple example:
C# | Java |
---|---|
public class EventSource { public delegate void FooDelegate(); public event FooDelegate FooEvent; private void RaiseFooEvent() { FooEvent(); } } public class EventClient { public void SubscribeAndUnsubscribe() { EventSource t = new EventSource(); // subscribe via method name: t.FooEvent += HandleFooEvent; // unsubscribe via method name: t.FooEvent -= HandleFooEvent; // subscribe via lambda: t.FooEvent += () => { HandleFooEvent(); }; } private void HandleFooEvent() { } } |
public class EventSource { @FunctionalInterface public interface FooDelegate { void invoke(); } public Event<FooDelegate> FooEvent = new Event<FooDelegate>(); private void RaiseFooEvent() { // invoke all listeners: for (FooDelegate listener : FooEvent.listeners()) { listener.invoke(); } } } public class EventClient { public final void SubscribeAndUnsubscribe() { EventSource t = new EventSource(); // subscribe via method name: t.FooEvent.addListener("HandleFooEvent", () -> HandleFooEvent()); // unsubscribe via method name: t.FooEvent.removeListener("HandleFooEvent"); // subscribe via lambda: t.FooEvent.addListener(() -> { HandleFooEvent(); }); } private void HandleFooEvent() { } } // ---------------------------------------------------------------------------------------- // Copyright © 2007 - 2024 Tangible Software Solutions Inc. // This class can be used by anyone provided that the copyright notice remains intact. // // This class is used to convert C# events to Java. // ---------------------------------------------------------------------------------------- public final class Event<T> { private java.util.Map<String, T> namedListeners = new java.util.HashMap<String, T>(); private java.util.List<T> anonymousListeners = new java.util.ArrayList<T>(); public void addListener(String methodName, T namedEventHandlerMethod) { if (!namedListeners.containsKey(methodName)) namedListeners.put(methodName, namedEventHandlerMethod); } public void addListener(T unnamedEventHandlerMethod) { anonymousListeners.add(unnamedEventHandlerMethod); } public void removeListener(String methodName) { if (namedListeners.containsKey(methodName)) namedListeners.remove(methodName); } public java.util.List<T> listeners() { java.util.List<T> allListeners = new java.util.ArrayList<T>(); allListeners.addAll(namedListeners.values()); allListeners.addAll(anonymousListeners); return allListeners; } } |
Java doesn't have extension methods, so a C# extension method is just converted to an ordinary Java static method (calls to the method have to be adjusted to static calls using the class name).
C# | Java |
---|---|
public static class ContainsExtension { public static void ExtensionMethod(this string myParam) { // ... } } class TestClass { void TestMethod() { string s; s.ExtensionMethod(); } } |
public final class ContainsExtension { public static void ExtensionMethod(String myParam) { // ... } } public class TestClass { private void TestMethod() { String s; ContainsExtension.ExtensionMethod(s); } } |
Java | C# |
---|---|
for (String s : StringList) { ... } |
foreach (string s in StringList) { ... } |
Java's functional interfaces are closely related to C# delegates.
Java | C# |
---|---|
@FunctionalInterface public interface FooFunctional { void invoke(); } public class UseFunctionalInterface { void method() { FooFunctional funcVar = () -> voidMethod(); funcVar.invoke(); } void voidMethod() { } } |
public delegate void FooFunctional(); public class UseFunctionalInterface { internal virtual void method() { FooFunctional funcVar = () => voidMethod(); funcVar(); } internal virtual void voidMethod() { } } |
Java generics and C# generics are implemented in totally different ways — Java generics uses the concept of 'type erasure' (compiling to Object and casts), while C# generics is a run-time feature, but you can still often achieve the same result by converting one to the other.
Defining a Generic Class
Java | C# |
---|---|
public class GenericClass<T> { } |
public class GenericClass<T> { } |
Defining a Generic Class with a Constraint
Java | C# |
---|---|
public class GenericClass<T extends SomeBase> { } |
public class GenericClass<T> where T: SomeBase { } |
Defining a Generic Method
Java | C# |
---|---|
public <T> void Method(T param) { } |
public void Method<T>(T param) { } |
Defining a Generic Method with a Constraint
Java | C# |
---|---|
public <T extends SomeBase> void Method(T param) { } |
public void Method<T>(T param) where T: SomeBase { } |
Java | C# |
---|---|
import Foo.*; import static Foo.Bar.*; *no equivalent* *no equivalent* |
using Foo; using static Foo.Bar; // namespace alias: using foo = SomeNamespace; // type alias: using bar = SomeNamespace.SomeType; |
Java does not have indexers, so you must use get/set methods instead:
C# | Java |
---|---|
public int this[int index] { get { return field[index]; } set { field[index] = value; } } |
public final int get(int index) { return field[index]; } public final void set(int index, int value) { field[index] = value; } |
Basic Inheritance
C# | Java |
---|---|
class Foo : SomeBase { } |
class Foo extends SomeBase { } |
Inheritance Keywords
C# | Java |
---|---|
abstract (class) abstract (method) override (method) sealed (class) sealed (method) new (shadowing) |
abstract (class) abstract (method) @Override (method annotation) final (class) final (method) no Java equivalent |
Defining Interfaces
Java | C# |
---|---|
public interface IFoo { void Method(); } |
public interface IFoo { void Method(); } |
Implementing Interfaces
Java | C# |
---|---|
public class Foo implements IFoo { public void Method() { } } |
// implicit implementation: public class Foo : IFoo { public void Method() { } } // explicit implementation: public class Foo : IFoo { void IFoo.Method() { } } |
Expression Lambda
Java | C# |
---|---|
myVar = (String text) -> text.Length; | myVar = (string text) => text.Length; |
Multi-statement Lambda
Java | C# |
---|---|
myVar = (String text) -> { return text.Length; } |
myVar = (string text) => { return text.Length; } |
Most programming languages allow 'overloading' operators to implement specialized behavior for the operator when used on an instance of a type. Java doesn't allow this, but the same behavior is achieved through static methods:
C# | Java |
---|---|
public class SomeType { private int IntValue; public static int operator +(SomeType X, SomeType Y) { return X.IntValue + Y.IntValue; } public void OperatorTest() { SomeType o1 = new SomeType(); SomeType o2 = new SomeType(); int i = o1 + o2; } } |
public class SomeType { private int IntValue; public static int opAdd(SomeType X, SomeType Y) { return X.IntValue + Y.IntValue; } public final void OperatorTest() { SomeType o1 = new SomeType(); SomeType o2 = new SomeType(); int i = SomeType.opAdd(o1, o2); } } |
Java does not allow optional parameters. Overloaded methods are the only alternative in Java to optional parameters (these are inserted into the converted code by C# to Java Converter). A C# method with n optional parameters is converted to n + 1 overloaded methods. The overloaded methods call the overloaded method with the maximum number of parameters (which contains your original method code), passing the default values originally specified for the original optional parameters.
Here's an example of the simplest possible case:
C# | Java |
---|---|
public void TestOptional(int x = 0) { ... } |
public void TestOptional() { TestOptional(0); } public void TestOptional(int x) { ... } |
Java | C# |
---|---|
package FooPackage; // only one per file public class FooClass { } |
namespace FooPackage // can have many per file { public class FooClass { } } |
Java | C# |
---|---|
private void Method(Object... myParam) { } |
void Method(params object[] myParam) { } |
Java | C# |
---|---|
public void PatternMatching(Object obj) { // with 'instanceof' expression: if (obj instanceof String stringVar) { // use stringVar } // in switch statement: switch (obj) { case String s -> System.out.println(stringMessage); case Integer i -> System.out.println(intMessage); case Object o -> System.out.println(objectMessage); } // in switch expression: String message = switch(obj) { case String s -> stringMessage; case Integer i -> intMessage; case Object o -> objectMessage; }; } |
public virtual void PatternMatching(object obj) { // with 'is' expression: if (obj is string stringVar) { // use stringVar } // in switch statement: switch (obj) { case string s: Console.WriteLine(stringMessage); break; case int i: Console.WriteLine(intMessage); break; case object o: Console.WriteLine(objectMessage); break; } // in switch expression: string message = obj switch { string s => stringMessage, int i => intMessage, object o => objectMessage }; } |
Java does not have properties, so you must use get/set methods instead:
C# | Java |
---|---|
public int IntProperty { get { return intField; } set { intField = value; } } |
public int getIntProperty() { return intField; } public void setIntProperty(int value) { intField = value; } |
Java does not support C#-style 'ref' parameters. All Java parameters are passed by value (if it's a reference, then the reference is passed by value). However, you can wrap the parameter type in another type (we call it 'RefObject').
Here's a simple example:
C# | Java |
---|---|
public void refParamMethod(ref int i) { i = 1; } public void callRefParamMethod() { int i = 0; refParamMethod(ref i); } |
public void refParamMethod(tangible.RefObject<Integer> i) { i.argValue = 1; } public void callRefParamMethod() { int i = 0; tangible.RefObject<Integer> tempRef_i = new tangible.RefObject<Integer>(i); refParamMethod(tempRef_i); i = tempRef_i.argValue; } package tangible; // ---------------------------------------------------------------------------------------- // Copyright © 2007 - 2024 Tangible Software Solutions Inc. // This class can be used by anyone provided that the copyright notice remains intact. // // This class is used to replicate the ability to pass arguments by reference in Java. // ---------------------------------------------------------------------------------------- public final class RefObject<T> { public T argValue; public RefObject(T refArg) { argValue = refArg; } } |
Java static initializer blocks and C# static constructors serve the same purpose.
Java | C# |
---|---|
class Foo { public static int field; static { field = 1; } } |
class Foo { public static int field; static Foo() { field = 1; } } |
The '==' and '!=' string operators mean different things in Java and C#. In Java, it means identity equality, but in C# it means value equality.
Java | C# |
---|---|
String one = "one"; String two = "two"; // testing that 2 string objects are the same object // caution: Java string internment often // makes this true whenever 'equals' is true: boolean result = one == two; // null-tolerant string comparison result = Objects.equals(one, two); // non-null-tolerant string comparison (exception if 'one' is null) result = one.equals(two); |
string one = "one"; string two = "two"; // testing that 2 string objects are the same object // caution: C# string internment often // makes this true whenever '==' is true: bool result = string.ReferenceEquals(one, two); // null-tolerant string comparison result = one == two; // or: result = string.Equals(one, two) // non-null-tolerant string comparison (exception if 'one' is null) result = one.Equals(two); |
Java and C# 'switch' are mostly equivalent, except:
1. Java 'switch' allows fall-through from a non-empty 'case' to the next 'case' or 'default'. In C#, a jump statement
(break, return, throw, or goto) must be reached on every path through the 'case' logic, so a 'goto' statement is required
to produce a fall-through from a non-empty 'case'.
2. Java also has a newer alternative shorter syntax not available in C#.
Java | C# |
---|---|
// fall-through from a non-empty 'case': switch (someCondition) { case 1: code; case 2: code; default: code; } // short-form switch: switch (day) { case MONDAY, FRIDAY, SUNDAY -> System.out.println(6); case TUESDAY -> System.out.println(7); } |
// fall-through from a non-empty 'case': switch (someCondition) { case 1: code; goto case 2; case 2: code; goto default; default: code; break; } switch (day) { case MONDAY: case FRIDAY: case SUNDAY: Console.WriteLine(6); break; case TUESDAY: Console.WriteLine(7); break; } |
Java | C# |
---|---|
public void method() { Fruit fruit = Fruit.APPLE; int numberOfLetters = switch (fruit) { case PEAR -> 4; case APPLE, MANGO -> 5; case PAPAYA -> 6; default -> 0; }; } public enum Fruit { APPLE, MANGO, PAPAYA, PEAR } |
public virtual void method() { Fruit fruit = Fruit.APPLE; int numberOfLetters = fruit switch { Fruit.PEAR => 4, Fruit.APPLE or Fruit.MANGO => 5, Fruit.PAPAYA => 6, _ => 0 }; } public enum Fruit { APPLE, MANGO, PAPAYA, PEAR } |
Java | C# |
---|---|
synchronized (x) { ... } |
lock (x) { ... } |
Java | C# |
---|---|
boolean b = f instanceof Foo; Class t = w.class; |
bool b = f is Foo; Type t = typeof(w); |
The C# 'using' statement (not the C# 'using' directive) is a shortcut for a try/finally block which disposes an object of type System.IDisposable. Java 7 introduces the 'try with resources' statement, which operates on objects of type java.io.Closeable:
C# | Java |
---|---|
using (Foo f = new Foo()) { } |
// Java 7 or higher: try (Foo f = new Foo()) { } // Before Java 7: Foo f = new Foo(); try { } finally { f.close(); } |
Java 15 has 'text blocks', but check the documentation — the rules about indentation are very convoluted. Prior to Java 15, the closest you can get is a string concatenation which spans multiple lines. C# confusingly now has 2 types of verbatim strings — the traditional 'verbatim string' and the C#11 'raw string literal', which is nearly identical to the Java 15 text block.
C# | Java |
---|---|
// verbatim string: string s = @"multiline verbatim string"; // C#11 raw string literal: string s = """ multiline verbatim string """; |
// Java 15 text blocks: String s = """ multiline verbatim string"""; // before Java 15: String s = "multiline" + "\r\n" + " verbatim" + "\r\n" + " string"; |
Copyright © 2004 – 2024 Tangible Software Solutions Inc.