public class VendingMachine {
// Field : 자판기가 가지는 것(동전통, 상품 케이스...)
// 생성자
// 메소드: 자판기가 가지는 기능
}
VendingMachineMain 클래스
main 메소드를 가진다.
VendingMachineMain 클래스에서 main 메소드를 작성하고 VendingMachine 인스턴스를 생성한다.
static main 메소드 -> 클래스 메소드
인스턴스를 사용하지 않아도 사용 가능(메모리에 있어야 함)하다.
다시 말해, 클래스 메소드는 인스턴스를 생성하지 않아도 메모리에 저장되어 있다.
폰 노이만(Von Neumann)의 프로그램 내장 방식이란, 모든 프로그램은 메모리에 올라 가야지만 실행될 수 있다.
public class VendingMachineMain {
public static void main(String[] args) {
// VendingMachine 클래스를 사용하고 싶다
// VendingMachine -> 자판기만 메모리에 생성한 것
VendingMachine vm1 = new VendingMachine();
VendingMachine vm2 = new VendingMachine();
}
}
main 메소드 동작
VendingMachine 클래스가 필요하다.
왜? 해당 클래스가 main 메소드 안에서 사용되고 있으니까
VendingMachineMain은 VendingMachine 클래스에 의존한다.
main 메소드 안에는 String 클래스도 사용되고 있다.
VendingMachineMain은 String 클래스에도 의존한다.
static한 메소드는 인스턴스를 생성하지 않아도 호출할 수 있다.
VendingMachine.printVersion();
위의 코드가 오류가 발생하지 않는다면, printVersion() 메소드는 static한 메소드이다.
클래스명.메소드명();
또한 static 메소드는
레퍼런스변수명.static메소드();
위의 코드도 오류가 발생하지 않고 실행된다.
하지만 관례는 ❌
public String pushProductButton(int menuId) {
System.out.println(menuId + "을 전달 받았습니다.");
return "콜라";
}
String product = vm1.pushProductButton(100);
System.out.println(product);
public static void printVersion() {
System.out.println("v1.0");
}
VendingMachine.printVersion();
VendingMachine vm1 = new VendingMachine();
VendingMachine vm2 = new VendingMachine();
위의 코드가 실행되면 Heap 메모리에 2개의 인스턴스가 올라간다.
javac VendingMachineMain.java
javac VendingMachine.java // 클래스가 2개이므로 컴파일도 2개 해줘야한다.
실행할 땐, main 메소드를 가지고 있는 VendingMachineMain을 실행한다.
java VendingMachineMain -> CLASSPATH에서 VendingMachineMain 클래스를 찾게된다.
자바 명령은 JVM이 실행한다.
-> JVM이 VendingMachineMain을 실행한다.
JVM이 클래스를 실행하려면 일단 클래스를 찾아야 한다.
JVM은 CLASSPATH 경로에서 클래스를 찾아서 실행한다.
CLASSPATH.이라고 잡혀있다고 생각하자. 점(.)은 현재 경로가 CLASSPATH 경로에 잡혀있으니까,java Hello는 현재 경로에서 JVM이 Hello 클래스를 찾아서 실행해주는 것이다.
찾았으면 VendingMachineMain 클래스를 JVM은 읽어들이고 읽어들인 클래스 정보를 PERM이라는 메모리 영역에 저장한다.
❗ 인스턴스가 아니라, 클래스 자체에 대한 정보가 PERM 영역에 올라간다.
클래스 정보가 PERM 영역에 올라가게 되면, JVM은 해당 클래스가 어떤 static 메소드를 가지고 있는지, 인스턴스 메소드를 가지고 있는지 모두 알게 된다.
그리고 나서 JVM은 프로그램 시작점인 main 메소드를 찾고 실행한다.
메소드가 실행되면 Java Stack 메모리 영역에 실행된 메소드 정보가 올라간다.
`Java Stck` 에 저장된 메소드 실행 정보 하나 -> 스택 엔트리(Stack Entry)
main 메소드 안에 선언된 변수들은 `스택 엔트리`에 저장된다. -> 로컬(local) 변수
main 메소드가 실행되면 Heap 메모리에 String배열 인스턴스가 만들어지고 이 인스턴스를 args변수가 참조한다.
스택 엔트리는 프로그램 카운트라고 해서 몇 번째 줄을 실행하고 있는 지 정보도 기억하고 있다. 다음 줄을 실행할 때마다 프로그램 카운트는 증가한다.
JVM이 VendingMachine.printVersion(); 만나면 printVersion() 메소드는 static 메소드이므로 실행 가능하다고 판단하고 실행해준다.
-> 실행되면 Java Stack에 스택 엔트리가 하나 더 추가된다. printVersion() 메소드 안에서 선언된 변수들은 스택 엔트리에 생성된다.
printVersion() 메소드가 실행 후에 종료가 되면 해당 메소드의 실행 정보를 담고 있는 스택 엔트리는 Java Stack에서 제거된다.
그리고 나서 main 메소드의 printVersion()을 호출한 그 다음 줄을 실행한다.
VendingMachine vm1 = new VendingMachine();
VendingMachine vm2 = new VendingMachine();
위의 코드가 실행되면서 인스턴스가 생성된다.-> VendingMachine 인스턴스를 스택엔트리의 vm1 변수가 참조한다.
2번 째 VedingMachine 인스턴스도 Heap 메모리에 생성되고 스택 엔트리의 vm2 변수가 참조한다.
다음의 메소드가 호출된다.
vm1.pushProductButton(100);
pushProductButton() 메소드가 호출되면서 Java Stack에 스택 엔트리가 생성되고, pushProductButton() 메소드에 선언된 변수 menuId가 스택 엔트리에 생성된다.
pushProductButton() 메소드가 실행되면서 menuId를 출력하고 "콜라" 문자열을 리턴한다.
이 메소드가 종료되면서Java Stack에서 제거되고 pushProductButton() 메소드가 리턴한 값을 product에 저장하고 출력한다.
Java Stack에서 제거된다.Java Stack에는 더 이상 남아있는 스택 엔트리가 없게 된다.메소드 안에 선언된 변수 -> 지역 변수
지역 변수는 메소드가 호출되면 생성하고, 종료되면 사라진다.
같은 메소드를 동시에 열 번을 호출 -> 그 메소드 안의 지역 변수는 각각 다른 영역에 저장되어 사용된다. 그러므로 동시에 메소드가 호출되어도 문제 없다.