Java-interviewspørgsmål

1. Introduktion

Denne artikel indeholder svar på nogle af de vigtigste spørgsmål om jobinterview om kernen i Java. Svarene på nogle af dem er muligvis ikke indlysende, så denne artikel hjælper med at rydde op.

2. Core-Java sprogspørgsmål til begyndere

Q1. Videregives data ved hjælp af reference eller efter værdi i Java?

Selv om svaret på dette spørgsmål er ret simpelt, kan dette spørgsmål være forvirrende for begyndere. Lad os først afklare, hvad spørgsmålet handler om:

  1. Går forbi værdi - det betyder, at vi passerer en kopi af et objekt som en parameter til en metode.
  2. Bestået ved reference - det betyder, at vi passerer en henvisning til et objekt som en parameter til en metode.

For at besvare spørgsmålet skal vi analysere to tilfælde. De repræsenterer to typer data, som vi kan overføre til en metode: en primitiv og en genstand.

Når vi overfører primitive til en metode, kopieres dens værdi til en ny variabel. Når det kommer til objekter, kopieres referenceværdien til en ny variabel. Så vi kan sige, at Java er et strengt forbipasseringsværdi Sprog.

Vi kan lære mere om det i en af ​​vores artikler: Pass-By-Value som en Parameter Passing Mechanism i Java.

Q2. Hvad er forskellen mellem import og statisk import?

Vi kan bruge regelmæssig import til at importere en bestemt klasse eller alle klasser defineret i en anden pakke:

importere java.util.ArrayList; // specifik klasseimport java.util. *; // alle klasser i util-pakke

Vi kan også bruge dem til at importere offentlige indlejrede klasser af en lukkende klasse:

import com.baeldung.A. *

Vi skal dog være opmærksomme på, at importen ovenfor ikke importerer klassen EN sig selv.

Der er også statisk import, der giver os mulighed for at importere statiske medlemmer eller indlejrede klasser:

importer statisk java.util.Collections.EMPTY_LIST;

Effekten er, at vi kan bruge den statiske variabel EMPTY_LIST uden at foregribe det fuldt kvalificerede klassenavn, dvs. som om det blev erklæret i den aktuelle klasse.

Q3. Hvilke adgangsmodifikatorer er tilgængelige i Java, og hvad er deres formål?

Der er fire adgangsmodifikatorer i Java:

  1. privat
  2. Standard (pakke)
  3. beskyttet
  4. offentlig

Det privat modifikator sikrer, at klassemedlemmer ikke er tilgængelige uden for klassen. Det kan anvendes på metoder, egenskaber, konstruktører, indlejrede klasser, men ikke til selve topklasser.

I modsætning til privat modifikator, kan vi anvende Standard modifikator til alle typer klassemedlemmer og til selve klassen. Vi kan ansøge Standard synlighed ved slet ikke at tilføje nogen adgangsmodifikator. Hvis vi bruger Standard synlighed vores klasse eller dens medlemmer er kun tilgængelige inden for pakken i vores klasse. Vi skal huske på, at standardadgangsmodifikatoren ikke har noget til fælles med Standard nøgleord.

På samme måde som Standard modifikator, kan alle klasser inden for en pakke få adgang beskyttet medlemmer. Hvad mere er, den beskyttet modifikator giver underklasser adgang til de beskyttede medlemmer af en superklasse, selvom de ikke er inden for den samme pakke. Vi kan ikke anvende denne adgangsmodifikator på klasser, kun på klassemedlemmer.

Det offentlig modifikator kan bruges sammen med klassens nøgleord og alle klassemedlemmer. Det gør klasser og klassemedlemmer tilgængelige i alle pakker og af alle klasser.

Vi kan lære mere i artiklen Java Access Modifiers.

Q4. Hvilke andre modifikatorer er tilgængelige i Java, og hvad er deres formål?

Der er fem andre modifikatorer tilgængelige i Java:

  • statisk
  • endelig
  • abstrakt
  • synkroniseret
  • flygtige

Disse styrer ikke synligheden.

Først og fremmest kan vi anvende statisk nøgleord til felter og metoder. Statiske felter eller metoder er klassemedlemmer, mens ikke-statiske felter er objektmedlemmer. Klassemedlemmer har ikke brug for nogen instans for at blive påberåbt. De kaldes med klassens navn i stedet for objektets referencenavn. Denne artikel går nærmere ind på statisk nøgleord.

Så har vi endelig nøgleord. Vi kan bruge det med felter, metoder og klasser. Hvornår endelig bruges på et felt, betyder det, at feltreferencen ikke kan ændres. Så det kan ikke tildeles igen til et andet objekt. Hvornår endelig anvendes til en klasse eller en metode, forsikrer det os om, at denne klasse eller metode ikke kan udvides eller tilsidesættes. Det endelig nøgleord er forklaret mere detaljeret i denne artikel.

Det næste nøgleord er abstrakt. Denne kan beskrive klasser og metoder. Når klasser er abstrakt, de kan ikke instantieres. I stedet er de beregnet til at blive underklasseret. Når metoder er det abstrakt, de efterlades uden implementering, og de kan tilsidesættes i underklasser.

Det synkroniseret nøgleord kan være det mest avancerede. Vi kan bruge det med forekomsten såvel som med statiske metoder og kodeblokke. Når vi bruger dette nøgleord, får vi Java til at bruge en monitorlås til at give synkronisering på et givet kodefragment. Flere oplysninger om synkroniseret kan findes i denne artikel.

Det sidste nøgleord, vi skal diskutere, er flygtige. Vi kan kun bruge det sammen med instansfelter. Den erklærer, at feltværdien skal læses fra og skrives til hovedhukommelsen - uden om CPU-cachen. Alt læser og skriver for en flygtig variabel er atomisk. Det flygtige nøgleord forklares detaljeret i denne artikel.

Q5. Hvad er forskellen mellem JDK, JRE og JVM?

JDK står for Java-udviklingssæt, som er et sæt værktøjer, der er nødvendige for udviklere til at skrive applikationer i Java. Der er tre typer JDK-miljøer:

  • Standard Edition - udviklingssæt til oprettelse af bærbare desktop- eller serverapplikationer
  • Enterprise Edition - en udvidelse til Standard Edition med understøttelse af distribueret computing eller webtjenester
  • Micro Edition - udviklingsplatform til indlejrede og mobile applikationer

Der er masser af værktøjer inkluderet i JDK, som hjælpe programmører med at skrive, debugge eller vedligeholde applikationer. De mest populære er en kompilator (javac), en tolk (java), en arkiver (krukke) og en dokumentationsgenerator (javadoc).

JRE er en Java Runtime-miljø. Det er en del af JDK, men det indeholder den mindste funktionalitet til at køre Java-applikationer. Den består af en Java Virtual Machine, kerneklasser og understøttende filer. For eksempel har den ingen compiler.

JVM er forkortelsen for Java Virtual Machine, som er en virtuel maskine, der er i stand til at køre programmer, der er kompileret til bytecode. Det er beskrevet af JVM-specifikationen, da det er vigtigt at sikre interoperabilitet mellem forskellige implementeringer. Den vigtigste funktion ved en JVM er at give brugerne mulighed for at implementere den samme Java-applikation i forskellige operativsystemer og miljøer uden at bekymre sig om, hvad der ligger under.

Lad os kontrollere forskellen mellem JVM, JRE og JDK for mere information.

Q6. Hvad er forskellen mellem stak og bunke?

Der er to dele af hukommelsen, hvor alle variabler og objekter er gemt af JVM. Den første er stak og det andet er bunke.

Det stak er et sted, hvor JVM reserverer blokke til lokale variabler og yderligere data. Stakken er en LIFO (sidst i først ud) struktur. Det betyder, at når en metode kaldes, er en ny blok reserveret til lokale variabler og objektreferencer. Hver ny metodeindkaldelse forbeholder sig den næste blok. Når metoder er færdige med deres udførelse, frigives blokke på den omvendte måde, de blev startet på.

Hver ny tråd har sin egen stak.

Vi skal være opmærksomme på, at stakken har meget mindre hukommelsesplads end bunken. Og når en stak er fuld, vil JVM kaste en StackOverflowError. Det vil sandsynligvis forekomme, når der er et dårligt rekursivt opkald, og rekursionen går for dybt.

Hvert nyt objekt oprettes på Java heap som bruges til en dynamisk fordeling. Der er en garbage samler som er ansvarlig for at slette ubrugte genstande, der er opdelt i unge (børnehave) og gamle rum. Hukommelsesadgang til bunken er langsommere end adgangen til stakken. JVM kaster en OutOfMemoryError når bunken er fuld.

Vi kan finde flere detaljer i artiklen Stack Memory og Heap Space i Java.

Q7. Hvad er forskellen mellem Sammenlignelig og Komparator Grænseflader?

Undertiden når vi skriver en ny klasse, vil vi gerne være i stand til at sammenligne objekter fra den klasse. Det er især nyttigt, når vi vil bruge sorterede samlinger. Der er to måder, vi kan gøre dette på: med Sammenlignelig interface eller med Komparator interface.

Lad os først se på Sammenlignelig grænseflade:

offentlig grænseflade Sammenlignelig {int sammenligneTo (T var1); }

Vi skal implementere denne grænseflade efter den klasse, hvis objekter vi vil sortere.

Det har sammenligne med() metode og returnerer et heltal. Det kan returnere tre værdier: -1, 0 og 1, hvilket betyder, at dette objekt er mindre end, lig med eller større end det sammenlignede objekt.

Det er værd at nævne, at den tilsidesatte sammenligneT0 () metoden skal være i overensstemmelse med lige med() metode.

På den anden side kan vi bruge Komparator interface. Det kan videregives til sortere() metoder til Kollektion interface eller ved instantering af sorterede samlinger. Derfor bruges det mest til at skabe en engangs sorteringsstrategi.

Hvad mere er, det er også nyttigt, når vi bruger en tredjepartsklasse, der ikke implementerer den sammenlignelige grænseflade.

Ligesom sammenligne med() metode, den tilsidesatte sammenligne() metoder skal være i overensstemmelse med lige med() metode, men de kan eventuelt tillade sammenligning med nuller.

Lad os besøge Comparator and Comparable i Java-artiklen for at få flere oplysninger.

Q8. Hvad er ugyldig Type og hvornår bruger vi det?

Hver gang vi skriver en metode i Java, skal den have en returtype. Hvis vi ønsker, at metoden ikke skal returnere nogen værdi, kan vi bruge ugyldig nøgleord.

Vi skal også vide, at der er en Ugyldig klasse. Det er en pladsholderklasse, der f.eks. Kan bruges, når man arbejder med generiske lægemidler. Det Ugyldig klasse kan hverken instantieres eller udvides.

Q9. Hvad er metoderne i objektklassen, og hvad gør de?

Det er vigtigt at vide, hvilke metoder Objekt hold indeholder, og hvordan de fungerer. Det er også meget nyttigt, når vi vil tilsidesætte disse metoder:

  • klon () - returnerer en kopi af dette objekt
  • lige med() - vender tilbage rigtigt når dette objekt er lig med det objekt, der sendes som en parameter
  • færdiggør () - affaldssamleren kalder denne metode, mens den renser hukommelsen
  • getClass () - returnerer runtime-klassen for dette objekt
  • hashCode () - returnerer en hash-kode for dette objekt. Vi skal være opmærksomme på, at det skal være i overensstemmelse med lige med() metode
  • underrette() - sender en meddelelse til en enkelt tråd, der venter på objektets skærm
  • notifyAll () - sender en meddelelse til alle tråde, der venter på objektets skærm
  • toString () - returnerer en strengrepræsentation af dette objekt
  • vente() - der er tre overbelastede versioner af denne metode. Det tvinger den aktuelle tråd til at vente den angivne tid, indtil en anden tråd ringer underrette() eller notifyAll () på dette objekt.

Q10. Hvad er et rum, og hvordan kan vi bruge det?

Enum er en type klasse, der giver udviklere mulighed for at specificere et sæt foruddefinerede konstante værdier. For at skabe en sådan klasse er vi nødt til at bruge enum nøgleord. Lad os forestille os et antal dage i ugen:

offentlig enum Dag {SUNDAG, MANDAG, TIRSDAG, ONSDAG, TORSDAG, FREDAG, LØRDAG}

For at gentage over alle konstanter kan vi bruge det statiske værdier () metode. Derudover gør enums os i stand til at definere medlemmer såsom egenskaber og metoder som almindelige klasser.

Selvom det er en særlig type klasse, kan vi ikke underklasse det. Et enum kan dog implementere en grænseflade.

En anden interessant fordel ved Enums er, at de er trådsikre, og derfor bruges de populært som singletoner.

Vi kan finde mere om Enums i en af ​​vores guider.

Q11. Hvad er -en KRUKKE?

KRUKKE er en genvej til Java arkiv. Det er en arkivfil pakket i ZIP-filformatet. Vi kan bruge den til at medtage de klassefiler og de ekstra ressourcer, der er nødvendige for applikationer. Det har mange funktioner:

  • Sikkerhed - vi kan digitalt underskrive JAR-filer
  • Kompression - mens vi bruger en JAR, kan vi komprimere filer til effektiv lagring
  • Bærbarhed - vi kan bruge den samme JAR-fil på tværs af flere platforme
  • Versionering - JAR-filer kan indeholde metadata om de filer, de indeholder
  • Forsegling - vi kan forsegle en pakke i en JAR-fil. Dette betyder, at alle klasser fra en pakke skal inkluderes i den samme JAR-fil
  • Udvidelser - vi kan bruge JAR-filformatet til at pakke moduler eller udvidelser til eksisterende software

Q12. Hvad er -enNullPointerException?

Det NullPointerException er sandsynligvis den mest almindelige undtagelse i Java-verdenen. Det er en ukontrolleret undtagelse og udvides således RuntimeException. Vi skal ikke prøve at håndtere det.

Denne undtagelse kastes, når vi forsøger at få adgang til en variabel eller kalder en metode til en null-reference, som når:

  • påberåbe sig en metode til en null-reference
  • indstilling eller hentning af et felt med en null-reference
  • kontrol af længden af ​​en null array-reference
  • indstilling eller hentning af et element i en null matrixreference
  • kaste nul

Q13. Hvad er to typer casting i Java? Hvilken undtagelse kan kastes under casting? Hvordan kan vi undgå det?

Vi kan skelne mellem to typer casting i Java. Vi kan udføre upcasting, der kaster et objekt til en supertype eller downcasting, der kaster et objekt til en undertype.

Upcasting er meget simpelt, da vi altid kan gøre det. For eksempel kan vi opkastere en Snor eksempel til Objekt type:

Objekt str = "streng";

Alternativt kan vi nedslået en variabel. Det er ikke så sikkert som upcasting, da det involverer en typekontrol. Hvis vi forkert støber et objekt, vil JVM kaste et ClassCastExcpetion ved kørselstid. Heldigvis kan vi bruge forekomst af nøgleord for at forhindre ugyldig casting:

Objekt o = "streng"; String str = (String) o; // det er ok Objekt o2 = nyt objekt (); Streng str2 = (Streng) o2; // ClassCastException kastes, hvis (o2 forekomst af streng) {// returnerer falske streng str3 = (streng) o2; }

Vi kan lære mere om type casting i denne artikel.

3. Core-Java sprogspørgsmål til avancerede programmører

Q1. Hvorfor er streng en uforanderlig klasse?

Det skal vi vide Snor genstande behandles forskelligt end andre genstande af JVM. En forskel er, at Snor genstande er uforanderlige. Det betyder, at vi ikke kan ændre dem, når vi først har oprettet dem. Der er flere grunde til, at de opfører sig sådan:

  1. De opbevares i streng pool som er en særlig del af bunkehukommelsen. Det er ansvarligt for at spare meget plads.
  2. Uforanderligheden af Snor klasse garanterer, at dens hash-kode ikke ændres. På grund af den kendsgerning Strenge kan effektivt bruges som nøgler i hashing-samlinger. Vi kan være sikre på, at vi ikke overskriver nogen data på grund af en ændring i hash-koder.
  3. De kan bruges sikkert på tværs af flere tråde. Ingen tråd kan ændre værdien af ​​en Snor objekt, så vi får trådsikkerhed gratis.
  4. Strenge er uforanderlige for at undgå alvorlige sikkerhedsproblemer. Følsomme data såsom adgangskoder kan ændres af en upålidelig kilde eller en anden tråd.

Vi kan lære mere om uforanderlighed af strenge i denne artikel.

Q2. Hvad er forskellen mellem dynamisk binding og statisk binding?

Binding i Java er en proces til at knytte et metodekald til den rette metodekropp. Vi kan skelne mellem to typer binding i Java: statisk og dynamisk.

Hovedforskellen mellem statisk binding og dynamisk binding er, at statisk binding finder sted ved kompileringstidspunktet og dynamisk binding ved kørselstid.

Statisk binding bruger klasseoplysninger til binding. Det er ansvarligt for at løse klassemedlemmer, der er privat eller statisk og endelig metoder og variabler. Statisk binding binder også overbelastede metoder.

Dynamisk bindingbruger derimod objektoplysninger til at løse bindinger. Derfor er det ansvarligt for løsning af virtuelle og tilsidesatte metoder.

Q3. Hvad er JIT?

JIT står for "just in time". Det er en komponent i JRE, der kører i løbetiden og øger applikationens ydeevne. Specifikt er det en kompilator, der kører lige efter programmets start.

Dette adskiller sig fra den almindelige Java-kompilator, som kompilerer koden længe før applikationen startes. JIT kan fremskynde applikationen på forskellige måder.

For eksempel er JIT-kompilatoren ansvarlig for at kompilere bytecode til native instruktioner i farten for at forbedre ydeevnen. Det kan også optimere koden til den målrettede CPU og operativsystemet.

Derudover har den adgang til mange runtime-statistikker, der kan bruges til rekompilering for optimal ydeevne. Med dette kan det også udføre nogle globale kodeoptimeringer eller omarrangere kode for bedre cacheudnyttelse.

Q4. Hvad er refleksion i Java?

Refleksion er en meget kraftig mekanisme i Java. Refleksion er en mekanisme i Java-sprog, der gør det muligt for programmører at undersøge eller ændre programmets interne tilstand (egenskaber, metoder, klasser osv.) Ved kørsel. Pakken java.lang.reflect indeholder alle nødvendige komponenter til brug af refleksion.

Når du bruger denne funktion, kan vi få adgang til alle mulige felter, metoder, konstruktører, der er inkluderet i en klassedefinition. Vi kan få adgang til dem uanset deres adgangsmodifikator. Det betyder, at vi for eksempel har adgang til private medlemmer. For at gøre det behøver vi ikke kende deres navne. Alt, hvad vi skal gøre er at bruge nogle statiske metoder til Klasse.

Det er værd at vide, at der er mulighed for at begrænse adgang via refleksion. For at gøre det kan vi bruge Java-sikkerhedsadministratoren og Java-sikkerhedspolitikken. De giver os mulighed for at give tilladelser til klasser.

Når vi arbejder med moduler siden Java 9, skal vi vide, at vi som standard ikke er i stand til at bruge refleksion på klasser importeret fra et andet modul. For at tillade andre klasser at bruge refleksion for at få adgang til de private medlemmer af en pakke, er vi nødt til at give tilladelsen "Reflektion".

Denne artikel går mere i dybden om Java Reflection.

Q5. Hvad er -en Klasselæsser?

Det klasselæsser er en af ​​de vigtigste komponenter i Java. Det er en del af JRE.

Kort sagt, den klasselæsser er ansvarlig for at indlæse klasser i JVM. Vi kan skelne mellem tre typer klasselæssere:

  • Bootstrap klasselæsser - det indlæser de centrale Java-klasser. De er placeret i / jre / lib vejviser
  • Udvidelse klasselæsser - det indlæser klasser placeret i / jre / lib / ekst eller i den sti, der er defineret af java.ext.dirs ejendom
  • System classloader - det indlæser klasser på klassestien til vores ansøgning

En klasselæsser indlæser klasser "efter behov". Det betyder, at klasser indlæses, efter at de er kaldet af programmet. Hvad mere er, en klasselæsser kan kun indlæse en klasse med et givet navn en gang. Men hvis den samme klasse er indlæst af to forskellige klasselæssere, mislykkes disse klasser i en ligestillingskontrol.

Der er flere oplysninger om klasselæssere i artiklen Klasselæssere i Java.

Q6. Hvad er forskellen mellem statisk og dynamisk klasseindlæsning?

Statisk klasseindlæsning finder sted, når vi har kildeklasser tilgængelige på kompileringstidspunktet. Vi kan gøre brug af det ved at oprette objektforekomster med ny nøgleord.

Dynamisk klassebelastning refererer til en situation, hvor vi ikke kan give en klassedefinition på kompileringstidspunktet. Alligevel kan vi gøre det under kørsel. For at oprette en forekomst af en klasse skal vi bruge Class.forName () metode:

Class.forName ("oracle.jdbc.driver.OracleDriver") 

Q7. Hvad er formålet med Serialiserbar Interface?

Vi kan bruge Serialiserbar interface for at muliggøre serielizability af en klasse ved hjælp af Java's Serialization API. Serialisering er en mekanisme til at gemme et objekts tilstand som en bytesekvens, mens deserialisering er en mekanisme til at gendanne et objekts tilstand fra en sekvens af bytes. Den serielle output indeholder objektets tilstand og nogle metadata om objektets type og typer af dets felter.

Vi bør vide, at undertyper af seriøse klasser også kan serienummeres. Men hvis vi ønsker at lave en klasse, der kan serialiseres, men dens supertype ikke kan serialiseres, skal vi gøre to ting:

  • implementere Serialiserbar interface
  • forsikre dig om, at en konstruktør uden argument er til stede i superklassen

Vi kan læse mere om serialisering i en af ​​vores artikler.

Q8. Er der en destruktor i Java?

I Java sletter affaldssamleren automatisk de ubrugte objekter for at frigøre hukommelsen. Udviklere har ikke noget behov for at markere objekterne til sletning, hvilket er fejlbehæftet. Så det er fornuftigt, at Java ikke har nogen destruktorer til rådighed.

Hvis objekterne holder åbne stikkontakter, åbne filer eller databaseforbindelser, Affaldssamleren er ikke i stand til at genvinde disse ressourcer. Vi kan frigive ressourcerne i tæt metode og anvendelse prøv endelig syntaks for at kalde metoden bagefter før Java 7, såsom I / O-klasser FileInputStreamog FileOutputStream. Fra og med Java 7 kan vi implementere interface Kan lukkes automatisk og brug prøv med ressourcer erklæring for at skrive kortere og renere kode. Men det er muligt, at API-brugerne glemmer at ringe til tæt metode, så færdiggør metode og Renere klasse opstår for at fungere som sikkerhedsnet. Men vær opmærksom på, at de ikke svarer til destruktøren.

Det er ikke forsikret begge færdiggør metode og Renere klasse kører hurtigt. De får endda ingen chance for at løbe, før JVM går ud. Selvom vi kunne ringe System.runFinalization at foreslå, at JVM kører færdiggør metoder til eventuelle objekter, der afventer færdiggørelse, er det stadig ikke-deterministisk.

Desuden er færdiggør metode kan forårsage ydeevneproblemer, deadlocks osv. Vi kan finde mere information ved at se på en af ​​vores artikler: En guide til færdiggørelsesmetoden i Java.

Fra og med Java 9, Renere klasse tilføjes for at erstatte færdiggør metode på grund af de ulemper, den har. Som et resultat har vi bedre kontrol over tråden, der udfører rengøringshandlingerne.

Men java spec påpeger rengøringsmidlernes opførsel under System.exit er implementeringsspecifik, og Java giver ingen garantier for, om rengøringshandlinger påberåbes eller ej.