CodeGym /Blog Jawa /Acak /Top 50 pitakonan lan jawaban wawancara kerja kanggo Java ...
John Squirrels
tingkat
San Francisco

Top 50 pitakonan lan jawaban wawancara kerja kanggo Java Core. Bagean 2

Diterbitake ing grup
Top 50 pitakonan lan jawaban wawancara kerja kanggo Java Core. Bagean 1Top 50 pitakonan lan jawaban wawancara kerja kanggo Java Core.  Bagean 2 - 1

Multithreading

24. Kepriye carane nggawe thread anyar ing basa Jawa?

Siji cara utawa liyane, thread digawe nggunakake kelas Thread. Nanging ana macem-macem cara kanggo nindakake iki ...
  1. Warisan java.lang.Thread .
  2. Ngleksanakake antarmuka java.lang.Runnable - konstruktor kelas Utas njupuk obyek Runnable.
Ayo dadi pirembagan bab saben wong.

Warisan kelas Utas

Ing kasus iki, kita nggawe kelas kita warisan java.lang.Thread . Wis cara roto () , lan iku mung apa kita kudu. Kabeh urip lan logika thread anyar bakal ana ing metode iki. Iki minangka cara utama kanggo thread anyar. Sawise iku, kabeh sing isih ana yaiku nggawe obyek saka kelas kita lan nelpon metode wiwitan () . Iki bakal nggawe thread anyar lan miwiti nglakokake logika. Ayo dideleng:

/**
* An example of how to create threads by inheriting the {@link Thread} class.
*/
class ThreadInheritance extends Thread {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance threadInheritance1 = new ThreadInheritance();
       ThreadInheritance threadInheritance2 = new ThreadInheritance();
       ThreadInheritance threadInheritance3 = new ThreadInheritance();
       threadInheritance1.start();
       threadInheritance2.start();
       threadInheritance3.start();
   }
}
Output konsol bakal kaya iki:
Utas-1 Utas-0 Utas-2
Yaiku, sanajan ing kene kita weruh yen benang dieksekusi ora kanthi urutan, nanging kaya sing dikarepake JVM kanggo mbukak :)

Ngleksanakake antarmuka Runnable

Yen sampeyan nglawan warisan lan / utawa wis oleh sawetara kelas liyane, sampeyan bisa nggunakake antarmuka java.lang.Runnable . Kene, kita nggawe kelas kita ngleksanakake antarmuka iki kanthi ngleksanakake cara roto () , kaya ing conto ing ndhuwur. Kabeh sing isih ana yaiku nggawe obyek Utas . Iku bakal katon sing luwih baris kode sing luwih elek. Nanging kita ngerti carane pusaka pernicious lan sing luwih apik kanggo ngindhari saka kabeh cara;) Deleng:

/**
* An example of how to create threads from the {@link Runnable} interface.
* It's easier than easy — we implement this interface and then pass an instance of our object
* to the constructor.
*/
class ThreadInheritance implements Runnable {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance runnable1 = new ThreadInheritance();
       ThreadInheritance runnable2 = new ThreadInheritance();
       ThreadInheritance runnable3 = new ThreadInheritance();

       Thread threadRunnable1 = new Thread(runnable1);
       Thread threadRunnable2 = new Thread(runnable2);
       Thread threadRunnable3 = new Thread(runnable3);

       threadRunnable1.start();
       threadRunnable2.start();
       threadRunnable3.start();
   }
}
Lan iki asile:
Utas-0 Utas-1 Utas-2

25. Apa bedane proses lan benang?

Top 50 pitakonan lan jawaban wawancara kerja kanggo Java Core.  Bagean 2 - 2Proses lan benang beda-beda kanthi cara ing ngisor iki:
  1. Program sing mlaku diarani proses, nanging benang minangka bagean saka proses.
  2. Proses kasebut independen, nanging benang minangka potongan saka proses.
  3. Proses duwe papan alamat sing beda ing memori, nanging benang nuduhake papan alamat sing umum.
  4. Ngalih konteks ing antarane benang luwih cepet tinimbang ngoper ing antarane proses.
  5. Komunikasi antar-proses luwih alon lan luwih larang tinimbang komunikasi antar-benang.
  6. Sembarang owah-owahan ing proses wong tuwa ora mengaruhi proses anak, nanging owah-owahan ing thread induk bisa mengaruhi thread anak.

26. Apa keuntungan saka multithreading?

  1. Multithreading ngidini aplikasi / program tansah responsif kanggo input, sanajan iku wis mlaku sawetara tugas latar mburi;
  2. Multithreading ndadekake iku bisa kanggo ngrampungake tugas luwih cepet, amarga Utas mbukak independen;
  3. Multithreading nyedhiyakake panggunaan memori cache sing luwih apik, amarga benang bisa ngakses sumber daya memori sing dienggo bareng;
  4. Multithreading nyuda jumlah server sing dibutuhake, amarga siji server bisa mbukak pirang-pirang thread bebarengan.

27. Apa kahanan ing siklus urip thread?

Top 50 pitakonan lan jawaban wawancara kerja kanggo Java Core.  Bagean 2 - 3
  1. Anyar: Ing negara iki, obyek Utas digawe nggunakake operator anyar, nanging thread anyar durung ana. Utas ora diwiwiti nganti kita nelpon cara wiwitan () .
  2. Runnable: Ing negara iki, thread wis siyap kanggo mbukak sawise wiwitan () metode diarani. Nanging, durung dipilih dening panjadwal thread.
  3. Running: Ing negara iki, panjadwal thread milih thread saka negara siap, lan mlaku.
  4. Nunggu / Diblokir: ing kahanan iki, thread ora mlaku, nanging isih urip utawa ngenteni thread liyane rampung.
  5. Mati / Mandhek: nalika thread metu saka roto () cara, iku ing negara mati utawa mungkasi.

28. Apa bisa mbukak thread kaping pindho?

Ora, kita ora bisa miwiti maneh utas, amarga sawise utas diwiwiti lan mlaku, bakal dadi negara Mati. Yen kita nyoba miwiti thread kaping pindho, java.lang.IllegalThreadStateException bakal dibuwang. Ayo dideleng:

class DoubleStartThreadExample extends Thread {

   /**
    * Simulate the work of a thread
    */
   public void run() {
	// Something happens. At this state, this is not essential.
   }

   /**
    * Start the thread twice
    */
   public static void main(String[] args) {
       DoubleStartThreadExample doubleStartThreadExample = new DoubleStartThreadExample();
       doubleStartThreadExample.start();
       doubleStartThreadExample.start();
   }
}
Bakal ana pangecualian sanalika eksekusi teka ing wiwitan kaloro ing thread sing padha. Coba dhewe ;) Iku luwih apik kanggo ndeleng iki sapisan saka krungu bab satus kaping.

29. Apa yen sampeyan nelpon mbukak () langsung tanpa nelpon wiwitan ()?

Ya, sampeyan mesthi bisa nelpon cara roto () , nanging Utas anyar ora bakal digawe, lan cara ora mbukak ing Utas kapisah. Ing kasus iki, kita duwe obyek biasa nelpon cara biasa. Yen kita ngomong bab wiwitan () cara, iku prakara liyane. Nalika cara iki diarani, JVM miwiti thread anyar. Utas iki, ing siji, nelpon cara kita;) Ora pracaya? Kene, cobanen:

class ThreadCallRunExample extends Thread {

   public void run() {
       for (int i = 0; i < 5; i++) {
           System.out.print(i);
       }
   }

   public static void main(String args[]) {
       ThreadCallRunExample runExample1 = new ThreadCallRunExample();
       ThreadCallRunExample runExample2 = new ThreadCallRunExample();

       // Two ordinary methods will be called in the main thread, one after the other.
       runExample1.run();
       runExample2.run();
   }
}
Lan output console bakal katon kaya iki:
0123401234
Nalika sampeyan bisa ndeleng, ora ana thread digawe. Kabeh bisa kaya ing kelas biasa. Pisanan, metode obyek pisanan dieksekusi, lan banjur kapindho.

30. Apa sing diarani benang daemon?

Utas daemon minangka utas sing nindakake tugas kanthi prioritas luwih murah tinimbang utas liyane. Ing tembung liya, tugase kanggo nindakake tugas tambahan sing kudu ditindakake mung bebarengan karo utas liyane (utama). Ana akeh benang daemon sing mlaku kanthi otomatis, kayata pengumpulan sampah, finalizer, lsp.

Apa sebabe Jawa mungkasi thread daemon?

Tujuane utas daemon yaiku nyedhiyakake dhukungan latar mburi kanggo utas pangguna. Dadi, yen utas utama diakhiri, JVM kanthi otomatis mungkasi kabeh benang daemon.

Metode kelas Utas

Kelas java.lang.Thread nyedhiyakake rong cara kanggo nggarap thread daemon:
  1. public void setDaemon(status boolean) - Cara iki nuduhake apa iki bakal dadi thread daemon. Default iku palsu . Iki tegese ora ana benang daemon sing bakal digawe kajaba sampeyan ujar kanthi khusus.
  2. public boolean isDaemon () - Cara iki ateges getter kanggo variabel daemon , kang kita nyetel nggunakake cara sadurungé.
Tuladha:

class DaemonThreadExample extends Thread {

   public void run() {
       // Checks whether this thread is a daemon
       if (Thread.currentThread().isDaemon()) {
           System.out.println("daemon thread");
       } else {
           System.out.println("user thread");
       }
   }

   public static void main(String[] args) {
       DaemonThreadExample thread1 = new DaemonThreadExample();
       DaemonThreadExample thread2 = new DaemonThreadExample();
       DaemonThreadExample thread3 = new DaemonThreadExample();

       // Make thread1 a daemon thread.
       thread1.setDaemon(true);

       System.out.println("daemon? " + thread1.isDaemon());
       System.out.println("daemon? " + thread2.isDaemon());
       System.out.println("daemon? " + thread3.isDaemon());

       thread1.start();
       thread2.start();
       thread3.start();
   }
}
Output konsol:
daemon? daemon bener? daemon palsu? Utas daemon palsu pangguna thread pangguna
Saka output, kita waca sing nang thread dhewe, kita bisa nggunakake statis currentThread () cara kanggo mangerteni kang thread. Utawa, yen kita duwe referensi kanggo obyek thread, kita uga bisa ngerteni langsung saka iku. Iki nyedhiyakake tingkat konfigurasi sing dibutuhake.

31. Apa bisa nggawe benang dadi daemon sawise digawe?

Ora. Yen sampeyan nyoba nindakake iki, sampeyan bakal entuk IllegalThreadStateException . Iki tegese kita mung bisa nggawe thread daemon sadurunge diwiwiti. Tuladha:

class SetDaemonAfterStartExample extends Thread {

   public void run() {
       System.out.println("Working...");
   }

   public static void main(String[] args) {
       SetDaemonAfterStartExample afterStartExample = new SetDaemonAfterStartExample();
       afterStartExample.start();
      
       // An exception will be thrown here
       afterStartExample.setDaemon(true);
   }
}
Output konsol:
Kerja... Pengecualian ing utas "utama" java.lang.IllegalThreadStateException ing java.lang.Thread.setDaemon(Thread.java:1359) ing SetDaemonAfterStartExample.main(SetDaemonAfterStartExample.java:14)

32. Apa sing diarani pancing mati?

Pancing mateni yaiku benang sing diarani sacara implisit sadurunge mesin virtual Java (JVM) dipateni. Mangkono, kita bisa nggunakake kanggo nerbitaké sumber utawa nyimpen negara nalika mesin virtual Jawa mati normal utawa ora normal. Kita bisa nambah pancing shutdown nggunakake cara ing ngisor iki:

Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
Kaya sing dituduhake ing conto:

/**
* A program that shows how to start a shutdown hook thread,
* which will be executed right before the JVM shuts down
*/
class ShutdownHookThreadExample extends Thread {

   public void run() {
       System.out.println("shutdown hook executed");
   }

   public static void main(String[] args) {

       Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());

       System.out.println("Now the program is going to fall asleep. Press Ctrl+C to terminate it.");
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
Output konsol:
Saiki program bakal turu. Pencet Ctrl + C kanggo mungkasi. pancing shutdown kaleksanan

33. Apa sing diarani sinkronisasi?

Ing Jawa, sinkronisasi minangka kemampuan kanggo ngontrol akses sawetara utas menyang sumber daya sing dienggo bareng. Nalika sawetara utas nyoba nindakake tugas sing padha bebarengan, sampeyan bisa entuk asil sing salah. Kanggo ndandani masalah iki, Jawa nggunakake sinkronisasi, sing ngidini mung siji utas kanggo mbukak ing wektu. Sinkronisasi bisa ditindakake kanthi telung cara:
  • Sinkronisasi metode
  • Sinkronisasi blok tartamtu
  • Sinkronisasi statis

Sinkronisasi metode

Cara sing disinkronake digunakake kanggo ngunci obyek kanggo sumber daya sing dienggo bareng. Nalika thread nelpon cara diselarasake, iku kanthi otomatis ndarbeni kunci obyek lan nerbitaké nalika thread ngrampungake tugas. Kanggo nindakake iki, sampeyan kudu nambah tembung kunci sing disinkronake . Kita bisa ndeleng cara kerjane kanthi ndeleng conto:

/**
* An example where we synchronize a method. That is, we add the synchronized keyword to it.
* There are two authors who want to use one printer. Each of them has composed their own poems
* And of course they don’t want their poems mixed up. Instead, they want work to be performed in * * * order for each of them
*/
class Printer {

   synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer  = new Printer();

       // Create two threads
       Writer1 writer1 = new Writer1(printer);
       Writer2 writer2 = new Writer2(printer);

       // Start them
       writer1.start();
       writer2.start();
   }
}

/**
* Author No. 1, who writes an original poem.
*/
class Writer1 extends Thread {
   Printer printer;

   Writer1(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<string> poem = Arrays.asList("I ", this.getName(), " Write", " A Letter");
       printer.print(poem);
   }

}

/**
* Author No. 2, who writes an original poem.
*/
class Writer2 extends Thread {
   Printer printer;

   Writer2(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<String> poem = Arrays.asList("I Do Not ", this.getName(), " Not Write", " No Letter");
       printer.print(poem);
   }
}
Lan output konsol yaiku:
Aku Utas-0 Tulis Layang Aku Ora Utas-1 Ora Tulis Layang

Blok sinkronisasi

Blok sing disinkronake bisa digunakake kanggo nindakake sinkronisasi ing sumber daya tartamtu ing sawijining metode. Ayo dadi ngomong yen ing cara gedhe (ya, sampeyan ora kudu nulis, nanging kadhangkala padha kelakon) sampeyan kudu nyinkronake mung bagean cilik sakperangan alesan. Yen sampeyan nglebokake kabeh kode cara ing blok sing disinkronake, bakal bisa digunakake kanthi cara sing padha karo cara sing disinkronake. Sintaks katon kaya iki:

synchronized ("object to be locked") {
   // The code that must be protected
}
Supaya ora mbaleni conto sadurunge, kita bakal nggawe thread nggunakake kelas anonim, IE kita bakal langsung ngleksanakake antarmuka Runnable.

/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   void print(List<String> wordsToPrint) {
       synchronized (this) {
           wordsToPrint.forEach(System.out::print);
       }
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer = new Printer();

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}

}
Lan output konsol yaiku:
Aku Writer1 Tulis Layang Aku Ora Writer2 Ora Tulis Ora Layang

Sinkronisasi statis

Yen sampeyan nggawe cara statis disinkronake, banjur ngunci bakal kelakon ing kelas, ora obyek. Ing conto iki, kita nindakake sinkronisasi statis kanthi nggunakake tembung kunci sing disinkronake menyang cara statis:

/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   static synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               Printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               Printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}
Lan output konsol yaiku:
Aku Ora Writer2 Ora Tulis Ora Layang Aku Writer1 Tulis Layang

34. Apa sing diarani variabel volatile?

Ing program multithreaded, tembung kunci molah malih digunakake kanggo safety thread. Nalika variabel sing bisa diowahi, owah-owahan kasebut katon ing kabeh utas liyane, saengga variabel bisa digunakake dening siji utas sekaligus. Kanthi nggunakake tembung kunci sing molah malih , sampeyan bisa njamin manawa variabel kasebut aman kanggo benang lan disimpen ing memori sing dienggo bareng, lan benang ora bakal disimpen ing cache. Kaya apa iki?

private volatile AtomicInteger count;
Kita mung nambah volatile kanggo variabel. Nanging elinga yen iki ora ateges safety thread lengkap ... Sawise kabeh, operasi ing variabel bisa uga ora atom. Yen ngandika, sampeyan bisa nggunakake kelas Atom sing nindakake operasi atom, IE ing instruksi CPU siji. Ana akeh kelas kasebut ing paket java.util.concurrent.atomic .

35. Apa sing diarani deadlock?

Ing Jawa, deadlock bisa kedadeyan minangka bagean saka multithreading. Kebuntuan bisa kedadeyan nalika utas nunggu kunci obyek sing dipikolehi dening utas liyane, lan utas kapindho ngenteni kunci obyek sing dipikolehi dening utas pisanan. Iki tegese loro utas nunggu saben liyane, lan eksekusi kode ora bisa diterusake. Top 50 pitakonan lan jawaban wawancara kerja kanggo Java Core.  Bagean 2 - 4Ayo nimbang conto sing duwe kelas sing ngetrapake Runnable. Konstruktor kasebut njupuk rong sumber. Run () cara ndarbeni kunci kanggo wong-wong mau supaya. Yen sampeyan nggawe rong obyek saka kelas iki, lan ngirim sumber daya ing urutan sing beda, sampeyan bisa kanthi gampang ngalami deadlock:

class DeadLock {

   public static void main(String[] args) {
       final Integer r1 = 10;
       final Integer r2 = 15;

       DeadlockThread threadR1R2 = new DeadlockThread(r1, r2);
       DeadlockThread threadR2R1 = new DeadlockThread(r2, r1);

       new Thread(threadR1R2).start();
       new Thread(threadR2R1).start();
   }
}

/**
* A class that accepts two resources.
*/
class DeadlockThread implements Runnable {

   private final Integer r1;
   private final Integer r2;

   public DeadlockThread(Integer r1, Integer r2) {
       this.r1 = r1;
       this.r2 = r2;
   }

   @Override
   public void run() {
       synchronized (r1) {
           System.out.println(Thread.currentThread().getName() + " acquired resource: " + r1);

           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           synchronized (r2) {
               System.out.println(Thread.currentThread().getName() + " acquired resource: " + r2);
           }
       }
   }
}
Output konsol:
Utas kapisan angsal sumber kapisan Utas kapindho pikantuk sumber kaloro

36. Kepriye carane supaya ora buntu?

Amarga kita ngerti carane deadlock kedadeyan, kita bisa nggawe kesimpulan ...
  • Ing conto ing ndhuwur, deadlock ana amarga kasunyatan sing kita wis nested ngunci. Yaiku, kita duwe blok sing disinkronake ing blok sing disinkronake. Kanggo ngindhari iki, tinimbang nesting, sampeyan kudu nggawe lapisan abstraksi anyar sing luwih dhuwur, mindhah sinkronisasi menyang tingkat sing luwih dhuwur, lan ngilangi kunci nested.
  • Sing luwih ngunci sampeyan nindakake, luwih kamungkinan bakal ana deadlock. Mulane, saben sampeyan nambahake blok sing disinkronake, sampeyan kudu mikir apa sampeyan pancene mbutuhake lan apa sampeyan bisa ngindhari nambahake sing anyar.
  • Nggunakake Thread.join() . Sampeyan uga bisa mbukak deadlock nalika siji thread ngenteni liyane. Kanggo supaya masalah iki, sampeyan bisa nimbang nyetel wektu entek kanggo gabung () cara.
  • Yen kita duwe siji thread, mula ora bakal ana deadlock;)

37. Apa kahanan lomba?

Yen balapan nyata nglibatake mobil, banjur balapan ing multithreading kalebu benang. Nanging kenapa? : / Ana rong utas sing mlaku lan bisa ngakses obyek sing padha. Lan bisa uga nyoba nganyari status obyek sing dienggo bareng bebarengan. Kabeh wis jelas nganti saiki, ta? Utas sing dileksanakake salah siji secara harfiah ing podo karo (yen prosesor wis luwih saka siji inti) utawa sequentially, karo prosesor alokasi irisan-irisan wektu interleaved. Kita ora bisa ngatur proses kasebut. Iki tegese nalika siji thread maca data saka obyek, kita ora bisa njamin yen bakal duwe wektu kanggo ngganti obyek sadurunge sawetara thread liyane nglakoni. Masalah kasebut muncul nalika kita duwe combo "mriksa lan tumindak". Apa tegese? Umpamane kita duwe pernyataan yen sing awak ngganti kondisi kasebut dhewe, contone:

int z = 0;

// Check
if (z < 5) {
// Act
   z = z + 5;
}
Loro utas bisa bebarengan ngetik blok kode iki nalika z isih nol lan banjur loro utas bisa ngganti nilai. Akibaté, kita ora bakal entuk nilai sing dikarepake 5. Nanging, kita bakal entuk 10. Kepiye carane sampeyan bisa ngindhari iki? Sampeyan kudu entuk kunci sadurunge mriksa lan tumindak, banjur uculake kunci kasebut. Sing, sampeyan kudu duwe thread pisanan ngetik blok yen , nindakake kabeh tumindak, ngganti z , lan mung banjur menehi thread sabanjuré kesempatan kanggo nindakake padha. Nanging utas sabanjure ora bakal mlebu blok yen , amarga z saiki bakal dadi 5:

// Acquire the lock for z
if (z < 5) {
   z = z + 5;
}
// Release z's lock
===================================================

Tinimbang kesimpulan

Aku pengin matur nuwun kanggo kabeh sing maca nganti pungkasan. Iku adoh banget, nanging sampeyan tahan! Mungkin kabeh ora jelas. Iki normal. Nalika aku sinau basa Jawa, aku ora bisa mbungkus otakku babagan variabel statis. Nanging ora masalah gedhe. Aku turu ing, maca sawetara sumber liyane, banjur pangerten teka. Nyiapake wawancara luwih minangka pitakonan akademik tinimbang pitakonan praktis. Akibaté, sadurunge saben wawancara, sampeyan kudu nyemak lan nyegerake ing memori bab-bab sing ora kerep digunakake.

Lan kaya biasane, ana sawetara tautan sing migunani:

Matur nuwun kabeh kanggo maca. Sampai jumpa :) Profil GitHubkuTop 50 pitakonan lan jawaban wawancara kerja kanggo Java Core.  Bagean 2 - 5
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION