สวัสดี! คุณเชี่ยวชาญการสร้างคลาสของคุณเองด้วยฟิลด์และวิธีการแล้ว วันนี้เราจะมาพูดถึงรายละเอียดเกี่ยวกับวิธีการต่างๆ แน่นอนว่าเราทำสิ่งนี้มากกว่าหนึ่งครั้งในการบรรยายของเรา แต่เราพูดถึงประเด็นทั่วไปเป็นหลัก วันนี้เราจะวิเคราะห์วิธีการ "เป็นบางส่วน" อย่างแท้จริง - เราจะค้นหาว่าประกอบด้วยอะไรบ้าง มีตัวเลือกใดบ้างสำหรับการสร้างและวิธีการจัดการทั้งหมดนี้ :) ไปกันเลย!
ลายเซ็นวิธีการ
รหัสทั้งหมดที่อธิบายวิธีการเรียกว่าการประกาศวิธีการ ลายเซ็นวิธีการประกอบด้วยชื่อวิธีการและประเภทพารามิเตอร์ตามลำดับเฉพาะ ลักษณะทั่วไปของโฆษณาสามารถอธิบายได้ดังต่อไปนี้:модификатор доступа, тип возвращаемого значения, 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. ส่งคืนค่า
ถ้าเมธอดของเราต้องคืนค่าบางอย่าง เราก็จะระบุประเภทของค่าที่ส่งคืน สิ่งนี้สามารถเห็นได้ในตัวอย่างของ gettergetName()
:
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()
- มีสองบรรทัด เป็นเวอร์ชันของเมธอดนี้ที่จะถูกประมวลผลทุกครั้งที่มีการเรียกใช้เมธอด
GO TO FULL VERSION