안녕하세요! 지난 수업에서 우리는 클래스와 생성자에 대해 알게 되었고 우리 자신을 만드는 방법을 배웠습니다. 오늘 우리는 수업의 필수적인 부분인 Java 메소드에 대해 더 잘 알게 될 것입니다. Java의 메서드는 프로그램에서 특정 작업을 수행할 수 있도록 하는 명령 집합입니다. 즉, 메서드는 함수입니다. 클래스가 할 수 있는 것. 다른 프로그래밍 언어에서는 메소드를 종종 "함수"라고 부르지만 Java에서는 "메소드"라는 단어가 더 일반적입니다. :) 기억하시겠지만, 지난 수업에서 Cat 클래스 에 대한 간단한 메서드를 만들어서 고양이가 야옹하고 점프할 수 있도록 했습니다.
public class Cat {
String name;
int age;
public void sayMeow() {
System.out.println("Meow!");
}
public void jump() {
System.out.println("Pounce!");
}
public static void main(String[] args) {
Cat smudge = new Cat();
smudge.age = 3;
smudge.name = "Smudge";
smudge.sayMeow();
smudge.jump();
}
}
sayMeow() 및 jump()는 우리 클래스의 메서드입니다. 이러한 메서드를 실행하면 다음과 같은 콘솔 출력이 생성됩니다.
Meow!
Pounce!
우리의 방법은 매우 간단합니다. 단순히 콘솔에 텍스트를 출력합니다. 그러나 Java에서 메서드는 중요한 작업이 있습니다. 객체의 데이터에 대한 작업을 수행합니다. 개체의 데이터를 변경하고 변환하고 표시하고 다른 작업을 수행합니다. 우리의 현재 메서드는 Cat 개체의 데이터 로 아무 작업도 수행하지 않습니다 . 좀 더 예시적인 예를 살펴보겠습니다.
public class Truck {
int length;
int width;
int height;
int weight;
public int getVolume() {
int volume = length * width * height;
return volume;
}
}
예를 들어 여기에 Truck 을 나타내는 클래스가 있습니다 . 세미 트럭에는 길이, 너비, 높이 및 무게가 있습니다(나중에 필요함). getVolume() 메서드 에서 객체의 데이터를 부피를 나타내는 숫자(길이, 너비 및 높이를 곱함)로 변환하여 계산을 수행합니다. 이 숫자는 메서드의 결과입니다. 메서드의 선언은 public int getVolume 으로 작성됩니다 . 즉, 이 메서드는 int 를 반환해야 합니다 . 메서드의 반환 값을 계산했으며 이제 메서드를 호출한 프로그램에 반환해야 합니다. Java에서 메서드의 결과를 반환하려면 return 키워드를 사용합니다. 반환 볼륨;
자바 메소드 매개변수
메서드를 호출할 때 "인수"라는 값을 메서드에 전달할 수 있습니다. 메소드의 선언에는 메소드가 허용할 수 있는 변수의 유형과 순서를 알려주는 변수 목록이 포함됩니다. 이 목록을 "메소드 매개변수"라고 합니다. Truck 클래스 의 getVolume() 메서드는 현재 매개변수를 정의하지 않으므로 트럭 예제를 확장해 보겠습니다. BridgeOfficer 라는 새 클래스를 만듭니다 . 이것은 교량에서 근무하는 경찰관으로, 통과하는 모든 트럭이 허용 중량을 초과하는지 확인합니다.
public class BridgeOfficer {
int maxWeight;
public BridgeOfficer(int normalWeight) {
this.maxWeight = normalWeight;
}
public boolean checkTruck(Truck truck) {
if (truck.weight > maxWeight) {
return false;
} else {
return true;
}
}
}
checkTruck 메서드는 Truck 개체 라는 하나의 인수를 받아들이고 경찰관 이 트럭이 다리에 진입하도록 허용할지 여부를 결정합니다. 메서드 내부의 논리는 간단합니다. 트럭의 무게가 허용된 최대값을 초과하면 메서드는 false 를 반환합니다 . 다른 길을 찾아야 합니다 :( 가중치가 최대값 이하이면 통과할 수 있으며 메서드는 true를 반환합니다.. "return" 또는 "the method returns a value"라는 문구를 아직 완전히 이해하지 못했다면 프로그래밍을 잠시 중단하고 실생활의 간단한 예를 사용하여 고려하십시오. :) 당신이 아프고 며칠 동안 일을 하지 않고 집에 있다고 가정해 봅시다. 병가는 지불해야 하기 때문에 의사의 진단서를 가지고 회계 부서에 갑니다. 이 상황을 방법과 비교하면 회계사는 paySickLeave ()방법. 이 방법에 대한 인수로 의사의 진단서를 전달합니다(이 방법이 없으면 방법이 작동하지 않으며 급여를 받을 수 없습니다!). 그런 다음 귀하의 메모를 사용하여 방법 내에서 필요한 계산이 이루어지고(회계사는 이를 사용하여 회사가 귀하에게 지불해야 하는 금액을 계산합니다) 귀하의 작업 결과(금액)가 귀하에게 반환됩니다. 우리 프로그램은 비슷한 방식으로 작동합니다. 메서드를 호출하고 데이터를 전달하고 궁극적으로 결과를 받습니다. BridgeOfficer 프로그램의 main() 메서드는 다음과 같습니다 .
public static void main(String[] args) {
Truck first = new Truck();
first.weight = 10000;
Truck second = new Truck();
second.weight = 20000;
BridgeOfficer officer = new BridgeOfficer(15000);
System.out.println("Truck 1! Can I go, officer?");
boolean canFirstTruckGo = officer.checkTruck(first);
System.out.println(canFirstTruckGo);
System.out.println();
System.out.println("Truck 2! And can I?");
boolean canSecondTruckGo = officer.checkTruck(second);
System.out.println(canSecondTruckGo);
}
우리는 10,000과 20,000의 적재량을 가진 두 대의 트럭을 만듭니다. 그리고 장교가 일하는 다리의 최대 무게는 15,000입니다. 프로그램은 officer.checkTruck(first) 메소드를 호출합니다. 메서드는 모든 것을 계산한 다음 true 를 반환하고 프로그램은 이를 부울 변수 canFirstTruckGo 에 저장합니다 . 이제 회계사가 준 돈으로 원하는 대로 할 수 있습니다. 하루가 끝나면 코드
boolean canFirstTruckGo = officer.checkTruck(first);
로 종기
boolean canFirstTruckGo = true;
여기에 매우 중요한 점이 있습니다. return 문은 메서드의 반환 값을 반환할 뿐만 아니라 메서드 실행을 중지합니다! return 문 뒤에 오는 코드는 실행되지 않습니다!
public boolean checkTruck(Truck truck) {
if (truck.weight > maxWeight) {
return false;
System.out.println("Turn around, you're overweight!");
} else {
return true;
System.out.println("Everything looks good, go ahead!");
}
}
메서드가 이미 결과를 반환하고 종료되었기 때문에 담당자의 설명은 표시되지 않습니다! 프로그램은 메서드가 호출된 위치로 돌아갑니다. 이것을 주시할 필요는 없습니다. Java 컴파일러는 return 문 다음에 코드를 작성하려고 할 때 오류를 생성할 만큼 똑똑합니다.
어벤져스: 파라미터 워
여러 방법으로 메서드를 호출해야 하는 상황이 있습니다. 우리 자신의 인공 지능을 만들어 보지 않겠습니까? Amazon에는 Alexa가 있고 Apple에는 Siri가 있습니다. 그렇다면 우리는 왜 그것을 가지면 안 됩니까? :) 영화 아이언맨에서 토니 스타크는 자신만의 놀라운 인공 지능인 자비스를 만듭니다. 그 멋진 캐릭터에게 경의를 표하고 그의 이름을 기리기 위해 우리 AI의 이름을 지정합시다. :) 가장 먼저 해야 할 일은 Jarvis에게 방에 들어오는 사람들에게 인사하는 법을 가르치는 것입니다.
public class Jarvis {
public void sayHi(String name) {
System.out.println("Good evening, " + name + ". How are you?");
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Tony Stark");
}
}
콘솔 출력:
Good evening, Tony Stark. How are you?
매우 좋은! 자비스는 이제 손님을 맞이할 수 있습니다. 물론, 그의 주인인 토니 스타크가 가장 자주 있을 것입니다. 하지만 그가 혼자 오지 않는다면 어떨까요! 우리의 sayHi() 메서드는 하나의 인수만 허용합니다. 따라서 방에 들어오는 한 사람에게만 인사할 수 있고 다른 사람은 무시합니다. 매우 예의 바르지 않습니까? 동의하지 않습니까? :/
자바 메소드 오버로딩
이 경우 이름은 같지만 매개 변수가 다른 두 가지 메서드를 작성하여 문제를 해결할 수 있습니다.
public class Jarvis {
public void sayHi(String firstGuest) {
System.out.println("Good evening, " + firstGuest + ". How are you?");
}
public void sayHi(String firstGuest, String secondGuest) {
System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
}
}
이를 메서드 오버로딩이라고 합니다. 메서드 오버로딩을 통해 프로그램이 더 유연해지고 다양한 작업 방식을 수용할 수 있습니다. 작동 방식을 검토해 보겠습니다.
public class Jarvis {
public void sayHi(String firstGuest) {
System.out.println("Good evening, " + firstGuest + ". How are you?");
}
public void sayHi(String firstGuest, String secondGuest) {
System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Tony Stark");
jarvis.sayHi("Tony Stark", "Captain America");
}
}
콘솔 출력:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
훌륭합니다. 두 버전 모두 작동했습니다. :) 그러나 우리는 문제를 해결하지 못했습니다! 손님이 3명이라면? 물론 세 개의 게스트 이름을 허용하도록 sayHi() 메서드를 다시 오버로드할 수 있습니다. 하지만 4개 또는 5개가 있을 수 있습니다. 무한대까지. sayHi() 메서드를 백만 번 오버로드하지 않고 자비스에게 이름을 처리하도록 가르치는 더 좋은 방법이 없을까요 ? :/ 물론 있습니다! 그렇지 않다면 Java가 세계에서 가장 인기 있는 프로그래밍 언어가 될 것이라고 생각하십니까? ;)
public void sayHi(String...names) {
for (String name: names) {
System.out.println("Good evening, " + name + ". How are you?");
}
}
( String... names )가 매개변수로 사용되면 문자열 모음이 메서드에 전달됨을 나타냅니다. 얼마나 많은지 미리 지정할 필요가 없으므로 이제 방법이 훨씬 더 유연해졌습니다.
public class Jarvis {
public void sayHi(String...names) {
for (String name: names) {
System.out.println("Good evening, " + name + ". How are you?");
}
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
}
}
콘솔 출력:
Good evening, Tony Stark. How are you?
Good evening, Captain America. How are you?
Good evening, Black Widow. How are you?
Good evening, Hulk. How are you?
여기에 있는 일부 코드는 익숙하지 않을 수 있지만 걱정하지 마십시오. 핵심은 간단합니다. 방법은 각 이름을 차례로 가져와 각 손님을 맞이합니다! 또한 전달된 문자열 수에 관계없이 작동합니다! 2명, 10명, 심지어 1000명까지 - 이 방법은 손님의 수에 관계없이 적절하게 작동합니다. 모든 가능성에 대해 방법을 오버로드하는 것보다 훨씬 편리하다고 생각하지 않습니까? :) 여기에 또 다른 중요한 점이 있습니다. 인수의 순서가 중요합니다! 메서드가 문자열과 숫자를 받는다고 가정해 보겠습니다.
public class Person {
public static void sayYourAge(String greeting, int age) {
System.out.println(greeting + " " + age);
}
public static void main(String[] args) {
sayYourAge("My age is ", 33);
sayYourAge(33, "My age is "); // Error!
}
}
Person 클래스의 sayYourAge 메소드가 문자열과 숫자를 입력으로 사용하는 경우 프로그램은 특정 순서로 이들을 전달해야 합니다! 다른 순서로 전달하면 컴파일러에서 오류가 발생하고 사용자는 자신의 나이를 말할 수 없습니다. 그건 그렇고, 지난 수업에서 다룬 생성자도 메서드입니다! 또한 그것들을 오버로드할 수 있으며(즉, 매개 변수 집합이 다른 여러 생성자를 생성) 전달된 인수의 순서도 근본적으로 중요합니다. 그들은 실제 방법입니다! :)
매개변수에 대해 다시 한 번
예, 죄송합니다. 아직 완료하지 않았습니다. :) 지금 공부할 주제는 매우 중요합니다. 향후 모든 인터뷰에서 이에 대해 질문을 받을 확률이 90%입니다! 메서드에 인수를 전달하는 방법에 대해 이야기해 봅시다. 간단한 예를 고려하십시오.
public class TimeMachine {
public void goToFuture(int currentYear) {
currentYear = currentYear+10;
}
public void goToPast(int currentYear) {
currentYear = currentYear-10;
}
public static void main(String[] args) {
TimeMachine timeMachine = new TimeMachine();
int currentYear = 2018;
System.out.println("What year is it?");
System.out.println(currentYear);
timeMachine.goToPast(currentYear);
System.out.println("How about now?");
System.out.println(currentYear);
}
}
타임머신에는 두 가지 방법이 있습니다. 둘 다 현재 연도를 나타내는 숫자를 입력으로 사용하고 그 값을 늘리거나 줄입니다(과거 또는 미래로 가고 싶은지 여부에 따라 다름). 그러나 콘솔 출력에서 볼 수 있듯이 이 방법은 작동하지 않습니다! 콘솔 출력:
What year is it?
2018
How about now?
2018
우리는 currentYear 변수를 goToPast() 메서드 에 전달했지만 그 값은 변경되지 않았습니다. 우리는 2018년에 있었고 여기에 머물렀습니다. 하지만 왜? :/ Java의 프리미티브는 값으로 메서드에 전달되기 때문입니다. 그게 무슨 뜻이야? goToPast() 메서드를 호출 하고 여기에 int 변수 currentYear(=2018)를 전달하면 이 메서드는 currentYear 변수 자체를 가져오는 것이 아니라 복사본을 가져옵니다. 물론 이 복사본의 값도 2018이지만 복사본에 대한 변경 사항은 원래 currentYear 변수에 어떤 식으로든 영향을 미치지 않습니다! 코드를 더 명확하게 만들고 currentYear에서 어떤 일이 발생하는지 살펴보겠습니다.
public class TimeMachine {
public void goToFuture(int currentYear) {
currentYear = currentYear+10;
}
public void goToPast(int currentYear) {
System.out.println("The goToPast method has started running!");
System.out.println("currentYear inside the goToPast method (at the beginning) = " + currentYear);
currentYear = currentYear-10;
System.out.println("currentYear inside the goToPast method (at the end) = " + currentYear);
}
public static void main(String[] args) {
TimeMachine timeMachine = new TimeMachine();
int currentYear = 2018;
System.out.println("What was the year when the program started?");
System.out.println(currentYear);
timeMachine.goToPast(currentYear);
System.out.println("And what year is it now?");
System.out.println(currentYear);
}
}
콘솔 출력:
What was the year when the program started?
2018
The goToPast method has started running!
currentYear inside the goToPast method (at the beginning) = 2018
currentYear inside the goToPast method (at the end) = 2008
And what year is it now?
2018
이는 goToPast() 메서드 에 전달된 변수가 currentYear 의 복사본일 뿐임을 명확하게 보여줍니다 . 사본을 변경해도 "원본" 값에는 영향을 미치지 않습니다. "참조로 전달"은 정반대를 의미합니다. 고양이에게 연습하자! 고양이 예제를 사용하여 참조로 전달하는 것이 어떻게 보이는지 봅시다. :)
public class Cat {
int age;
public Cat(int age) {
this.age = age;
}
}
이제 타임머신의 도움으로 세계 최초의 시간 여행 고양이인 Smudge를 과거와 미래로 보내드립니다 ! Cat 개체 와 함께 작동하도록 TimeMachine 클래스를 수정해 보겠습니다 .
public class TimeMachine {
public void goToFuture(Cat cat) {
cat.age += 10;
}
public void goToPast(Cat cat) {
cat.age -= 10;
}
}
이제 메서드는 전달된 숫자만 변경하지 않습니다. 오히려 특정 Cat 의 연령 필드를 변경합니다. 원래 숫자가 변경되지 않았기 때문에 프리미티브에는 이것이 작동하지 않았다는 것을 기억할 것입니다. 무슨 일이 일어날지 보자!
public static void main(String[] args) {
TimeMachine timeMachine = new TimeMachine();
Cat smudge = new Cat(5);
System.out.println("How old was Smudge when the program started?");
System.out.println(smudge.age);
timeMachine.goToFuture(smudge);
System.out.println("How about now?");
System.out.println(smudge.age);
System.out.println("Holy smokes! Smudge has aged 10 years! Back up quickly!");
timeMachine.goToPast(smudge);
System.out.println("Did it work? Have we returned the cat to its original age?");
System.out.println(smudge.age);
}
콘솔 출력:
How old was Smudge when the program started running?
5
How about now?
15
Holy smokes! Smudge has aged 10 years! Back up quickly!
Did it work? Have we returned the cat to its original age?
5
우와! 이제 그 방법은 뭔가 달랐습니다. 우리 고양이는 급격히 늙었지만 다시 젊어졌습니다! :) 그 이유를 알아봅시다. 프리미티브가 있는 예제와 달리 개체가 메서드에 전달될 때 참조로 전달됩니다. 원본 스머지 개체에 대한 참조가 changeAge() 메서드 에 전달되었습니다 . 따라서 메서드 내에서 smudge.age를 변경하면 객체가 저장된 동일한 메모리 영역을 참조하게 됩니다. 처음에 만든 것과 동일한 Smudge에 대한 참조입니다. 이것을 "참조에 의한 전달"이라고 합니다! 그러나 참조가 있는 모든 것이 그렇게 쉬운 것은 아닙니다. :) 예제를 변경해 봅시다.
public class TimeMachine {
public void goToFuture(Cat cat) {
cat = new Cat(cat.age);
cat.age += 10;
}
public void goToPast(Cat cat) {
cat = new Cat(cat.age);
cat.age -= 10;
}
public static void main(String[] args) {
TimeMachine timeMachine = new TimeMachine();
Cat smudge = new Cat(5);
System.out.println("How old was Smudge when the program started?");
System.out.println(smudge.age);
timeMachine.goToFuture(smudge);
System.out.println ("Smudge went to the future! Has his age changed?");
System.out.println(smudge.age);
System.out.println ("And if you try going back?");
timeMachine.goToPast(smudge);
System.out.println(smudge.age);
}
}
콘솔 출력:
How old was Smudge when the program started running?
5
Smudge went to the future! Has his age changed?
5
And if you try going back?
5
다시 작동하지 않습니다! О_О 무슨 일이 일어났는지 알아봅시다. :) goToPast / goToFuture 메서드 및 참조가 작동하는 방식과 관련 이 있습니다 . 자, 주목해주세요! 이것은 참조와 메서드가 작동하는 방식을 이해하는 데 가장 중요한 것입니다. 사실 우리가 goToFuture (Cat cat) 메서드를 호출할 때 전달되는 것은 참조 자체가 아니라 고양이 개체에 대한 참조의 복사본입니다. 따라서 메서드에 개체를 전달할 때 개체에 대한 두 개의 참조가 있습니다. 이것은 무슨 일이 일어나고 있는지 이해하는 데 매우 중요합니다. 이것이 바로 마지막 예에서 고양이의 나이가 변경되지 않은 이유입니다. 앞의 예에서 나이를 변경할 때 우리는 단순히 goToFuture() 에 전달된 참조를 취했습니다.메서드를 사용하여 메모리에서 개체를 찾고 나이를 변경하는 데 사용했습니다( cat.age += 10 ). 그러나 이제 goToFuture() 메서드 내에서 새 개체( cat = new Cat(cat.age) ) 를 만들고 이 개체에는 메서드에 전달된 것과 동일한 참조 복사본이 할당됩니다. 결과적으로:
- 첫 번째 참조( Cat smudge = new Cat (5) )는 원래 고양이(5세)를 가리킵니다.
- 그런 다음 cat 변수에 goToPast() 메서드를 전달 하고 새 개체를 할당하면 참조가 복사되었습니다.
cat.age += 10;
그리고 물론 main() 메서드에서 우리는 고양이의 나이 smudge.age 가 변경되지 않았음을 콘솔에서 볼 수 있습니다 . 결국, 스머지는 여전히 5년 된 이전의 원래 개체를 가리키는 참조 변수이며 해당 개체에 대해 아무 작업도 수행하지 않았습니다. 모든 연령 변경은 새 개체에서 수행되었습니다. 따라서 개체는 참조에 의해 메서드에 전달되는 것으로 나타났습니다. 개체의 복사본은 자동으로 생성되지 않습니다. 고양이 개체를 메서드에 전달하고 수명을 변경하면 수명도 변경됩니다. 그러나 참조 변수는 값을 할당하거나 메서드를 호출할 때 복사됩니다! 프리미티브 전달에 대해 말한 내용을 여기에서 반복해 보겠습니다. " changeInt() 메서드를 호출하고 int변수 x (=15) , 메서드는 x 변수 자체를 가져오는 것이 아니라 복사본을 가져옵니다. 따라서 사본에 대한 변경 사항은 원본 x 에 영향을 미치지 않습니다.Java에서 인수가 전달되는 방식에 대해 한 번 이상 논쟁하게 될 것입니다(숙련된 개발자 사이에서도). 그러나 이제 어떻게 작동하는지 정확히 알고 있습니다. 계속 하세요! :) 배운 내용을 보강하려면 Java 과정에서 비디오 강의를 시청하는 것이 좋습니다.
GO TO FULL VERSION