C# og Java er to programmeringssprog, der udvikler programmeringssproget C++ , med en syntaks, der i vid udstrækning arver C++- syntaksen , og som er skabt i mange henseender i et konkurrencepræget miljø, og som følge heraf har visse ligheder , samt en række forskelle .
C#- og Java-sprogene dukkede op på forskellige tidspunkter. Java-sproget blev skabt længe før fremkomsten af C#. Oak Java blev udviklet af Sun Microsystems i 1990, og i 1995 udkom den første betaversion af Java. Oprettelsen af C# blev annonceret i 2000, og i 2002 blev den første version af .NET platformen frigivet til at understøtte C#. Således, hvis Java blev skabt ved at stole mere på oplevelsen af Objective C- og C-sprogene, så var C#, C++ og Java selv en sådan støtte [1] . Og på trods af navnet viste C# sig at være tættere på Java end på C++ [2] [3] .
Fra en udviklers synspunkt er Java og C# meget ens. Begge sprog er stærkt maskinskrevne, objektsprog. Begge har inkorporeret meget af C++-syntaksen, men i modsætning til C++ er de nemmere at lære for begyndere. Begge lånte fra C et sæt grundlæggende nøgleord og servicesymboler, inklusive krøllede seler til at fremhæve blokke. Begge sprog er afhængige af affaldsindsamling . Begge sprog er ledsaget af rige samlinger af biblioteker. Men sprog har også deres egne karakteristika og forskelle, styrker og svagheder. C# tog højde for mange af Javas mangler og korrigerede dem i dens implementering [4] . Men Java står ikke stille og udvikler sig parallelt med C#.
Kik Redek fra Microsoft anser C# for at være et mere komplekst sprog end Java [1] . Efter hans mening, " Java blev bygget for at forhindre en udvikler i at skyde sig selv i foden" , og "C# blev bygget til at give udvikleren en pistol, men lad sikkerheden være tændt" ( engelsk "C# blev bygget til at give udvikleren en pistol, men lad sikringen være tændt" ).
Syntaktiske forskelle er også tilstrækkelige.
Syntaks | Java | C# |
---|---|---|
Importer statiske navne ( import static) |
giver dig mulighed for separat at importere nogle eller alle de statiske metoder og variabler i en klasse og bruge deres navne uden kvalifikationer i importmodulet | Siden C# 6.0 er dette blevet introduceret (f.eks. ( using static System.Math)). |
skifte erklæring | Switch-sætningsargumentet skal enten være et heltal eller en opregnet type. Fra og med Java 7 blev det muligt at bruge strengliteraler i en switch-sætning, og denne skelnen fra C# er blevet elimineret [2] . | Både konstanttyper og strengtyper understøttes. C# 7 introducerede understøttelse af referencetyper og null. Det er også muligt at angive yderligere betingelser for en blok ved hjælp af casenøgleordet when[5] . I modsætning til Java er der ingen direkte overgang til næste blok case. For at gå til næste blok caseskal du bruge goto [2] sætningen . |
goto jump statement | brugen af goto blev bevidst opgivet, men der er en mekanisme, der giver dig mulighed for at forlade den ydre løkke fra den indlejrede ved at markere den med etiketten og bruge operatorerne breaksammen continuemed etiketten ( continue <метка>;) | goto er bevaret, dets sædvanlige brug er at overføre kontrol til forskellige etiketter casei sætningen switchog afslutte den indlejrede sløjfe |
Konstanter | der er ingen konstanter som sådan, statiske klassevariable med en modifikator bruges i stedet final - effekten af deres brug er nøjagtig den samme | separat koncept for navngivet indtastet konstant og nøgleordconst |
Flydende komma præcision | Java indeholder strictfp- konstruktionen , som garanterer de samme resultater for floating point-operationer på alle platforme. | C# er afhængig af implementeringen, der er ingen garanti for nøjagtig de samme resultater af beregninger. |
Deaktivering af checks | I Java er alle dynamiske kontroller kun aktiveret/deaktiveret på pakkeniveau | C# indeholder og-konstruktionerne checkedtil at uncheckedaktivere eller deaktivere dynamisk aritmetisk overløbskontrol lokalt . |
Begge sprog implementerer den samme model til at arbejde med dynamiske data: objekter skabes dynamisk ved hjælp af konstruktionen new, runtime overvåger for referencer til dem, og skraldeopsamleren rydder periodisk op i hukommelsen fra objekter, der ikke er refereret til. For at optimere affaldsindsamlingen indeholder specifikationerne for sprog og runtime-miljøer ikke begrænsninger på levetiden af et objekt efter den sidste reference til det er blevet slettet - samleren arbejder uafhængigt af programmets udførelse, så den faktiske ødelæggelse af objektet kan opstå når som helst efter den sidste reference er slettet, før programmet afsluttes. I virkeligheden optimerer skraldeopsamlere udførelsen på en sådan måde, at de giver et acceptabelt hukommelsesforbrug med minimal opbremsning i programmer.
Både Java og C# har stærke og svage objektreferencer . Begge sprog understøtter færdiggørelsesmetoder . På grund af usikkerheden om, hvornår et objekt slettes, kan færdiggørelsesprogrammer ikke bruges til at frigive de systemressourcer, der er optaget af objektet, hvilket tvinger dig til at oprette yderligere metoder til at "rydde op" i objektet og kalde dem eksplicit.
C# har en grænseflade i standardbiblioteket IDisposableog en speciel konstruktion usingfor at sikre, at oprydningsmetoden kaldes i tide:
// DisposableClass implementerer IDisposable-grænsefladen og beskriver dens metode Dispose class DisposableClass : IDisposable { public void Dispose () { // ... Ressourcer optaget af instansen frigives her } } ved at bruge ( DisposableClass obj = new DisposableClass (...)) { // ... Kode, der bruger obj-objektet } // ... Her er Dispose-metoden garanteret allerede kaldt på obj-objektetDer er ingen sådan konstruktion i Java, og objektoprydning kan kun udføres manuelt:
klasse AnyClass { void clear () { // ... Clear code goes here } } AnyClass obj = ny AnyClass ( ...); prøv { // ... kode ved hjælp af obj } endelig { obj . klar (); // - et eksplicit kald til objektets oprydningsmetode efter dets brug er fuldført }Java 7 tilføjede en "try-with-resources"-konstruktion for at give automatisk oprydning på nøjagtig samme måde som C#:
prøv ( BufferedReader br = ny BufferedReader ( ny FileReader ( sti ))) { return br . readLine (); }Når try-blokken afsluttes, vil alle objekter, der er blevet tildelt en værdi i dens header (parenteserne før sætningsblokken), blive ryddet. En forudsætning er, at klasserne af disse objekter skal implementere java.lang.AutoCloseable-systemgrænsefladen.
Java giver dig mulighed for at registrere en lytter, der vil modtage beskeder, når en reference er opsamlet skrald, hvilket forbedrer WeakHashMaps ydeevne .
C# (mere specifikt, common language runtime) giver dig mulighed for at annullere udførelsen af en finalizer for et givet objekt ved hjælp af en metode GC.SuppressFinalize(obj)(f.eks. en SQL -forbindelse på en filstrøm). Dette er nyttigt, fordi færdiggørelse betragtes som en relativt dyr affaldsindsamlingsoperation, og et objekt med en færdiggører "lever" længere.
Begge sprog er objektorienterede , med en syntaks, der er arvet fra C++, men væsentligt redesignet. Kode og data kan kun beskrives inden for klasser.
IndkapslingI Java tillader den beskyttede modifikator i erklæringen, udover adgang fra efterkommerklasser, adgang fra alle klasser i samme pakke som ejerklassen.
I C#, for objekter, der skulle være synlige i samlingen (en omtrentlig analog til Java-pakken), er en separat intern modifikator blevet introduceret (en analog af standard i Java), og beskyttet bevarer sin oprindelige betydning, taget fra C ++ - kun adgang fra efterkommerklasser. Det er tilladt at kombinere internt og beskyttet - så får du det adgangsområde svarende til beskyttet i Java.
Indre klasserBegge sprog giver dig mulighed for at definere en klasse inden for en klasse.
I Java bruges indre klasser til at efterligne lukninger. Java indre klasser har adgang til de ikke-statiske medlemmer af den overordnede klasse, dvs. "kend til dette"; derudover kan du inden for metoder definere lokale klasser, der har læseadgang til lokale variabler og unavngivne (anonyme) lokale klasser, som faktisk giver dig mulighed for at oprette forekomster af objekter og grænseflader, der tilsidesætter din klasses metoder, direkte på stedet af deres brug. Hændelseshåndtering kan bygges på denne mekanisme i Java-programmer (en hændelse genererer et kald til en metode, der er abstrakt i den oprindelige handlerklasse; hvor der er behov for en specifik hændelseshandler, opretter programmøren en instans af en lokal anonym klasse - efterfølgeren af basishandlerklassen og bruger den direkte). Dette eliminerer behovet for en speciel type og syntaktisk støtte til begivenheder, men den faktiske kode, der skaber handlerne, er noget mere kompleks at forstå. Især variable omfang bliver mere komplekse .
C# har lukninger og lambdaer. C#-tilgangen minder mere om C++: indre klasser i C# har kun adgang til statiske medlemmer af den ydre klasse, og for at få adgang til ikke-statiske medlemmer skal du udtrykkeligt angive en instans af den ydre klasse. Lokale indre klasser understøttes ikke i C#.
Lambda-udtryk er også dukket op i Java siden version 8 .
MetoderPå begge sprog defineres metoder gennem klassefunktioner. Metodens krop er placeret inde i klassedeklarationen. Statiske metoder, abstrakte metoder er understøttet . C# har også en eksplicit implementering af interface-metoder, som giver en klasse mulighed for at implementere interface-metoder adskilt fra sine egne metoder, eller at give forskellige implementeringer af metoder af samme navn, der hører til to forskellige interfaces.
Java 8 introducerede standardsætningen, som giver dig mulighed for at definere "standard" implementeringen af grænseflademetoder. Dermed slipper klassen, der implementerer grænsefladen, forpligtelsen til at implementere standardmetoder, men kan tilsidesætte dem.
En lignende funktion dukkede op i C # 9.0 - inden for rammerne af grænsefladebeskrivelsen kan udvikleren specificere organer for alle metoder. Ligesom i Java, når udvikleren implementerer en grænseflade, kan udvikleren tilsidesætte standardimplementeringen, men er ikke forpligtet til at gøre det.
I Java sendes primitive typer ( byte, int, double, float, booleanosv.) af værdi, og for de øvrige (objekt-) typer sendes en objektreference med værdi.
I C# videregives primitive typer af strukturværdi ( struct) (såkaldte værdityper), andre typer videregives ved reference (såkaldte referencetyper). C# understøtter også den eksplicitte beskrivelse af parameteroverførsel ved reference (og refnøgleord ) . Når du bruger out, kontrollerer compileren, om værdien er til stede i tildelingsmetoden. Det understøttes også at returnere værdier fra metoder ved hjælp af ref typenavn-konstruktionen. inout
C# tillader, at metoder får samme navn som klassenavnet, og derved skabes en klassekonstruktør [6] (I Java kan en programmør også definere en konstruktør, der faktisk vil være en metode) [4] .
C# understøtter flere specielle syntaksundertyper, når metodelegemer beskrives:
- iteratorblokke: metoder, der returnerer IEnumerable<T>eller IEnumerator<T>absolut kan beskrive sekvensen af returnerede værdier ved hjælp af yield returnog -konstruktionerne yield break.
- asynkrone metoder: metoder, der returnerer Task/ ValueTask/ Task<T>/ ValueTask<T>og er markeret med nøgleordet async, kan bruge await-konstruktionen i deres kroppe, når de kalder andre metoder, der returnerer Task/ ValueTask/ Task<T>/ ValueTask<T>. Dette giver dig mulighed for at implementere cooperativ multitasking, fordi. await-konstruktionen afbryder udførelsen af den aktuelle metode, indtil den anmodede værdi er klar, og overfører kontrol til planlæggeren, som kan begynde at udføre den næste klar-opgave uden at overføre kontrol til OS-kernen.
Startende med C# 8.0 kan du kombinere begge funktioner ved at skabe asynkrone iteratorer - en implementering af IAsyncEnumerable<T>/ -grænsefladen IAsyncEnumerator<T>ved hjælp af await, yield returnog -konstruktionerne yield break.
Virtualitet af metoderC# kopierer konceptet C++ virtuelle metoder : en virtuel metode skal udtrykkeligt erklæres med nøgleordet virtual, andre metoder er ikke virtuelle. Denne selektive deklaration af virtuelle metoder blev introduceret i C#, da deklarering af alle metoder virtuelle i høj grad kan bremse udførelsen [7] . Derudover kræver C# en eksplicit erklæring om en virtuel metodetilsidesættelse i en afledt klasse med nøgleordet override. Hvis du vil skjule (skjule) en virtuel metode, det vil sige blot indføre en ny metode med samme navn og signatur, skal du angive et nøgleord new(i mangel af hvilket compileren udsender en advarsel). Det er forbudt at skjule (dunkle) abstrakte metoder. Erklæring af en tilsidesættelsesmetode med nøgleordet sealedforhindrer tilsidesættelsesmetoden i at blive tilsidesat i efterkommerklasser, men giver dig stadig mulighed for at skjule den.
I Java derimod er alle offentlige metoder, undtagen statiske, virtuelle, og det er umuligt at tilsidesætte en metode, så virtualitetsmekanismen ikke tænder. Metoden tilsidesætter næsten altid basisklassemetoden med samme navn og signatur, hvis nogen. Nøgleordet finalgiver dig mulighed for at forhindre oprettelsen af en metode med samme signatur i afledte klasser.
Java-tilgangen er syntaktisk enklere og sikrer, at metoden for den klasse, objektet tilhører, altid påberåbes. På den anden side er virtualitet ikke altid nødvendig, og overheaden ved at kalde virtuelle metoder er noget højere, da disse opkald normalt ikke går gennem inline substitution og kræver yderligere adgang til den virtuelle metodetabel (selvom nogle implementeringer af JVM, bl.a. Sun-implementeringen, implementer inline substitution af de oftest kaldet virtuelle metoder).
Virtualiteten af alle metoder er potentielt usikker: hvis en programmør fejlagtigt erklærer en metode, der allerede er i basisklassen, ikke har til hensigt at tilsidesætte den, men simpelthen ikke er opmærksom på, at en sådan metode allerede eksisterer, så er den nye metode vil tilsidesætte metoden af samme navn i basisklassen, selvom dette ikke er udviklerens hensigt. I C# er en lignende fejl også mulig, men compileren vil udsende en advarsel om, at den tilsidesættende metode er erklæret uden newog override. Java 5 introducerede en lignende mekanisme - hvis en metode tilsidesætter en virtuel metode fra en forfaderklasse, udsender compileren en advarsel; For at forhindre, at der udsendes en advarsel, skal den tilsidesættende metode være annoteret med "@Override"-annotationen.
Begge sprog understøtter ideen om primitive typer (som i C# er en delmængde af værdityper - værdityper ), og både til oversættelse af primitive typer til objekttyper giver deres automatiske "boksning" til objekter (boksning) og "unboxing" (unboxing) (i Java - fra version 5). I C# kan primitive typer omtales som objekter, og det er en af grundene til, at C# er populært. I Java er primitive typer og objekttyper adskilt, wrapper-klasser bruges til at referere til primitive typer som objekter (f.eks. Integer-indpakningen for int-typen), dette forårsager utilfredshed hos mange Java-udviklere [8] [9] .
Der er flere primitive typer i C# end i Java, på grund af usignerede heltalstyper (usigned), som er parret med alle signerede, og en speciel type decimaltil højpræcision fastpunktsberegninger (i Java tjener klasserne java.math.BigIntegerog til dette java.math.BigDecimal).
Java har forladt de fleste usignerede typer for at forenkle sproget. Et af de velkendte problemer med sådanne typer er vanskeligheden ved at bestemme typen af resultatet af aritmetiske operationer på to argumenter, hvoraf det ene er fortegn og det andet uden fortegn. Uanset hvilke regler sproget anvender for sådanne operationer, vil det i nogle situationer føre til fejl (f.eks. i C ++ giver en operation på en værdi uden fortegn et resultat uden fortegn; som et resultat, når man tæller med 16- bittal, vil udtrykket "40000 / (-4 )" som et resultat ikke give -10000, men 55536). Denne afvisning skaber imidlertid sine egne problemer; da en væsentlig del af de tekniske data, der bruges på et lavt niveau (f.eks. forskellige servicedata, der transmitteres af hardwaren og returneres af operativsystemets API-funktioner) er af typen usigneret heltal, og fraværet af sådanne typer fører til behovet at udføre usikre datakonverteringsoperationer, og i nogle tilfælde - erstatte brugen af simpel usigneret aritmetik med ikke-oplagte kombinationer af bitvise operationer.
Strukturer (optegnelser)C# giver dig mulighed for at oprette brugerdefinerede værdityper ved hjælp af struct. Dette er en direkte arv fra C++ sproget, som skaberne af Java bevidst opgav. I modsætning til klasseforekomster oprettes værditypeforekomster ikke på heapen , men på opkaldsstakken eller som en del af forekomsten af objektet, hvori de er erklæret, hvilket i nogle tilfælde forbedrer kodeydeevnen. Fra en programmørs synspunkt ligner de klasser, men med flere begrænsninger: de kan ikke have en eksplicit parameterløs konstruktør (men de kan have en konstruktør med parametre), de kan ikke nedarves fra [10] , og de kan ikke nedarve eksplicit fra andre typer (altid implicit) . er nedarvet fra klasse System.ValueType), men kan implementere grænseflader. Derudover understøtter værdierne af struct-typer logikken i at tildele en værdi (det vil sige, at tildele værdien af en variabel til en anden kopierer ikke referencen til det samme objekt, men kopierer feltværdierne for en struktur til en anden). Siden version 1.6 har Java også mulighed for at oprette objekter på stakken, men det sker automatisk uden brugerindblanding.
I Java, for at forhindre en klasse i at blive nedarvet, kan den erklæres endelig final, hvorved der opnås en delvis analog af konstruktionen struct(kopiering efter værdi vil alligevel ikke blive understøttet). sealedC# bruger modifikatoren [11] til samme formål .
Opregnede typerOpregnede typer i C# er afledt af primitive integraltyper. En gyldig værdi af en opregnet type er enhver værdi af dens underliggende primitiv, selvom dens tildeling kan kræve en eksplicit cast . Dette tillader opregnede typeværdier at blive kombineret med en bitvis "eller"-operation, hvis de er bitflag.
I Java er opregnede typer klasser, og deres værdier er henholdsvis objekter. En opregningstype kan have metoder, implementere grænseflader. De eneste gyldige typeværdier er dem, der er angivet i erklæringen. At kombinere dem som flag kræver et særligt enum sæt objekt. Det er muligt at definere forskellige metodeimplementeringer for hver værdi.
Arrays og samlingerArrays og samlinger fik også udtryk i syntaksen for begge sprog, takket være en speciel slags loop for (loop over en samling, også kendt som en for loop foreach). På begge sprog er et array et objekt af klasse Array, men i Java implementerer det ingen samlingsgrænseflader, selvom det er muligt at iterere over arrays med en for(:)-løkke. Begge sprog har generiske samlingsklasser i standardbiblioteket .
I Java kan der strengt taget kun deklareres endimensionelle arrays. Et multidimensionelt array i Java er et array af arrays. C# har både ægte multidimensionelle arrays og arrays af arrays, som almindeligvis i C# omtales som "jagged" eller "jagged" arrays. Multidimensionelle arrays er altid "rektangulære" (i 2D-termer), mens arrays af arrays kan gemme strenge af forskellig længde (igen i 2D, på samme måde i multidimensional). Multidimensionelle arrays fremskynder hukommelsesadgang (for dem bliver markøren kun derefereret én gang), mens takkede arrays er langsommere, men sparer hukommelse, når ikke alle rækker er fyldte. Multidimensionelle arrays kræver kun ét opkald fra operatøren for at oprette dem new, mens takkede arrays kræver eksplicit allokering af hukommelse i en loop for hver række.
Parametriserede (generiske) typerPå begge sprog kan typer parametreres, hvilket understøtter det generiske programmeringsparadigme . Syntaktisk er definitionen af typer ret tæt - på begge sprog er den nedarvet fra C++-skabeloner, dog med nogle modifikationer.
Generics i Java er udelukkende en sprogkonstruktion og implementeres kun i compileren. Compileren erstatter alle generiske typer med deres øvre grænser og indsætter den passende cast, hvor den parameteriserede type bruges. Resultatet er en bytekode, der ikke indeholder referencer til generiske typer og deres parametre. Denne teknik til implementering af generiske typer kaldes type sletning . Dette betyder, at oplysninger om de originale generiske typer ikke er tilgængelige under kørsel, og pålægger nogle begrænsninger, såsom manglende evne til at oprette nye array-forekomster fra generiske typeargumenter. Java runtime-miljøet er ukendt med det generiske system, hvilket resulterer i nye JVM-implementeringer, der kun kræver minimale opdateringer for at fungere med det nye klasseformat.
C# gik den anden vej. Genericitetsunderstøttelse er blevet integreret i selve den virtuelle runtime, først introduceret i .NET 2.0. Sproget her er kun blevet en ekstern grænseflade til at få adgang til disse funktioner i miljøet. Som i Java udfører compileren statisk typekontrol, men udover dette udfører JIT load -time validering . Generisk type information er fuldt ud til stede under kørsel og giver fuld understøttelse af generisk type refleksion og oprettelse af nye implementeringer.
Java-tilgangen kræver yderligere runtime-tjek, garanterer ikke, at kodeklienten følger typematching, og giver ikke refleksion for generiske typer. Java tillader ikke, at generics specialiseres til primitiver (dette kan kun gøres ved at pakke primitive typer ind i klasser), mens C# giver generics for både referencetyper og værdityper, inklusive primitiver. I stedet foreslår Java at bruge indpakkede primitive typer som parametre (f.eks. List<Integer>i stedet List<int>for ), men dette kommer på bekostning af yderligere heap-allokering. I både Java og C# producerer generiske typespecialiseringer på forskellige referencetyper den samme kode [12] , men for C# genererer runtime dynamisk optimeret kode, når der er specialiseret sig i værdityper (f.eks. List<int>), hvilket gør det muligt at lagre og hente dem fra containere uden operationer for- og indsættelse.
Java kræver, at programmøren manuelt implementerer observatørmønsteret , selvom det giver noget syntaktisk sukker i form af anonyme indlejrede klasser , som giver dig mulighed for at definere en klassekropp og straks instansiere den på et tidspunkt i koden.
C# giver omfattende support til hændelsesbaseret programmering på sprogniveau, herunder .NET- delegerede , multicasting, speciel syntaks til indstilling af hændelser i klasser, operationer til registrering og afregistrering af hændelseshandlere, delegeret kovarians og anonyme metoder med et komplet sæt af lukkesemantik .
Lukninger er inkluderet i Java SE 8 [1] . Disse lukninger har ligesom delegerede i C# fuld adgang til alle lokale variabler i et givet omfang, ikke kun læseadgang til variabler markeret med et ord final(som med anonyme indlejrede klasser).
C# inkluderer operatøroverbelastning og brugerspecificeret type casting , som er velkendte for C++ programmører. C# understøtter det med nogle begrænsninger, der sikrer logisk integritet, hvilket, når det bruges omhyggeligt, er med til at gøre koden mere kortfattet og læsbar. Java inkluderer ikke operatøroverbelastning for at undgå misbrug og for at holde sproget simpelt [13] [14] [15] .
C# understøtter konceptet "egenskaber" - pseudofelter i en klasse, hvortil der gives adgang med fuld kontrol ved at skabe metoder til at hente og indstille feltets værdi. Ejendomsbeskrivelser er lavet vha. konstruktionerne getog set. Der er ikke et sådant koncept i Java [16] (selvom der ikke er nogen begrænsninger for at implementere det ved hjælp af traditionelle metoder).
C# inkluderer også såkaldte indeksere , som kan opfattes som et særligt tilfælde af operatøroverbelastning (svarende til overbelastning operator[]i C++), eller parameteriserede egenskaber. En indekser er en egenskab ved navn this[], som kan have en eller flere parametre (indekser), og indekserne kan være af enhver type. Dette giver dig mulighed for at oprette klasser, hvis instanser opfører sig som arrays/kort:
min liste [ 4 ] = 5 ; strengnavn = xmlNode . _ Attributter [ "navn" ]; ordrer = kundeKort [ Kunden ];Brugen af egenskaber er ildeset af nogle autoritative programmører. Især skriver Jeffrey Richter :
“Personligt kan jeg ikke lide egenskaber, og jeg ville være glad, hvis deres support blev fjernet fra Microsoft .NET Framework og relaterede programmeringssprog. Årsagen er, at egenskaber ligner felter, men faktisk er metoder." [17]
I henhold til den almindelige C#-navngivningsstil er egenskabsnavne visuelt forskellige fra felter ved, at de begynder med et stort bogstav.
C#, i modsætning til Java, understøtter betinget kompilering ved hjælp af preprocessor- direktiver . Den har også en egenskab Conditional, der betyder, at den angivne metode kun kaldes, når den givne kompileringskonstant er defineret. På denne måde kan du indsætte i koden for eksempel assertion checks, som kun vil virke i debug-versionen, når konstanten er defineret DEBUG. I .NET-standardbiblioteket er dette Debug.Assert().
Java-versioner 1.4 og nyere inkluderer en runtime-antagelseskontrol på sproget. Desuden kan hvis konstruktioner med konstante betingelser udvides på kompileringstidspunktet. Der er tredjepartsimplementeringer af præprocessorer til Java, de bruges primært til udvikling af applikationer til mobile enheder.
Eksterne moduler i Java og C# er forbundet på lignende måde. Java bruger nøgleordet import, C# bruger nøgleordet bruger. Eksempel [18] :
// Java eksempel import java.lang.System ; public class GlobalGreeting2 { public static void main ( String [ ] args ) { System . ud . println ( "Zdravo, zemjata!" ); } } | // C# eksempel ved hjælp af System ; public class GlobalGreeting2 { public static void Main ( string [ ] args ) { Console . WriteLine ( "Salut, monde!" ); } } |
Den væsentlige forskel mellem import i Java og brug i C# er, at C# bruger begrebet navnerum (namespace), der minder om C++ mekanismen af samme navn [18] . Java bruger konceptet pakker . Navneområder har intet at gøre med kompilerede moduler (assemblies eller assembly i Microsoft-terminologi). Flere samlinger kan indeholde det samme navneområde, og én samling kan erklære flere navneområder, ikke nødvendigvis indlejrede. C#-omfangsmodifikatorer har intet at gøre med navnerum. I Java danner klasser erklæret i den samme pakke som standard en enkelt kompileret enhed. Standardomfangsmodifikatoren (ingen eksplicit specifikation) begrænser omfanget af klassefelter og -metoder til pakken.
I Java er strukturen af en pakkes kildefiler og mapper som standard relateret til pakkestrukturen - en pakke svarer til en mappe, dens underpakker - undermapper til denne mappe, kildefiler er placeret i mapper svarende til pakken eller underpakken hvori de indgår. Kildetræet følger således pakkens struktur. I C# har placeringen af en kildefil intet at gøre med dens navneområde.
Ingen af mulighederne har en væsentlig magtoverlegenhed, blot forskellige mekanismer bruges til at løse tvetydigheder [18] .
I C# kan klasser placeres i filer vilkårligt. Navnet på kildekodefilen har intet at gøre med navnene på de klasser, der er defineret i den. Det er tilladt at placere flere offentlige klasser i én fil. Fra version 2.0 giver C# dig også mulighed for at opdele en klasse i to eller flere filer (søgeord partial). Den sidste funktion er lavet for at adskille den kode, der er skrevet af en person, og den kode, der genereres. Det bruges for eksempel af værktøjer til opbygning af visuelle grænseflader: den del af klassen, der indeholder felterne og metoderne, der styres af grænsefladekonstruktøren, er adskilt i en separat fil.
I Java kan hver fil kun indeholde én offentlig klasse, og Java kræver, at filnavnet er det samme som det pågældende klassenavn, hvilket eliminerer fil- og klassenavneforvirring. Desuden bør størrelsen af en kildekodefil ifølge Suns anbefalede kodeformateringskonvention ikke overstige 2000 linjer kode , fordi en større fil er sværere at parse. En stor filstørrelse betragtes også som et tegn på dårligt design.
Begge sprog understøtter en undtagelseshåndteringsmekanisme, der er syntaktisk designet på nøjagtig samme måde: Sproget har en exception throw-operator throwog en undtagelseshåndteringsblok, try{}catch(){}finally{}der sørger for aflytning af undtagelser, der er opstået inde i blokken, deres behandling, samt som den garanterede udførelse af endelige handlinger.
Java understøtter kontrollerede (markerede) undtagelser : programmøren skal udtrykkeligt for hver metode specificere de typer undtagelser, som metoden kan give, disse typer er anført i metodeerklæringen efter nøgleordet throws. Hvis en metode bruger metoder, der kaster kontrollerede undtagelser, skal den enten eksplicit fange alle disse undtagelser eller inkludere dem i sin egen erklæring. Således indeholder koden eksplicit en liste over undtagelser, der kan kastes af hver metode. Undtagelsestypehierarkiet indeholder også to typer ( RuntimeExceptionog Error), hvis efterkommere ikke er markeret og ikke bør erklæres. De er forbeholdt runtime-undtagelser, der kan forekomme hvor som helst, eller som normalt ikke kan håndteres af programmøren (såsom runtime-fejl), og bør ikke erklæres i en throws.
C# understøtter ikke kontrollerede undtagelser. Deres fravær er et bevidst valg af udviklere. Anders Hejlsberg , chefarkitekt for C#, mener, at de i Java til en vis grad var et eksperiment og ikke retfærdiggjorde sig selv [2] .
Nytten af kontrollerede undtagelser kan diskuteres. Se artiklen Exception Handling for detaljer .
Generelt ligner de parallelle programmeringsmekanismer i C# dem, der leveres af Java, forskellen ligger i implementeringsdetaljerne. I begge tilfælde er der en trådbiblioteksklasse, der implementerer konceptet med en "tråd". Java giver to måder at oprette native tråde på, enten ved at udvide Thread-klassen eller ved at implementere Runnable-grænsefladen. I begge tilfælde skal programmøren definere en nedarvet (inkluderet i grænsefladen) run()-metode, der indeholder trådens brødtekst - den kode, der vil blive eksekveret i den. C# bruger i stedet delegat-mekanismen: for at oprette en tråd oprettes en instans af standard-Thread-klassen, hvortil en delegat sendes som en konstruktørparameter, der indeholder en metode - trådens krop.
Begge sprog har evnen til at oprette en synkront eksekverbar kodeblok; i Java gøres dette med synchronized() operatoren, i C# med lock() operatoren. Det er også muligt i Java at erklære synkrone metoder ved at bruge den synkroniserede modifikator i overskriften på en metodeerklæring. Sådanne metoder blokerer deres værtsobjekt, når de udføres (altså af de synkroniserede klassemetoder, for det samme tilfælde, kan kun én udføres på samme tid og kun i én tråd, resten vil vente). En lignende funktion i .NET er implementeret ved hjælp af MethodImplAttribute-metodeimplementeringsattributten MethodImplOptions.Synchronized, men i modsætning til Java er denne funktion ikke formelt en del af C#-sproget.
C# har en operatør lock(){} [3] , der anskaffer en lås, før den går ind i en blok og frigiver den både ved udgang og ved at kaste en undtagelse. Java-modstykket er synkroniseret() {}.
C# 4.5 introducerede async and await [4] operatørerne samt en ny opgaveklasse, der er mere effektiv end Thread til korte, samtidige opgaver. Effektiv parallel behandling af opregnede typer (Enumerable containere) er implementeret på samme mekanisme. [5]
På begge sprog er identiske metoder til synkronisering også tilgængelige, baseret på at sende og vente på et signal fra en tråd til en anden (andre). I Java er disse notify(), notifyAll() og wait() metoderne, i C# - Pulse(), PulseAll(), Wait() metoderne (de tre metoder er funktionelt ens parvis). Den eneste forskel er, at i Java er disse metoder (og følgelig monitorfunktionaliteten) implementeret i Object-klassen, så der kræves ingen yderligere biblioteker til synkronisering, mens disse metoder i C# er implementeret som statiske metoder i en separat biblioteksklasse Monitor (implicit brugt af operatørlåsen). I C# indeholder standardbiblioteket også flere yderligere synkroniseringsprimitiver til parallel eksekvering af tråde: mutexes, semaforer, synkroniseringstimere. Siden version 1.5 har JDK SE inkluderet pakkerne java.util.concurrent, java.util.concurrent.atomic og java.util.concurrent.locks, som indeholder et omfattende sæt værktøjer til implementering af parallel computing.
Java Native Interface (JNI) tillader programmer at kalde systemspecifikke funktioner på lavt niveau (såsom winAPI-biblioteker) fra Java. Som regel bruges JNI ved skrivning af drivere. Når man skriver JNI-biblioteker, skal en udvikler bruge en speciel API, der leveres gratis. Der er også specialiserede biblioteker til Java-interaktion med COM.
Platform Invoke (P/Invoke) teknologien implementeret i .NET giver dig mulighed for at kalde ekstern kode fra C#, som Microsoft kalder unmanaged . Gennem attributterne i metadataene kan programmøren præcist kontrollere overføringen ( marshaling ) af parametre og resultater, og dermed undgå behovet for ekstra tilpasningskode. P/Invoke giver næsten fuldstændig adgang til proceduremæssige API'er (såsom Win32 eller POSIX ), men giver ikke direkte adgang til C++ klassebiblioteker.
.NET Framework giver også en bro mellem .NET og COM , så du kan få adgang til COM-komponenter, som om de var native .NET-objekter, hvilket kræver yderligere programmørindsats, når du bruger COM-komponenter med komplekse ikke-trivielle grænseflader (f.eks. i tilfælde af passerende strukturer via et byte-array). I disse tilfælde skal du ty til usikker kode (se nedenfor) eller andre løsninger.
C# tillader begrænset brug af pointere , som sprogdesignere ofte finder farlige. C#'s tilgang til dette er at kræve nøgleordet unsafepå kodeblokke eller metoder, der bruger denne funktion. Dette nøgleord advarer brugere om en sådan kode om dens potentielle fare. Det kræver også en eksplicit/usikker compiler-indstilling, som er slået fra som standard. En sådan "usikker" kode bruges til at forbedre interaktionen med den ikke-administrerede API og nogle gange til at forbedre effektiviteten af visse dele af koden.
C# tillader også programmøren at deaktivere normal typekontrol og andre CLR-sikkerhedsfunktioner ved at tillade brugen af pointervariabler, så længe unsafe. Fordelen ved administreret usikker kode i forhold til P/Invoke eller JNI er, at det giver programmøren mulighed for at fortsætte med at arbejde i et velkendt C#-miljø for at udføre opgaver, som ellers ville kræve at kalde uadministreret kode skrevet på et andet sprog.
Der er adskillige JVM -implementeringer til næsten alle platforme på markedet. JVM er udviklet af virksomheder som IBM , Sun Microsystems (siden 2010 Oracle ), Bea og en række andre. Det skal bemærkes, at Sun (Oracle) frigiver sin JVM både under sin egen licens [6] og under en modificeret (gennem den såkaldte "Classpath undtagelse") GPLv2-licens [7] Arkiveret 3. marts 2012. .
Java Web Start og applets giver en bekvem, let og sikker måde at distribuere desktop-applikationer på, og effektiviteten af dens bytekode - repræsentation sammen med aggressive komprimeringsteknologier såsom pack200 gør Java til et båndbredde-intensivt distributionsværktøj til webapplikationer.
C# er også en standard på tværs af platforme. Dens primære platform er Windows , men der er implementeringer til andre platforme, hvoraf den vigtigste er Mono -projektet .
.NET er en universel open source-udviklingsplatform, der vedligeholdes af Microsoft og .NET-fællesskabet på GitHub. Det er på tværs af platforme (understøtter Windows, macOS og Linux) og kan bruges til at bygge enheds-, cloud- og IoT-applikationer.
ClickOnce tilbyder funktionalitet svarende til Java Web Start, men er kun tilgængelig for Windows-klienter. Internet Explorer på Windows kan vise .NET Windows Forms -grænsefladeelementer , som giver applet-lignende funktionalitet, men er begrænset til en bestemt browser.
Udviklingen af disse to sprog, og også deres API'er, binære formater og kørselstider, styres forskelligt.
C# er defineret af ECMA- og ISO-standarderne , som definerer sprogets syntaks, det eksekverbare modulformat (kendt som CLI) og Base Class Library (BCL). Standarderne inkluderer ikke mange af de nye biblioteker implementeret af Microsoft oven på standardrammerne, såsom biblioteker til databaser, GUI'er og webapplikationer ( Windows Forms , ASP.NET og ADO.NET ). Microsoft har dog formelt accepteret ikke at sagsøge fællesskabsprojekter for implementering af disse biblioteker [8] (link utilgængeligt) .
Til dato er ingen komponent i Java-miljøet blevet standardiseret af Ecma , ISO , ANSI eller nogen anden tredjeparts standardorganisation. Mens Oracle beholder ubegrænsede, eksklusive juridiske rettigheder til at ændre og licensere sine Java-varemærker, deltager Oracle frivilligt i en proces kaldet Java Community Process (JCP), som giver interesserede parter mulighed for at foreslå ændringer til enhver af Oracles Java-teknologier (sprog, værktøjssæt, API ) gennem konsultationer og ekspertgrupper. I henhold til reglerne i JCP kan ethvert forslag om at ændre JDK , Java runtime-miljøet eller Java-sprogspecifikationen ensidigt afvises af Oracle, fordi et "ja"-stemme fra Oracle er påkrævet for at godkende det. JCP kræver et medlemsgebyr fra kommercielle deltagere, mens non-profit organisationer og enkeltpersoner kan deltage gratis.
Mens "Java" er et varemærke tilhørende Oracle (tidligere Sun), og kun Oracle kan licensere navnet "Java", er der adskillige gratis projekter, der er delvist kompatible med Oracle Java. For eksempel giver GNU Classpath og GNU Compiler for Java (GCJ) et gratis klassebibliotek og compiler, der er delvist kompatibel med den nuværende version af Oracle Java [19] . I slutningen af 2006 annoncerede Sun, at al Java-kildekode, med undtagelse af proprietær kode, som de ikke bevarer rettighederne til, ville blive frigivet som gratis software i marts 2007 under en modificeret GPL -licens [20] . Oracle distribuerer i øjeblikket sin HotSpot Virtual Machine og Java-kompiler under GPL, men der er i øjeblikket ingen gratis licens til standard Java-runtime [21] [22] . Fordi Oracle vil beholde ejerskabet af sin Java-kildekode, vil frigivelse under GPL ikke forhindre Oracle i at distribuere ikke-frie eller open source-versioner af Java eller licensere den til andre [23] .
C#, CLR og det meste af det relaterede klassebibliotek er standardiserede og kan frit implementeres uden en licens. Adskillige gratis C#-systemer er allerede blevet implementeret, inklusive Mono og DotGNU . Mono-projektet implementerer også mange ikke-standard Microsoft-biblioteker ved at lære af Microsoft-materialer, svarende til GNU Classpath og Java. Målet med Mono-projektet er at undgå at krænke patenter eller ophavsrettigheder, og projektet er gratis at distribuere og bruge under GPL [24] . Microsoft distribuerer i øjeblikket en delt kildeversion af sin .NET-runtime til ikke-kommerciel brug [25] .
Java-tolke kan installeres ved at kopiere filer og arbejde uden begrænsninger på Windows siden mindst Windows 2000. Den officielle C#-ramme skal installeres på systemet som administrator, visse versioner af sproget kan kræve en bestemt version af Windows.
Java er bygget på en mere åben kultur med stærkt konkurrencedygtige virksomheder inden for forskellige områder af funktionalitet. De fleste af de ekstra biblioteker er tilgængelige under gratis og open source-licenser. Sun opfordrer også til praksis med at beskrive nogle funktioner som en specifikation (se JCP-processen), og overlade implementeringen til tredjeparter (eventuelt at give en referenceimplementering). Dermed er spørgsmålet om uafhængighed fra softwareproducenten løst.
På trods af eksistensen af Mono , binder C# udviklere tæt til Microsoft -platformen (inklusive OS, kontorløsninger). Derfor har brugeren af software skrevet i .NET ofte ikke noget valg i forhold til at bruge forskellige systemkomponenter. Dette fører til den såkaldte vendor-locking, hvor producenten af tredjepartssoftware kan diktere køberen næsten alle betingelser for at understøtte det implementerede projekt. Mens brugeren af en Java-applikation som regel kan vælge leverandøren af yderligere software (såsom en database, OS, applikationsserver osv.).
Java er ældre end C# og bygget på en stor og aktiv brugerbase, der bliver lingua franca i mange moderne områder inden for datalogi, især dem, der involverer netværk . Java dominerer programmeringskurser på amerikanske universiteter og colleges, og litteraturen om Java i dag er meget større end på C#. Javas modenhed og popularitet har ført til flere biblioteker og API'er i Java (hvoraf mange er open source) end i C#.
I modsætning til Java er C# et relativt nyt sprog. Microsoft har studeret eksisterende sprog som Java, Delphi og Visual Basic og har ændret nogle aspekter af sproget for bedre at passe til behovene i visse typer applikationer.
Med hensyn til Java kan man høre kritik af, at dette sprog er langsomt til at udvikle sig, det mangler nogle funktioner, der letter moderigtige programmeringsmønstre og -metoder. C#-sproget er blevet kritiseret for måske at være for hurtigt til at imødekomme aktuelle tendenser inden for programmering på bekostning af fokus og sproglig enkelhed. Tilsyneladende har designerne af Java indtaget en mere konservativ holdning til at tilføje store nye funktioner til sprogets syntaks end i andre moderne sprog – måske ikke at ville binde sproget til strømninger, der kan føre til blindgyder i det lange løb. Med udgivelsen af Java 5.0 blev denne tendens stort set vendt, da den introducerede flere store nye sprogfunktioner: type foreachlooping, automatisk indpakning, variadiske metoder, optalte typer, generiske typer og annoteringer (som alle også er til stede i C#). Startende med Java 8 begyndte aktiv implementering af nye funktioner, især: lambda-udtryk, nøgleordet var, modularitet i Jigsaw-projektet og så videre.
C# udvikler sig til gengæld hurtigere, med meget mindre tilbageholdenhed med at tilføje nye domænespecifikke funktioner. Denne tendens var især tydelig i versionen af C# 3.0, hvor der for eksempel dukkede SQL - lignende forespørgsler op. (De nye funktioner er bygget til at forblive et almindeligt sprog. For mere om C# 3.0, se C#-artiklen .) Domænespecifikke tilføjelser til Java er blevet overvejet, men er i det mindste indtil dato blevet opgivet.
Siden fremkomsten af C# er det konstant blevet sammenlignet med Java. Det er ubestrideligt, at C# og dets administrerede CLR skylder Java og dets JRE (Java Runtime Environment) meget.
Det kan diskuteres, om udviklingen af C# på nogen måde er et resultat af Microsofts erkendelse af, at et Java-ledet administreret kodemiljø har mange fordele i en voksende netværksverden, især med fremkomsten af internettet på andre enheder end personlige computere og den voksende vigtig netværkssikkerhed. Forud for oprettelsen af C# modificerede Microsoft Java (opretter J++ ) for at tilføje funktioner, der kun kører på Windows , og dermed overtrådte Sun Microsystems licensaftale . Mens Microsoft var i anden fase af sin forretningsstrategi, kendt som " Embrace, Extend and Extinguish ", blev J++-udviklingen standset af en retssag anlagt af Sun. Udelukket fra at udvikle en Java-klon med de funktioner, den ønskede, skabte Microsoft et alternativ, der var mere i overensstemmelse med deres behov og vision for fremtiden.
På trods af en så hektisk start, bliver det mere og mere tydeligt, at de to sprog sjældent konkurrerer med hinanden på markedet. Java dominerer mobilsektoren og har en stærk tilhængerskare på webapplikationsmarkedet. C# er blevet godt modtaget på Windows desktop-markedet, og takket være ASP.NET er C# også en spiller på webapplikationsmarkedet.
Desktop-applikationerFor begge sprog er der et sæt biblioteker, der giver mulighed for at bygge en brugergrænseflade til desktop-applikationer. I tilfælde af Java er disse Swing- og SWT- multiplatform-bibliotekerne samt JavaFX-platformen, som giver dig mulighed for at oprette RIA-applikationer. I princippet giver enhver af dem dig mulighed for at oprette desktop-applikationer på tværs af platforme i Java.
For C# på Windows-platformen er de vigtigste platforme til udvikling af desktop grafiske applikationer Windows Forms og WPF platforme. Til udvikling under Windows 8 er der en speciel platform WinRT . Til Windows 10-udvikling er der en dedikeret UWP-platform. Til andre platforme bruges gtk#-biblioteket, lavet af Mono-projektet. Forsøg på frit at implementere Windows. Forms er blevet lavet og bliver lavet (for eksempel i DotGNU- projektet ), men på grund af originalens lukkede karakter lider de uundgåeligt af sekundære og ufuldstændige, de kan næppe konkurrere med implementeringen fra Microsoft og kan derfor kun bruges til forsinket portering af Windows-applikationer til andre platforme. Udviklinger, der oprindeligt er baseret på Windows, er normalt bygget på Windows.Forms, og det bliver vanskeligt at overføre dem til en anden platform. Mono C#-udvikling ved hjælp af gtk# er bærbar, men meget mindre. Der er ingen implementering af WPF-rammerne i Mono-projektet, så WPF-applikationer er ikke bærbare til Linux-baserede operativsystemer.
C# bliver sammen med Java efterhånden populært på adskillige Linux- og BSD-baserede operativsystemer [26] [27] [28] . Implementeringen af Mono-projektet var en juridisk smertefri proces, da CLR- og C#-sproget er standardiseret af Ecma og ISO, og enhver kan implementere dem uden at bekymre sig om den juridiske side af tingene [29] . Samtidig skal det bemærkes, at en applikation skrevet under Windows-miljøet kan have betydelige startproblemer under et andet OS.
MobilappsJ2ME (JavaME, Java(2) Micro Edition) har en meget bred base på mobiltelefon- og PDA -markederne , hvor kun de billigste enheder mangler KVM (en nedstribet Java Virtual Machine til ressourcebegrænsede enheder). Java-programmer, herunder mange spil, er allestedsnærværende.
Mens næsten alle telefoner inkluderer KVM, bruges disse funktioner ikke særlig meget af de fleste brugere. Java-applikationer på de fleste telefoner består normalt af menusystemer, små spil osv. Fuldgyldige mobiltelefonapplikationer er sjældne.
Java bruges til at udvikle applikationer til Android ved hjælp af den ikke-standardiserede Dalvik virtuelle maskine (eller ART ).
C# er det primære sprog til at skrive applikationer til Windows Phone -mobiloperativsystemet udviklet af Microsoft. Der er dog en Xamarin cross - platform udviklingsramme , der giver dig mulighed for at oprette native applikationer til Android, IOS og Windows Phone.
Java | |
---|---|
Platforme | |
Sun Technologies | |
Nøgle tredjepartsteknologier | |
Historie |
|
Sprogegenskaber | |
Scripting sprog |
|
Java konferencer |
|