JavaRush /จาวาบล็อก /Random-TH /การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java ตอนท...
Константин
ระดับ

การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java ตอนที่ 4

เผยแพร่ในกลุ่ม
สวัสดีทุกคน วันนี้ฉันจะมาวิเคราะห์ คำถามสัมภาษณ์ มากกว่า 250 ข้อสำหรับ Java Developer ต่อไป การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 1ส่วนก่อนหน้าของการวิเคราะห์: อันดับแรก , ที่สอง , ที่สาม งั้นมาทำต่อเลย

29. เป็นไปได้ไหมที่จะใช้ return ในตัวสร้าง?

คุณสามารถ ทำได้แต่ไม่มีค่าส่งคืนทางด้านขวาของreturn นั่นคือคุณสามารถใช้return; เป็นการก่อสร้างเสริมระหว่างการคำนวณในตัวสร้างเพื่อที่จะเสร็จสิ้นการดำเนินการโค้ดเพิ่มเติมอย่างเร่งด่วน (ขัดจังหวะ) และดำเนินการเริ่มต้นของวัตถุให้เสร็จสิ้น ตัวอย่างเช่น เรามีคลาสCatและหากCatไม่มีที่อยู่อาศัย - isHomeless = trueเราจำเป็นต้องเริ่มต้นการกำหนดค่าให้เสร็จสิ้นและไม่กรอกข้อมูลในฟิลด์อื่น ๆ (เพราะเราไม่รู้จักพวกมันเนื่องจากแมวไม่มีที่อยู่อาศัย):
public Cat(int age, String name, boolean isHomeless) {
   if (isHomeless){
       this.isHomeless = isHomeless;
       return;
   }
   this.isHomeless = isHomeless;
   this.age = age;
   this.name = name;
}
แต่เมื่อพูดถึงค่าเฉพาะ Constructor ไม่สามารถใช้ return เพื่อคืนค่าได้เนื่องจาก:
  • เมื่อประกาศ Constructor คุณจะไม่มีอะไรที่คล้ายกับประเภทการคืนสินค้า
  • โดยทั่วไปแล้ว ตัวสร้างจะถูกเรียกโดยปริยายในระหว่างการสร้างอินสแตนซ์
  • Constructor ไม่ใช่วิธีการ แต่เป็นกลไกที่แยกจากกันซึ่งมีวัตถุประสงค์เพียงอย่างเดียวในการเริ่มต้นตัวแปรอินสแตนซ์ และผู้ ปฏิบัติงาน ใหม่ มีหน้าที่รับผิดชอบในการสร้างวัตถุ
การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 2

30. เป็นไปได้ไหมที่จะโยนข้อยกเว้นจากตัวสร้าง?

ตัวสร้างจัดการกับข้อยกเว้นในลักษณะเดียวกับวิธีการทุกประการ และหากเมธอดอนุญาตให้เราโยนข้อยกเว้นโดยการเขียน<ExceptionType> ในส่วนหัว ของเมธอด Constructor จะอนุญาตให้เราทำสิ่งนี้ได้ และเมื่อสืบทอดและกำหนด Constructor ที่สืบทอดมา เราก็สามารถขยายประเภทข้อยกเว้นได้ ตัวอย่างเช่น IOException -> ข้อยกเว้น (แต่ไม่ใช่ในทางกลับกัน) เพื่อเป็นตัวอย่างในการส่งข้อยกเว้นโดย Constructor ลองใช้ คลาส Catกัน สมมติว่าเมื่อสร้างมันขึ้นมาเราต้องการป้อนชื่อและอายุจากคอนโซล:
public Cat() throws IOException {
   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   this.name = reader.readLine();
   this.age = Integer.parseInt(reader.readLine());
}
เนื่องจากreader.readLine()ส่ง IOException เราจึงระบุในส่วนหัวว่าเป็นข้อยกเว้นที่เป็นไปได้

31. ส่วนหัวของคลาสประกอบด้วยองค์ประกอบใดบ้าง? เขียนตัวอย่าง

เมื่อพูดถึงองค์ประกอบที่ประกอบเป็นส่วนหัวของคลาส ลองดูแผนภาพเล็กๆ กัน:
  • ส่วนประกอบบังคับจะอยู่ในวงเล็บ <>
  • ทางเลือก - ใน {}
{ตัวแก้ไขการเข้าถึงคลาส} คลาสคงที่ {คลาสสุดท้าย} คลาสนามธรรม} <ชื่อคลาส>{สืบทอดจากคลาสผู้ปกครอง} {การนำอินเทอร์เฟซไปใช้} ดังนั้นสิ่งที่เรามี: {class access modifier} - เฉพาะตัวแก้ไข สาธารณะและตัวแก้ไขการเข้าถึงที่ขาดหายไป ซึ่งก็คือdefault เท่านั้นที่พร้อมใช้งาน สำหรับ คลาส {class static} - staticเป็นตัวดัดแปลงที่ระบุว่าคลาสนี้เป็นแบบคงที่ ใช้ได้กับคลาสภายในเท่านั้น (คลาสภายในคลาสอื่น) {class Finality} - ตามที่เราจำได้ นี่คือ ตัวแก้ไข ขั้นสุดท้ายโดยที่คลาสจะไม่สามารถสืบทอดได้ (ตัวอย่างจากกล่อง - String ) {class abstraction} - modifier - abstractซึ่งบ่งชี้ว่าคลาสนี้อาจมีวิธีการที่ไม่ได้ใช้งาน ตัวแก้ไขนี้ขัดแย้งกับ ตัวแก้ไข สุดท้ายนั่นคือมีเพียงตัวเดียวเท่านั้นที่สามารถอยู่ในส่วนหัวของคลาสได้ เนื่องจาก ตัวแก้ไข นามธรรมบอกเป็นนัยว่าคลาสที่กำหนดจะได้รับการสืบทอดและส่วนนามธรรมจะถูกนำไปใช้ และสุดท้ายบ่งชี้ว่านี่เป็นเวอร์ชันสุดท้าย (สุดท้าย) ของคลาส และไม่สามารถสืบทอดได้ จริงๆ แล้ว การใช้ตัวดัดแปลงทั้งสองพร้อมกันคงเป็นเรื่องไร้สาระ และคอมไพเลอร์จะไม่อนุญาตให้เราทำสิ่งนี้ <class>เป็นคีย์เวิร์ดที่จำเป็นซึ่งระบุการประกาศคลาส <ชื่อคลาส>เป็นชื่อคลาสแบบง่าย ซึ่งเป็นตัวระบุคลาส Java เฉพาะ ชื่อคลาสแบบเต็มประกอบด้วยชื่อแพ็กเกจแบบเต็ม + + ชื่อคลาสธรรมดา {การสืบทอดจากคลาสผู้ปกครอง} - การระบุคลาสพาเรนต์ (ถ้ามี) โดยใช้ คีย์เวิร์ด ขยาย ตัวอย่างเช่น .. ขยาย ParentClass {การใช้งานอินเทอร์เฟซ} - การระบุอินเทอร์เฟซที่คลาสนี้นำไปใช้ (ถ้ามี) โดยใช้ คำ หลักApplys ตัวอย่างเช่น: ... ใช้ FirstInterface, SecondInterface ... เอาล่ะ เป็นตัวอย่างของส่วนหัวของคลาส ให้พิจารณาส่วนหัวของ คลาส Lionซึ่งสืบทอดมาจากCatและใช้ อินเทอร์เฟซ WildAnimal :
public final class Lion extends Cat implements WildAnimal
การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 3

32. ส่วนหัวของ method ประกอบด้วยองค์ประกอบใดบ้าง? เขียนตัวอย่าง

อีกครั้ง เมื่อดูองค์ประกอบที่ประกอบเป็นส่วนหัวของวิธีการ ให้พิจารณาแผนภาพขนาดเล็กโดยที่:
  • ส่วนประกอบบังคับอยู่ในวงเล็บ <>
  • ทางเลือก - ใน {}
{ตัวแก้ไขการเข้าถึง} วิธีคงที่ {วิธีนามธรรม} วิธีสุดท้าย {ตัวแก้ไขการซิงโครไนซ์} { ตัวแก้ไขดั้งเดิม <ค่าส่งคืน <ชื่อวิธี> <(> {ข้อโต้แย้งของวิธี} <)> {ข้อยกเว้นที่ถูกโยน} {ตัวแก้ไขการเข้าถึง } — ตัวดัดแปลงการเข้าถึง ทั้งหมด ใช้งานได้สำหรับวิธีการ: public , protected , default , private {method static} - staticเป็นตัวดัดแปลงที่ระบุว่าวิธีนี้เป็นแบบคงที่ นั่นคือมันไม่ได้เชื่อมโยงกับวัตถุ แต่กับคลาส {method abstraction}เป็น ตัวแก้ไข นามธรรมซึ่งบ่งชี้ว่าไม่มีการนำไปใช้ (เนื้อหา) ของวิธีการ เพื่อการดำเนินการที่ถูกต้อง คุณต้องมี ตัวแก้ไข นามธรรมสำหรับคลาสที่มีการระบุเมธอดไว้ ด้วย เช่นเดียวกับในส่วนหัวของคลาส ตัวแก้ไขนี้ขัดแย้งกับ ตัวแก้ไข สุดท้ายแต่นอกเหนือจากนั้น ตัวแก้ไขนี้ยังขัดแย้งกับ ตัวแก้ไข แบบคงที่ ด้วย เนื่องจาก วิธีนามธรรมหมายถึงการแทนที่วิธีการในลูกหลาน และวิธีการแบบคงที่จะไม่ถูกแทนที่ {finality of the method} - สุดท้าย - ตัวดัดแปลงที่ระบุว่าวิธีนี้ไม่สามารถแทนที่ได้ {ตัวแก้ไขการซิงโครไนซ์} - ซิงโครไนซ์ - ตัวแก้ไขซึ่งหมายความว่าวิธีนี้ได้รับการปกป้องจากการเข้าถึงพร้อมกันจากเธรดที่แตกต่างกัน ถ้าวิธีการไม่คงที่ จะปิดบน mutex นี้ของออบเจ็กต์ ถ้าวิธีการเป็นแบบคงที่ มันจะปิดบน mutex ของคลาสปัจจุบัน {native modifier} - Native - ตัวดัดแปลงนี้บ่งชี้ว่าเมธอดนี้เขียนในภาษาการเขียนโปรแกรมอื่น <ค่าส่งคืน>คือประเภทของค่าที่เมธอดควรส่งคืน หากไม่ควรคืนสิ่งใดถือ เป็นโมฆะ <ชื่อวิธีการ>คือชื่อของวิธีการ ซึ่งเป็นตัวระบุในระบบ {method arguments}คืออาร์กิวเมนต์ (พารามิเตอร์) ที่เมธอดใช้: จำเป็นต่อการนำฟังก์ชันการทำงานไปใช้ {throwableExceptions} - ThrowsExceptionType - รายการข้อยกเว้นที่ตรวจสอบแล้วซึ่งเมธอดนี้สามารถส่งได้ และเพื่อเป็นตัวอย่างของส่วนหัวของ method ฉันจะให้สิ่งนี้:
public static void main(String[] args) throws IOException

33. สร้างคอนสตรัคเตอร์เริ่มต้นในวัตถุสืบทอดหากไม่ได้กำหนดไว้ในวัตถุฐาน (แต่มีการกำหนดคอนสตรัคเตอร์อื่นไว้)

ฉันไม่เข้าใจคำถามนั้นอย่างถ่องแท้ แต่บางทีมันอาจหมายความว่า ตัวอย่างเช่น ในพาเรนต์ เรามีตัวสร้างแบบกำหนดเอง:
public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
ดังนั้นในคลาส ancestor เราจำเป็นต้องกำหนด Constructor ที่จะเติม (เรียก) Constructor หลัก:
public  class Lion extends Cat {

   public Lion(int age, String name) {
       super(age, name);
   }
}
การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ส่วนที่ 4 - 4

34. คำสำคัญนี้ใช้เมื่อใด?

ในภาษา Java สิ่งนี้มีสองความหมายที่แตกต่างกัน 1. เพื่ออ้างอิงถึงวัตถุปัจจุบัน เช่นthis.age = 9 นั่นคือสิ่งนี้หมายถึงวัตถุที่ถูกเรียกและโค้ดที่ใช้สิ่งนี้ อ้างอิง ถึง หน้าที่หลักคือเพิ่มความสามารถในการอ่านโค้ดและหลีกเลี่ยงความคลุมเครือ ตัวอย่างเช่น ถ้าชื่อของฟิลด์คลาสภายในและอาร์กิวเมนต์ของเมธอดเหมือนกัน:
public void setName(String name) {
   this.name = name;
}
นั่นคือthis.nameเป็นเขตข้อมูลของ ชื่อ วัตถุ เป็นอาร์กิวเมนต์วิธีการ การอ้างอิงนี้ไม่สามารถใช้ในวิธีการแบบคงที่ 2. สิ่งนี้ สามารถใช้ในตัวสร้างในรูปแบบของการเรียก ใช้เมธอด เช่นthis(value) ในกรณีนี้ มันจะเป็นการเรียกไปยัง Constructor อื่นในคลาสเดียวกัน กล่าวโดยสรุป คุณสามารถเรียก Constructor สองตัวพร้อมกันเมื่อสร้าง Object:
public Cat(int age, String name) {
   this(name);
   this.age = age;
}

public Cat(String name) {
   this.name = name;
}
เมื่อ วัตถุ Cat ถูกสร้างขึ้น และเรียกใช้ตัวสร้างตัวแรก ทั้งสองฟิลด์ของวัตถุจะถูกเรียกและเริ่มต้นได้สำเร็จ มีความแตกต่างสองสามประการ:
  1. this()ใช้งานได้ในตัวสร้างเท่านั้น
  2. การอ้างอิงถึงตัวสร้างอื่นจะต้องอยู่ในบรรทัดแรกของบล็อกตัวสร้าง (เนื้อหา) ดังนั้น ไม่สามารถเรียกคอนสตรัคเตอร์ (อื่นๆ) มากกว่าหนึ่งตัวของคลาสที่กำหนดในตัวสร้างเดียวได้
การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 5ตัวอย่างเพิ่มเติมอยู่ในบทความนี้

35. ตัวเริ่มต้นคืออะไร?

เท่าที่ฉันเข้าใจ ในคำถามนี้ เรากำลังพูดถึงบล็อกการเริ่มต้นแบบธรรมดาและแบบสถิติ ก่อนอื่น เรามาจำไว้ว่าการเริ่มต้นคืออะไร การเริ่มต้นคือการสร้าง การเปิดใช้งาน การเตรียมงาน การกำหนดพารามิเตอร์ การนำโปรแกรมหรือส่วนประกอบเข้าสู่สภาวะพร้อมใช้งาน อย่างที่คุณจำได้ ในระหว่างการสร้างอ็อบเจ็กต์ ตัวแปรคลาสสามารถเริ่มต้นได้โดยตรงจากการประกาศ:
class Cat {
   private int age = 9;
   private  String name = "Tom";
หรือตั้งค่าภายนอกผ่านตัวสร้าง:
class Cat {
   private int age;
   private  String name;

   public Cat(int age, String name) {
       this.age = age;
       this.name = name;
   }
แต่มีวิธีอื่น: การตั้งค่าตัวแปรอ็อบเจ็กต์ภายในผ่านบล็อกการเริ่มต้น ซึ่งดูเหมือนวงเล็บปีกกา{ }ภายในคลาส โดยไม่มีชื่อ (เช่น วิธีการหรือตัวสร้าง):
class Cat {
   private int age;
   private  String name;

   {
       age = 10;
       name = "Tom";
   }
นั่นคือ บล็อกการเริ่มต้นคือโค้ดชิ้นหนึ่งที่ถูกโหลดเมื่อสร้างออบเจ็กต์ โดยทั่วไป บล็อกดังกล่าวจะใช้ในการคำนวณที่ซับซ้อนซึ่งจำเป็นเมื่อโหลดคลาส ผลลัพธ์ของการคำนวณเหล่านี้สามารถระบุเป็นค่าสำหรับตัวแปรได้ นอกจากนี้ นอกเหนือจากบล็อกการเริ่มต้นปกติแล้ว ยังมีบล็อกแบบคงที่ซึ่งมีลักษณะเหมือนกัน แต่มีคำหลัก แบบคงที่อยู่ข้างหน้าวงเล็บปีกกา:
class Cat {
   private static int age;
   private static String name;

   static{
       age = 10;
       name = "Tom";
   }
บล็อกนี้เหมือนกับบล็อกก่อนหน้าทุกประการ แต่หากวัตถุปกติถูกทริกเกอร์เมื่อแต่ละวัตถุถูกเตรียมใช้งาน วัตถุแบบคงที่จะทริกเกอร์เพียงครั้งเดียวเมื่อคลาสถูกโหลด ตามกฎแล้วในบล็อกดังกล่าว การคำนวณที่ซับซ้อนบางอย่างจะดำเนินการด้วยสำหรับการเริ่มต้นตัวแปรคลาสคงที่ในภายหลัง ข้อจำกัดเดียวกันนี้ใช้กับบล็อกแบบคงที่เช่นเดียวกับวิธี การแบบคงที่: ไม่สามารถใช้ข้อมูลที่ไม่คงที่ได้ เช่นเดียวกับการอ้างอิงถึงวัตถุปัจจุบัน - นี่ การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 6ต่อไป เราจะเห็นลำดับการเริ่มต้นของคลาส (ร่วมกับบรรพบุรุษ) เพื่อความเข้าใจที่ดีขึ้นเกี่ยวกับช่วงเวลาที่บล็อกการเริ่มต้นถูกทริกเกอร์

36. ในการสืบทอดคลาส public class Child ขยาย Parent ให้เขียนลำดับการเริ่มต้นของอ็อบเจ็กต์

เมื่อโหลดคลาส Child ลำดับการเริ่มต้นจะเป็นดังนี้:
  1. ฟิลด์คงที่ของคลาสParent
  2. บล็อกการเริ่มต้นแบบคง ที่สำหรับ คลาส Parent
  3. ฟิลด์คงที่ของคลาสChild
  4. บล็อกการเริ่มต้นแบบคง ที่สำหรับ คลาส Child
  5. ฟิลด์ที่ไม่คงที่ของคลาสParent
  6. ไม่ใช่บล็อกการเริ่มต้นแบบคงที่สำหรับคลาสParent
  7. ตัวสร้างสำหรับคลาสParent
  8. ฟิลด์ที่ไม่คงที่ของ คลาส Child
  9. ไม่ใช่บล็อกการเริ่มต้นแบบคงที่สำหรับคลาสChild
  10. ตัวสร้างคลาสChild
การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 7ต่อไปนี้เป็นบทความสั้นๆ ที่อธิบายลำดับการเริ่มต้นในทางปฏิบัติ

37. คุณรู้ความสัมพันธ์อะไรระหว่างคลาส (วัตถุ)?

ความสัมพันธ์ระหว่างคลาสใน Java มีสองประเภท:
  • IS-ความสัมพันธ์
หลักการ IS-A ใน OOP ขึ้นอยู่กับการสืบทอดคลาสหรือการใช้งานอินเทอร์เฟซ ตัวอย่างเช่น ถ้าคลาสLionสืบทอดมาจากCatเราจะบอกว่าLion is Cat :
Lion IS-A Cat
(แต่ไม่ใช่ทุกCat is a Lion ) สถานการณ์จะเหมือนกันทุกประการกับอินเทอร์เฟซ หาก คลาส Lionใช้ อินเทอร์เฟซ WildAnimalแสดงว่าพวกมันยังมีความสัมพันธ์กัน:
Lion IS-A WildAnimal
  • ความสัมพันธ์แบบมี-เอ
ความสัมพันธ์ประเภทนี้มีพื้นฐานมาจากการใช้คลาสโดยคลาสอื่น หรือที่เรียกว่า "การเชื่อมโยง" การเชื่อมโยงคือคลาสหนึ่งที่อ้างอิงถึงคลาสอื่น (หรือแม้แต่ระหว่างกัน) ตัวอย่างเช่น คลาส Carอาจหมายถึง คลาส Passengerและนี่จะเป็นความสัมพันธ์:
Car HAS-A Passenger
และในทางกลับกัน: หากPassengerมีการอ้างอิงถึงCarนี่จะเป็นความสัมพันธ์:
Passenger HAS-A Car

38. คุณรู้ความเชื่อมโยงระหว่างวัตถุอะไรบ้าง?

การรวมกลุ่มและการจัดองค์ประกอบไม่ใช่อะไรมากไปกว่าการรวมกลุ่มกรณีพิเศษ การรวมกลุ่มคือความสัมพันธ์ที่วัตถุหนึ่งเป็นส่วนหนึ่งของอีกวัตถุหนึ่ง ตัวอย่างเช่น ผู้โดยสารอาจอยู่ในรถยนต์ นอกจากนี้อาจมีผู้โดยสารหลายคนหรือไม่มีเลย (หากเรากำลังพูดถึง Tesla ก็ไม่จำเป็นต้องใช้คนขับ) ตัวอย่างเช่น:
public class Car {
   private List passengers = new ArrayList<>();

 void setPassenger(Passenger passenger) {
     passengers.add(passenger);
 }

   void move() {
       for (Passenger passenger : passengers) {
           System.out.println("Перевозка пассажира - " + passenger.toString());
       }
       passengers.clear();
   }
}
นั่นคือเราไม่สนใจจำนวนผู้โดยสาร (หรือว่ามีเลย): ฟังก์ชั่นของ คลาส Carไม่ได้ขึ้นอยู่กับสิ่งนี้ การรวมกลุ่มยังบอกเป็นนัยว่าเมื่อวัตถุถูกใช้โดยวัตถุอื่น วัตถุแรกสามารถนำไปใช้กับวัตถุอื่นได้ ตัวอย่างเช่น นักเรียนคนเดียวกันสามารถเป็นสมาชิกของทั้งชมรมถักนิตติ้งและกลุ่มดนตรีร็อค และในขณะเดียวกันก็ไปที่กลุ่มผู้เรียนภาษาอังกฤษ ดังที่คุณเข้าใจ การรวมกลุ่มคือความสัมพันธ์ที่หลวมกว่าระหว่างชั้นเรียน การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 8องค์ประกอบคือความสัมพันธ์ที่เข้มงวดยิ่งขึ้น เมื่อวัตถุไม่ได้เป็นเพียงส่วนหนึ่งของวัตถุอื่นเท่านั้น แต่งานของวัตถุอีกชิ้นนั้นขึ้นอยู่กับวัตถุชิ้นแรกเป็นอย่างมาก ยกตัวอย่างเครื่องยนต์ของรถยนต์ แม้ว่าเครื่องยนต์จะอยู่ได้โดยไม่มีรถยนต์ แต่ภายนอกเครื่องยนต์ก็ไม่มีประโยชน์ รถยนต์ไม่สามารถทำงานได้หากไม่มีเครื่องยนต์:
public class Car {
   private Engine engine;

   public Car(Engine engine) {
       this.engine = engine;
   }

   void startMoving() {
       engine.start();
           ...
   }
องค์ประกอบยังบอกเป็นนัยว่าเมื่อวัตถุถูกใช้โดยวัตถุอื่น วัตถุแรกไม่สามารถเป็นของบุคคลอื่นได้ หากเรากลับมาที่ตัวอย่างของเรา เครื่องยนต์สามารถเป็นของรถคันเดียวเท่านั้น แต่ไม่สามารถเป็นของสองคันขึ้นไปในเวลาเดียวกันได้ วันนี้เราคงจะหยุดที่นี่การวิเคราะห์คำถามและคำตอบจากการสัมภาษณ์นักพัฒนา Java  ตอนที่ 4 - 9
วัสดุอื่นๆ ในชุด:
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION