JavaRush /จาวาบล็อก /Random-TH /ลายเซ็นวิธีการ

ลายเซ็นวิธีการ

เผยแพร่ในกลุ่ม
สวัสดี! คุณเชี่ยวชาญการสร้างคลาสของคุณเองด้วยฟิลด์และวิธีการแล้ว วันนี้เราจะมาพูดถึงรายละเอียดเกี่ยวกับวิธีการต่างๆ แน่นอนว่าเราทำสิ่งนี้มากกว่าหนึ่งครั้งในการบรรยายของเรา แต่เราพูดถึงประเด็นทั่วไปเป็นหลัก วันนี้เราจะวิเคราะห์วิธีการ "เป็นบางส่วน" อย่างแท้จริง - เราจะค้นหาว่าประกอบด้วยอะไรบ้าง มีตัวเลือกใดบ้างสำหรับการสร้างและวิธีการจัดการทั้งหมดนี้ :) ไปกันเลย!ลายเซ็นวิธีการ - 1

ลายเซ็นวิธีการ

รหัสทั้งหมดที่อธิบายวิธีการเรียกว่าการประกาศวิธีการ ลายเซ็นวิธีการประกอบด้วยชื่อวิธีการและประเภทพารามิเตอร์ตามลำดับเฉพาะ ลักษณะทั่วไปของโฆษณาสามารถอธิบายได้ดังต่อไปนี้:
модификатор доступа, тип возвращаемого значения, Name метода(список параметров) {
    // тело метода
}
ลองมาดูตัวอย่างการประกาศวิธีการต่างๆ ของคลาสDogกัน
public class Dog {

   String name;

   public Dog(String name) {
       this.name = name;
   }

   public static void main(String[] args) {
       Dog max = new Dog("Max");
       max.woof();

   }

   public void woof() {
       System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
   }

   public void run(int meters) {
       System.out.println("Собака по имени " + name + " пробежала " + meters + " метров!");
   }

   public String getName() {
       return name;
   }
}

1. ตัวแก้ไขการเข้าถึง

ตัวแก้ไขการเข้าถึงจะแสดงรายการก่อนเสมอ วิธีการเรียนทั้งหมดDogถูกกำหนดโดยตัวpublicแก้ไข นั่นคือเราสามารถเรียกพวกมันจากคลาสอื่นได้:
public class Main {

   public static void main(String[] args) {

       Dog butch = new Dog("Бутч");
       butch.run(100);
   }

}
Dogอย่างที่คุณเห็น วิธีการเรียนในชั้นเรียนMainนั้น เข้าถึงได้ง่ายในชั้นเรียน สิ่งนี้เป็นไปได้ด้วยตัวpublicแก้ไข มีโมดิฟายเออร์อื่นๆ ใน Java และไม่ใช่ทั้งหมดที่จะอนุญาตให้คุณใช้เมธอดในคลาสอื่นได้ เราจะพูดถึงพวกเขาในการบรรยายอื่น ๆ สิ่งสำคัญคือการจำไว้ว่าตัวดัดแปลงนั้นรับผิดชอบอะไร: ความพร้อมใช้งาน/การเข้าไม่ถึงของวิธีการในคลาสอื่น :)

2. คำหลักแบบคงที่

หนึ่งในวิธีการDogกล่าวmain()คือ ถูกระบุโดยคำstaticหลัก หากมีอยู่แล้ว จะต้องระบุหลังตัวแก้ไขการเข้าถึง จำในการบรรยายครั้งก่อนๆ ที่เราพูดถึงเกี่ยวกับตัวแปรคลาสคงที่ได้ไหม เมื่อนำไปใช้กับวิธีการ คำนี้มีความหมายประมาณเดียวกัน หากระบุวิธีการเป็นstaticหมายความว่าสามารถใช้งานได้โดยไม่ต้องอ้างอิงถึงอ็อบเจ็กต์คลาสเฉพาะ และแท้จริงแล้ว ในการเรียกใช้เมธอดแบบสแตติกmain()ในคลาสDogคุณไม่จำเป็นต้องสร้างอินสแตนซ์Dogเพราะมันจะทำงานโดยไม่มีอินสแตนซ์ ถ้าวิธีนี้ไม่คงที่ ถ้าต้องการใช้มัน เราจะต้องสร้างอ็อบเจ็กต์ก่อน

3. ส่งคืนค่า

ถ้าเมธอดของเราต้องคืนค่าบางอย่าง เราก็จะระบุประเภทของค่าที่ส่งคืน สิ่งนี้สามารถเห็นได้ในตัวอย่างของ getter getName():
public String getName() {
   return name;
}
Stringมันส่งคืน วัตถุ ประเภท หากวิธีการไม่ส่งคืนสิ่งใดๆ คำหลักจะถูกระบุแทนประเภท ดังvoidเช่นในวิธีการwoof():
public void woof() {
   System.out.println("Собака по имени " + name + " говорит \"Гав-гав!\"");
}

วิธีการที่มีชื่อเดียวกัน

มีสถานการณ์ที่โปรแกรมของเราต้องการตัวเลือกมากมายเกี่ยวกับวิธีการทำงาน ทำไมเราไม่สร้างปัญญาประดิษฐ์ของเราเองล่ะ? Amazon มี Alexa, Yandex มี Alice แล้วทำไมเราถึงแย่กว่านี้ :) ในภาพยนตร์เรื่อง Iron Man โทนี่สตาร์กได้สร้างปัญญาประดิษฐ์ที่โดดเด่นของเขาเอง - JARVIS มาแสดงความเคารพต่อตัวละครที่ยอดเยี่ยมและตั้งชื่อ AI ของเราเพื่อเป็นเกียรติแก่เขา :) สิ่งแรกที่เราต้องสอนจาร์วิส - ทักทายผู้คนที่เข้ามาในห้อง (คงจะแปลกถ้าสติปัญญาที่ยอดเยี่ยมเช่นนี้กลับกลายเป็นว่าไม่สุภาพ)
public class Jarvis {

   public void sayHi(String name) {
       System.out.println("Good evening, " + name + ", How are you doing?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
   }
}
เอาต์พุตคอนโซล:

Добрый вечер, Тони Старк, How ваши дела?
ยอดเยี่ยม! จาร์วิสรู้วิธีทักทายคนที่เข้ามา แน่นอนว่ามักจะเป็นเจ้าของของเขา - โทนี่สตาร์ก แต่เขาอาจจะไม่มาคนเดียว! และวิธีการของเราsayHi()รับเพียงอาร์กิวเมนต์เดียวเป็นอินพุต ดังนั้นเขาจะสามารถทักทายได้เพียงคนเดียวจากผู้ที่มา และจะไม่สนใจอีกคนหนึ่ง ไม่สุภาพมากนัก เห็นด้วยไหม:/ ในกรณีนี้ เพื่อแก้ปัญหา เราสามารถเขียน 2 วิธีในคลาสที่มีชื่อเดียวกัน แต่มีพารามิเตอร์ต่างกัน:
public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Good evening, " + firstGuest + ", How are you doing?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Good evening, " + firstGuest + ", " + secondGuest + ", How are you doing?");
   }

}
สิ่งนี้เรียกว่าวิธีการโอเวอร์โหลด การโอเวอร์โหลดทำให้โปรแกรมของเรามีความยืดหยุ่นมากขึ้นและรองรับตัวเลือกการทำงานที่แตกต่างกัน ตรวจสอบวิธีการทำงาน:
public class Jarvis {

   public void sayHi(String firstGuest) {
       System.out.println("Good evening, " + firstGuest + ", How are you doing?");
   }

   public void sayHi(String firstGuest, String secondGuest) {
       System.out.println("Good evening, " + firstGuest + ", " + secondGuest + ", How are you doing?");
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
เอาต์พุตคอนโซล:

Добрый вечер, Тони Старк, How ваши дела? 
Добрый вечер, Тони Старк, Капитан Америка, How ваши дела?
เยี่ยมมาก ทั้งสองตัวเลือกใช้งานได้ :) อย่างไรก็ตาม เราไม่สามารถแก้ปัญหาได้! เกิดอะไรขึ้นถ้ามีแขกสามคน? แน่นอนว่าเราสามารถโอเวอร์โหลดวิธีการอีกครั้งsayHi()เพื่อรับชื่อแขกสามคนได้ แต่อาจมี 4 หรือ 5 อันก็ได้ และอื่นๆ ไม่มีที่สิ้นสุด มีวิธีอื่นในการสอนจาร์วิสให้ทำงานกับชื่อจำนวนเท่าใดก็ได้โดยไม่ต้องมีวิธีการเกินล้านวิธีsayHi()หรือไม่ :/ มีแน่นอน! ไม่เช่นนั้น Java จะเป็นภาษาโปรแกรมที่ได้รับความนิยมมากที่สุดในโลกหรือไม่? ;)
public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Good evening, " + name + ", How are you doing?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark");
       System.out.println();
       jarvis.sayHi("Tony Stark", "Captain America");
   }
}
บันทึก ( String...names) ที่ส่งผ่านเป็นพารามิเตอร์ช่วยให้เราสามารถระบุได้ว่ามีการส่งสตริงจำนวนหนึ่งไปยังเมธอด เราไม่ได้ระบุล่วงหน้าว่าควรมีจำนวนเท่าใด ดังนั้นการดำเนินการตามวิธีการของเราจึงมีความยืดหยุ่นมากขึ้น:
public class Jarvis {

   public void sayHi(String...names) {

       for (String name: names) {
           System.out.println("Good evening, " + name + ", How are you doing?");
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
   }
}
เอาต์พุตคอนโซล:

Добрый вечер, Тони Старк, How ваши дела? 
Добрый вечер, Капитан Америка, How ваши дела? 
Добрый вечер, Черная Вдова, How ваши дела? 
Добрый вечер, Халк, How ваши дела?
ภายในวิธีการนี้ เราจะวนซ้ำอาร์กิวเมนต์ทั้งหมดและส่งออกวลีสำเร็จรูปพร้อมชื่อไปยังคอนโซล ที่นี่เราใช้การวนซ้ำแบบง่ายfor-each(คุณพบแล้ว) เป็นเรื่องดีเพราะString...namesจริงๆ แล้วการเขียนหมายความว่าพารามิเตอร์ที่ส่งผ่านทั้งหมดจะถูกใส่ลงในอาร์เรย์โดยคอมไพเลอร์ ดังนั้น namesคุณสามารถทำงานกับตัวแปรได้เช่นเดียวกับอาร์เรย์ รวมถึงการวนซ้ำผ่านตัวแปรนั้นด้วย ยิ่งไปกว่านั้น มันจะใช้ได้กับสายที่โอนกี่สายก็ได้! สองสิบหรือพัน - วิธีการนี้จะใช้ได้กับแขกจำนวนเท่าใดก็ได้ สะดวกกว่าการโอเวอร์โหลดสำหรับตัวเลือกที่เป็นไปได้ทั้งหมดมาก คุณเห็นด้วยไหม :) เรามายกตัวอย่างวิธีการโอเวอร์โหลดอีกตัวอย่างหนึ่งกันดีกว่า มาเพิ่มวิธีการให้กับprintInfoFromDatabase()Jarvis มันจะพิมพ์ข้อมูลเกี่ยวกับบุคคลจากฐานข้อมูลไปยังคอนโซล หากฐานข้อมูลระบุว่าบุคคลนั้นเป็นซูเปอร์ฮีโร่หรือจอมวายร้าย ข้อมูลนี้จะปรากฏบนหน้าจอด้วย:
public class Jarvis {

   public  void printInfoFromDatabase (String bio) {

       System.out.println(bio);
   }

   public void printInfoFromDatabase(String bio, boolean isEvil, String nickname) {

       System.out.println(bio);
       if (!isEvil) {
           System.out.println("Также известен How супергерой " + nickname);
       } else {
           System.out.println("Также известен How суперзлодей " + nickname);
       }
   }

   public static void main(String[] args) {
       Jarvis jarvis = new Jarvis();
       jarvis.printInfoFromDatabase("Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington");
       System.out.println();
       jarvis.printInfoFromDatabase("Макс Эйзенхарт. Рост 188см, вес 86 кг.", true, "Магнето");
   }
}
บทสรุป:

Лора Палмер. Дата рождения - 22 июля 1972, город Твин Пикс, штат Washington
Макс Эйзенхарт. Рост 188см, вес 86 кг 
Также известен How суперзлодей Магнето
นี่คือวิธีการทำงานของเราขึ้นอยู่กับข้อมูลที่เราส่งเข้าไป อีกจุดสำคัญ:ลำดับการโต้แย้งก็สำคัญ! สมมติว่าวิธีการของเรารับสตริงและตัวเลขเป็นอินพุต:
public class Man {

   public static void sayYourAge(String greeting, int age) {
       System.out.println(greeting + " " + age);
   }

   public static void main(String[] args) {

       sayYourAge("My age - ", 33);
       sayYourAge(33, "My age - "); //error!
   }
}
หาก เมธอด sayYourAge()คลาสManรับสตริงและตัวเลขเป็นอินพุต แสดงว่านี่คือลำดับที่ต้องส่งผ่านในโปรแกรม! หากเราส่งผ่านตามลำดับอื่น คอมไพเลอร์จะส่งข้อผิดพลาดและบุคคลนั้นจะไม่สามารถบอกอายุของเขาได้ อย่างไรก็ตาม ตัวสร้างที่เรากล่าวถึงในการบรรยายครั้งล่าสุดก็เป็นวิธีการเช่นกัน! นอกจากนี้ยังสามารถโอเวอร์โหลดได้ (สร้างตัวสร้างหลายตัวด้วยชุดอาร์กิวเมนต์ที่แตกต่างกัน) และสำหรับพวกเขา ลำดับการส่งผ่านอาร์กิวเมนต์ก็มีความสำคัญขั้นพื้นฐานเช่นกัน วิธีการจริง! :)

วิธีเรียกเมธอดที่มีพารามิเตอร์คล้ายกัน

ดังที่คุณทราบใน Java มีคำดังกล่าวเป็นโมฆะ เมื่อทำงานกับมัน สิ่งสำคัญมากคือต้องเข้าใจว่า null ไม่ใช่ทั้งวัตถุหรือชนิดข้อมูล ลองนึกภาพเรามีคลาส Man และวิธีการintroduce()ที่ประกาศชื่อและอายุของบุคคล ในกรณีนี้ อายุสามารถสื่อถึงได้ในรูปแบบของข้อความหรืออาจแสดงเป็นตัวเลขก็ได้
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man sasha = new Man();
       sasha.introduce("Sasha", "двадцать один");

       Man masha = new Man();
       masha.introduce("Мария", 32);
   }
}
เราคุ้นเคยกับการโอเวอร์โหลดอยู่แล้ว ดังนั้นเราจึงรู้ว่าวิธีการนี้จะได้ผลตามที่คาดไว้ทั้งสองครั้ง:

Меня зовут Саша, мой возраст - двадцать один 
Меня зовут Мария, мой возраст - 32 
แต่จะเกิดอะไรขึ้นถ้าเราส่งค่า null เป็นพารามิเตอร์ตัวที่สอง ไม่ใช่สตริงหรือตัวเลข
public static void main(String[] args) {

   Man victor = new Man();
   victor.introduce("Виктор", null);//Ambiguous method call!
}
เราจะได้รับข้อผิดพลาดในการรวบรวม! ข้อผิดพลาด "การเรียกเมธอดคลุมเครือ" ถูกแปลเป็น "การเรียกเมธอดคลุมเครือ" เหตุใดจึงเกิดขึ้นได้และ "ความคลุมเครือ" คืออะไร? จริงๆแล้วมันง่าย ประเด็นคือ เรามีเมธอดสองแบบ: with Stringและ with Integerเป็นอาร์กิวเมนต์ที่สอง แต่ทั้งสองStringและIntegerอาจเป็นโมฆะได้! สำหรับทั้งสองประเภท (เนื่องจากเป็นประเภทอ้างอิง) ค่า null จึงเป็นค่าเริ่มต้น นั่นคือสาเหตุที่คอมไพเลอร์ในสถานการณ์นี้ไม่สามารถระบุได้ว่าควรเรียกใช้เมธอดเวอร์ชันใด การแก้ปัญหานี้ค่อนข้างง่าย ประเด็นก็คือว่า null สามารถแปลงเป็นประเภทการอ้างอิงเฉพาะได้อย่างชัดเจน ดังนั้นเมื่อเรียกเมธอด คุณสามารถระบุประเภทข้อมูลที่คุณต้องการสำหรับอาร์กิวเมนต์ที่สองในวงเล็บได้! คอมไพเลอร์จะเข้าใจ "คำใบ้" ของคุณและเรียกวิธีการที่ต้องการ:
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, Integer age) {
       System.out.println("Метод со строкой и числом!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", (String) null);
   }
}
บทสรุป:

Метод с двумя строками! 
Меня зовут Виктор, мой возраст - null
แต่ถ้าพารามิเตอร์ตัวเลขเป็นค่าดั้งเดิมintและไม่ใช่ออบเจ็กต์ประเภทการอ้างอิงIntegerข้อผิดพลาดดังกล่าวจะไม่เกิดขึ้น
public class Man {

   public void introduce(String name, String age) {
       System.out.println("Метод с двумя строками!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public void introduce(String name, int age) {
       System.out.println("Метод со строкой и числом!!");
       System.out.println("Меня зовут " + name + ", мой возраст - " + age);
   }

   public static void main(String[] args) {

       Man victor = new Man();
       victor.introduce("Виктор", null);
   }
}
คุณเดาได้ไหมว่าทำไม? ถ้าคุณเดาได้ก็ทำได้ดี :) เพราะพื้นฐานไม่สามารถเท่ากับโมฆะได้ ตอนนี้คอมไพเลอร์มีเพียงตัวเลือกเดียวในการเรียกเมธอดintroduce()- มีสองบรรทัด เป็นเวอร์ชันของเมธอดนี้ที่จะถูกประมวลผลทุกครั้งที่มีการเรียกใช้เมธอด
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION