Kérdések és válaszok junior fejlesztői pozícióhoz
Általános kérdés
1. Milyen tervezési mintákat ismer? Meséljen két tervezési mintáról, amelyeket a munkájában használt.
Nagyon sokféle minta létezik. Azoknak, akik szeretnének alaposan megismerkedni a tervezési mintákkal, javaslom, hogy olvassák el a "Head First. Design Patterns" című könyvet. Segítségével könnyedén elsajátíthatja a legalapvetőbb tervezési minták részleteit. Az állásinterjún megemlíthető tervezési mintákkal kapcsolatban a következők jutnak eszünkbe:- Builder – gyakran használt sablon, az objektumkészítés klasszikus megközelítésének alternatívája;
- Stratégia – egy minta, amely lényegében a polimorfizmust képviseli. Vagyis egy felületünk van, de a program viselkedése a függvénynek átadott konkrét interfész implementációtól függően változik (a stratégiai mintát ma már szinte mindenhol használják a Java alkalmazásokban).
- Factory — ez a minta megtalálható az ApplicationContextben (vagy a BeanFactoryban);
- Singleton – alapértelmezés szerint minden bab szingli;
- Proxy – alapvetően a Springben minden ilyen vagy olyan módon ezt a mintát használja, például az AOP;
- Felelősségi lánc – a Spring Security alapját képező minta;
- Sablon – a tavaszi JDBC-ben használatos.
Java Core
2. Milyen adattípusok vannak a Java-ban?
A Java a következő primitív adattípusokkal rendelkezik:- bájt – -128 és 127 közötti egész számok, 1 bájtot foglalnak el;
- rövid – a -32768 és 32767 közötti egész számok 2 bájtot foglalnak el;
- int – -2147483648 és 2147483647 közötti egész számok, 4 bájtot foglal el;
- hosszú – 9223372036854775808 és 9223372036854775807 közötti egész számok, 8 bájtot foglalnak el;
- float – a -3,4E+38 és 3,4E+38 közötti lebegőpontos számok 4 bájtot foglalnak el;
- double – a -1,7E+308 és 1,7E+308 közötti lebegőpontos számok 8 bájtot foglalnak el;
- char – egyetlen karakter UTF-16-ban, 2 bájtot foglal el;
- logikai igaz/hamis értékek, 1 bájtot foglal el.
3. Miben különbözik egy objektum a primitív adattípusoktól?
Az első különbség az elfoglalt memória mennyisége: a primitívek nagyon keveset foglalnak el, mert csak a saját értéküket tartalmazzák, de az objektumok sok különböző értéket tartalmazhatnak – primitíveket és más objektumokra való hivatkozásokat egyaránt. A második különbség a következő: a Java egy objektum-orientált nyelv, így a Java-ban minden az objektumok közötti interakció. A primitívek nem nagyon illenek ide. Valójában ezért a Java nem 100%-ban objektum-orientált nyelv. A harmadik különbség, amely a másodikból következik, az, hogy mivel a Java az objektumok interakcióira összpontosít, sok különböző mechanizmus létezik az objektumok kezelésére. Például konstruktorok, metódusok, kivételek (amelyek elsősorban objektumokkal működnek) stb. És hogy a primitívek valahogy működjenek ebben az objektum-orientált környezetben, a Java készítői kitaláltákburkolók a primitív típusokhoz ( Integer , Character , Double , Boolean ...)4. Mi a különbség az argumentumok referencia és érték szerinti átadása között?
A primitív mezők tárolják értéküket: például ha int i = 9-et állítunk be; , akkor az i mező tárolja a 9 értéket. Ha van hivatkozásunk egy objektumra, az azt jelenti, hogy van egy mezőnk az objektumra való hivatkozással. Más szóval, van egy mezőnk, amely az objektum címét tárolja a memóriában.Cat cat = new Cat();
Ez azt jelenti, hogy az objektumra hivatkozó mezők is értékeket tárolnak . Értékük memóriacímek. Vagyis a cat tárolja az új Cat() objektum memóriacímét . Amikor egy argumentumot adunk át egy metódusnak, az értéke másolódik. Primitív esetén a primitív értékét másoljuk. Ennek megfelelően a módszer a másolattal működik. A másolat megváltoztatása az eredetit nem érinti. Referenciatípus esetén a memóriacím értéke másolásra kerül. Ennek megfelelően mindkét referenciaváltozó ugyanarra az objektumra mutató címeket tárol. És ha ezt az új hivatkozást használjuk az objektum megváltoztatására, akkor azt tapasztaljuk, hogy a régi hivatkozásnál is megváltozott. Hiszen mindketten ugyanarra a tárgyra mutatnak.
5. Mi az a JVM, JDK és JRE?
A JVM a Java Virtual Machine rövidítése , amely a fordító által előre generált Java bájtkódot futtatja. A JRE a Java Runtime Environment rövidítése . Alapvetően ez egy Java alkalmazások futtatására szolgáló környezet. Tartalmazza a JVM-et, a szabványos könyvtárakat és egyéb összetevőket a Java programozási nyelven írt kisalkalmazások és alkalmazások futtatásához. Más szóval, a JRE egy csomag mindent tartalmaz, ami egy lefordított Java program futtatásához szükséges, de nem tartalmaz olyan eszközöket és segédprogramokat, mint például fordítók vagy hibakeresők az alkalmazások fejlesztéséhez. A JDK a Java Development Kit rövidítése , amely a JRE kiterjesztése. Vagyis nem csak Java alkalmazások futtatására, hanem fejlesztésére is alkalmas környezet. A JDK mindent tartalmaz, ami a JRE-ben található, valamint különféle további eszközöket – fordítókat és hibakeresőket –, amelyek a Java alkalmazások létrehozásához szükségesek (beleértve a Java dokumentumokat is).6. Miért érdemes a JVM-et használni?
Ahogy fentebb említettük, a Java virtuális gép egy virtuális gép, amely a fordító által előre generált Java bájtkódot futtat. Ez azt jelenti, hogy a JVM nem érti a Java forráskódot. Tehát először összeállítjuk a .java fájlokat. A lefordított fájlok .classkiterjesztést, és most bájtkód formájában vannak, amit a JVM megért. A JVM operációs rendszerenként eltérő. Amikor a JVM bájtkódfájlokat futtat, azokat a futó operációs rendszerhez igazítja. Valójában, mivel különböző JVM-ek léteznek, a JDK (vagy JRE) is különbözik a különböző operációs rendszerekben (minden verzióhoz saját JVM-re van szükség). Emlékezzünk arra, hogyan működik a fejlesztés más programozási nyelveken. Írsz egy programot, majd a kódját gépi kódba fordítják egy adott operációs rendszerhez, majd futtathatod. Más szóval, minden platformhoz más-más verziót kell írnia a programból. De a Java kettős kódfeldolgozása (a forráskód bájtkódba fordítása, majd a bájtkód feldolgozása a JVM által) lehetővé teszi, hogy élvezze a többplatformos megoldás előnyeit. A kódot egyszer elkészítjük, és bájtkódra fordítjuk. Ezután bármilyen operációs rendszerre vihetjük, és a natív JVM képes futtatni. És ez pontosan a Java legendájaegyszer írjon, bárhol futhat funkció.7. Mi az a bájtkód?
Ahogy fentebb is mondtam, a fordító a Java kódot köztes bájtkóddá alakítja (a .java kiterjesztésű fájloktól a .class kiterjesztésű fájlok felé haladunk). A bájtkód sok tekintetben hasonló a gépi kódhoz, azzal a különbséggel, hogy az utasításkészlete nem valós processzorhoz, hanem virtuálishoz való. Ennek ellenére tartalmazhat olyan szakaszokat, amelyeket egy JIT fordítóhoz terveztek, amely optimalizálja a parancsvégrehajtást az aktuális processzorhoz, amelyen a program fut. A JIT-fordítás, más néven on-the-fly fordítás, egy olyan technológia, amely növeli a bájtkódos program teljesítményét azáltal, hogy a bájtkódot gépi kódba vagy más formátumba fordítja, miközben a program fut. Ahogy azt sejteni lehetett, a JVM a JIT fordítót használja, amikor bájtkódot futtat. Nézzünk néhány minta bájtkódot: Nem túl olvasható, mi? A jó hír az, hogy ez az utasítás nem nekünk szól. A JVM-nek való.8. Melyek a JavaBean szolgáltatásai?
A JavaBean egy Java osztály, amely bizonyos szabályokat követ. Íme néhány szabály a JavaBean írására :-
Az osztálynak tartalmaznia kell egy üres (argumentum nélküli) konstruktort a nyilvános hozzáférés módosítóval. Ez a konstruktor lehetővé teszi az osztály objektumának létrehozását minden felesleges probléma nélkül (hogy ne kelljen felesleges érvekkel babrálni).
-
A belső mezők a get and set példány metódusokkal érhetők el , amelyeknek szabványos megvalósítással kell rendelkezniük. Például, ha van névmezőnk , akkor legyen getName és setName stb. Ez lehetővé teszi a különféle eszközök (keretrendszerek) számára, hogy minden nehézség nélkül automatikusan megkapják és beállítsák a babok tartalmát.
-
Az osztálynak felül kell írnia az equals() , hashCode() és toString() metódusokat.
-
Az osztálynak szerializálhatónak kell lennie. Vagyis rendelkeznie kell a Serializable marker interfésszel, vagy meg kell valósítania az Externalizable interfészt. Ez azért van így, hogy a bab állapota megbízhatóan menthető, tárolható és visszaállítható legyen.
9. Mi az OutOfMemoryError?
Az OutOfMemoryError egy kritikus futásidejű hiba, amely a Java virtuális géphez (JVM) kapcsolódik. Ez a hiba akkor fordul elő, ha a JVM nem tud lefoglalni egy objektumot, mert nincs elég memória hozzá, és a szemétgyűjtő nem tud több memóriát lefoglalni. Az OutOfMemoryError néhány típusa :-
OutOfMemoryError: Java kupacterület — az objektum nem foglalható le a Java kupacban, mert nincs elegendő memória. Ezt a hibát memóriaszivárgás vagy egy alapértelmezett kupacméret okozhatja, amely túl kicsi az aktuális alkalmazáshoz.
-
OutOfMemoryError: A GC Overhead limit túllépve – mivel az alkalmazás adatai alig férnek el a kupacban, a szemétgyűjtő folyamatosan fut, ami miatt a Java program nagyon lassan fut. Ennek eredményeként a szemétgyűjtő rezsikorlátját túllépik, és az alkalmazás ezzel a hibával összeomlik.
-
OutOfMemoryError: A kért tömb mérete meghaladja a virtuális gép korlátját – ez azt jelzi, hogy az alkalmazás megpróbált memóriát lefoglalni egy olyan tömbhöz, amely meghaladja a kupacméretet. Ez ismét azt jelentheti, hogy alapértelmezés szerint nem volt elegendő memória lefoglalva.
-
OutOfMemoryError: Metaspace – a kupacból kifogyott a metaadatok számára lefoglalt hely (a metaadatok az osztályokhoz és metódusokhoz tartozó utasítások).
-
OutOfMemoryError: kérjen mérete bájtokat az ok miatt. Elfogyott a csereterület — hiba történt, amikor megpróbálta lefoglalni a memóriát a kupacból, és ennek eredményeként a kupacban nincs elegendő hely.
10. Mi az a veremnyom? Hogyan szerezhetem meg?
A verem nyomkövetés azoknak az osztályoknak és metódusoknak a listája, amelyek egy alkalmazás végrehajtása során eddig meghívásra kerültek. A verem nyomkövetését az alkalmazás egy adott pontján a következőképpen kaphatja meg:StackTraceElement[] stackTraceElements =Thread.currentThread().getStackTrace();
Ezzel megkapjuk a StackTraceElements tömbjét, amelyek a LIFO (Last In First Out) sorrendben vannak elrendezve. A Java nyelven, amikor az emberek veremkövetésről beszélnek, általában a konzolon hiba (vagy kivétel) esetén megjelenő veremnyomra gondolnak. A veremnyomot az alábbi kivételektől kaphatja meg:
StackTraceElement[] stackTraceElements;
try{
...
} catch (Exception e) {
stackTraceElements = e.getStackTrace();
}
És ha egy kivétel veremnyomát szeretnénk megjeleníteni a konzolon:
try{
...
} catch (Exception e) {
e.printStackTrace();
}
Ezenkívül, ha hiba, ellenőrizetlen kivétel vagy kezeletlen ellenőrzött kivétel történik, akkor automatikusan megkapjuk a kivétel veremnyomát a konzolon, amikor az alkalmazás összeomlik. Íme egy kis példa a verem nyomkövetésére a konzolon: És ezzel a megjegyzéssel lezárjuk a mai témával kapcsolatos vitát.