Her kommer en kort gennemgang af visse forskelle og ligheder mellem Java og C#. Mit udgangspunkt er C#, som jeg kender fra tidligere på uddannelsen.

Jeg har Kotlin som læringsmål, men de fleste kilder jeg umiddelbart er kommet i nærheden af siger at Kotlin er en moderne version af Java. Derudover anbefaler de også at man har en grundviden på plads om Java før man giver sig i kast med Kotlin, og det er her denne tekst kommer ind i billedet.

Det er min tanke at jeg senere skal holde den viden jeg opsamler nu, op imod det jeg lærer om Kotlin.

Jeg starter med en opsamling, men i de efterfølgende afsnit kommer der lidt om mine iagttagelser. Det er ikke ment som en fyldestgørende sammenligning eller i bundgåede analyse af hverken Java eller C#.

Opsamling

Java og C# er to meget ens sprog. De fleste forskelle jeg har fundet ligger i primært i systaks, properties, konventioner for navngivning og selvfølgelig i at enslydende funktionalitet ikke er implementeret ens, såsom:

  • java: System.out.println("Hello World!");
  • C#: Console.WriteLine("Hello World!");

Hvis man ikke er bange for at kaste sig over Oracles java dokumentation , så burde det være en smal sag at få i gang med Java, hvis man allerede har C# i baggagen.

Fortolket kode

Måden både java og C# håndterer programmer på minder meget om hinanden. Begge sprog compilerer til et mellemliggende format, som efterfølgende skal fortolkes for at kunne eksekveres på en given platform.

Java bliver compileret til bytecode som ikke er maskinspecifik, men som kan køre på Java Virtual Machine(JVM). Java bytecode kan flyttes fra maskine til maskine, det kræver kun at den modtagende computer har en JVM som bytecoden kan køre i.

C# bliver compileret til Common Intermediary Language (CIL), som er et platform neutralt sprog. En CIL-fil vil så blive fortolket yderligere af den platform specifikke Common Language Runtime (CLR), som omdanner CIL til maskinlæsbar kode som kan eksekveres på den platform vi befinder os på.

Grundstruktur

Filen Main.java:

package com.example; 
// package declaration - indikerer filens placering i projektet
// svarer til et namespace i C#

public class Main{ 
  public static void main(string[] args){ // metoder starter med lowercase
    System.out.println("Hello from Java!");
  }
}

Hvis man vil trække packages ind i et projekt skal man bruge import package_name; lige under pakke-deklarationen.

I C# bruger man namespace i stedet for package, men de opfylder nogenlunde samme formål. Hvis man vil trække flere namespaces ind i et projekt bruger man using NameOfNamespace;.

Filen Program.cs:

using System;
namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello from C#!");
        }
    }
}

Identifiers

Navnene på klasser, metoder, fields (osv.) er identifiers

  • Identifiers skal starte med et bogstav eller underscore
  • Keywords kan ikke bruges som identifiers.

Disse konventioner bliver ikke overhold af kompileren, og hvis du bryder dem vil din kode stadig virke, men hvis andre udviklere skal se din kode, vil de have nemmere ved at orientere sig hvis nedenstående følges:

  • Klasser starter med stort bogstav, som vi kender det fra C#.
    • public class MyClass
  • Metoder og variabler starter med lowercase
    • void doSomething(String withThis){}
    • I C# er metoder med uppercase og variabler med lowercase
  • ved identifiers på konstanter er hele navnet UpperCase
    • public static final String FIRSTNAME = "David";
    • Side note: der findes ikke konstanter i Java, men når et field er defineret som static og final, omtaler man det som en konstant alligevel.
    • final-keyword’et betyder at værdien ikke kan ændres
    • I C# bruges PascalCase til konstanter.

Automatisk memory management

Javas garbage collection fungerer grundlæggende på samme måde som når man bruger C#. Det betyder at man som udvikler ikke eksplicit skal tildele og fratage hukommelse når man opretter eller destruerer et objekt.

Det vil sige:

  • Når man opretter en variable, et objekt eller andet, stiller java automatisk hukommelse til rådighed til formålet.
  • Når objektet ikke længere kan tilgås fra koden, vil garbage collectoren sørge for at rydde op og hukommelsen frigives igen.

Primitive Typer

Primitive typer er værdier, ikke objekter. Primitive typer står altid med lowercase. Der findes dog hjælpeklasser i Java.Lang pakken som kan bruges til at manipulere typerne på forskellige måder:

Primitiv datatype Hjælpe klasse
byte Byte
short Short
int Integer
long Long
float Float
boolean Boolean
char Character
double Double

Objekt, det vil sige ikke en primitiv type:

  • String
  • BigDecimal - bruges ved beregninger på penge / monetære værdier

Operationer

Både C# og Java føler samme operator-standard som c-sproget foreskriver - og derfor ligner C# og Java også hinanden meget på dette punkt.

Eksempelvis bruger man = til assignment af værdier.

Matematiske

I Java kan man bruge +, - , * , /, ++, -- til beregninger. Der findes desuden en klasse som kan lave mere avanceret matematik: Math.

Validerende, sammenlignende

De samme valideringsudtryk som man bruger i C# er også tilgængelige i Java: ==, !=, >, <, >=, <=.

Løkker

Løkker fungerer på samme måde i de to sprog. Du kan bruge for, foreach, while og do..while.

Den vigtigste forskel forekommer ved foreach hvor syntaksen er lidt anderledes i java:

String[] names = {"Bob", "Andrew", "Billy"}
foreach (String name : names) {
// kode udeladt
}

Arv

Igen ved arv er der store ligheder mellem C# og java, da der gælder de samme regler. Dog er der her forskel på syntaksen mellem de to sprog. Ved arv i Java bruger man extents keyword til at angive at Shirt har arvet fra ClothingItem. Contructoren i Shirt kalder superklassens constructor med super(type, size, price).

public class Shirt extents ClothingItem {
  public Shirt(String type, String size, double price){
    super(type, size, price);
  }
}

Her kommer tilsvarende i C#:

public class Shirt : ClothingItem {
  public Shirt(String type, String size, double price) : base(type, size, price){
  }
}

Override metoder fra superklassen

I C# angiver man at et metode kan overrides ved at bruge virtual keywordet i metode signaturen. I sub klassen bruger man så override i metoden signatur til at angive at man ikke vil bruge metoden fra superklassen.

Det ser sådan her ud i C#:

public class SuperClass {
  public virtual void OverrideableMethod(){ 
    Console.WriteLine("Denne metode kan erstattes i subklasserne");
  }
}

public class SubClass : SuperClass {
  public override void OverrideableMethod(){
    Console.WriteLine("Metoden er blevet erstattet her!!!");
  }
}

Hvis man skal override en metode i subklassen skal man bruge annotationen @Override over metoden. Dette er også en lille forskel fra syntakten i C#, hvor man ville bruge keyworded direkte i metodens signatur. Man bruger slet ikke keywordet virtual i java.

public class SuperClass {
  public void OverrideableMethod(){ 
    System.out.println("Denne metode kan erstattes i subklasserne");
  }
}

public class SubClass extents SuperClass {
  @override 
  public void OverrideableMethod(){
    System.out.println("Metoden er blevet erstattet her!!!");
  }
}

interfaces og abstrakte klasser

Ved arv fra en abstrakt superklasse bruger man stadig extents, men ved interfaces benytter man keywordet implements i stedet for.

Ellers fungerer det iøvrigt på samme måde som ved C#.

Iøvrigt er der en navngivningskonvention i C# om at alle interfaces starter med stort “I”, men sammen konvention findes ikke ved Java.

Properties

I java har man ikke properties som i C#. Hvor man i C# kan definere en property på denne måde: public string Name {get; set;}, skal man i java selv skrive metoderne helt ud efter denne model:

private String _name;

public void setName(String name){
  _name = name;
}

public string getName(){
  return _name;
}

Generics

Ved generics er der igen en lille syntaktisk forskel mellem sprogene.

Java-eksempel:

List<String> states = new ArrayList<>();
states.add("California");

Bemærk at List er et interface i java. ArrayList er en implementering af List-interfacet.

Bemærk også at typen String kun er angivet i den første diamant List<String>. Compileren ved allerede hvilken type du vil bruge når du instantierer klassen, derfor skal du ikke skrive typen igen: ArrayList<>()

Man kan kun bruge klasser i generics, så man kan ikke sætte en primitiv type ind. Hvis man vil arbejde med primitive typer i generics, så skal man bruge hjælpeklasserne : dvs. Integer for int og så videre.

Kilder