자바 메서드와 JVM의 메모리 구조에 대해 알아보자
2025. 2. 4. 13:00ㆍJAVA
728x90
반응형
안녕하세요. 진득코딩입니다.
지난 시간에 객체에 대해 배웠고 이 객체는 기능과 속성, 즉 멤버변수와 메서드로 이루어져 있는 것을 알아보았습니다.
이번 시간에는 맴버변수와 메서드에 대해 알아보고 JVM의 메모리 구조에 대해 알아보도록 하겠습니다.
선언위치에 따른 변수의 종류
- 변수는 클래스변수, 인스턴스변수, 지역변수 모두 세 종류가 있습니다.
- 변수의 종류를 결정짓는 중요한 요소는 변수의 선언된 위치입니다.
- 멤버변수를 제외한 나머지 변수들은 모두 지역변수입니다.
- 멤버변수 중 static이 붙은 것은 클래스변수, 붙지 않은 것은 인스턴스변수입니다.
변수의 종류 | 선언위치 | 생성시기 |
클래스변수 (class variable) |
클래스 영역 | 클래스가 메모리에 올라갈 때 |
인스턴스변수 (instance variable) |
인스턴스가 생성되었을 때 | |
지역변수 (local variable) |
클래스 영역 이외의 영역 (메서드, 생성자, 초기화 블럭 내부) |
변수 선언문이 수행되었을 때 |
- 인스턴스변수(instance variable)
- 클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어집니다.
- 인스턴스 변수의 값을 읽어 오거나 저장하기 위해서는 먼저 인스턴스를 생성해야 합니다.
- 인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있습니다. - 클래스변수(class variable)
- 클래스 변수를 선언하는 방법은 인스턴스변수 앞에 static을 붙이기만 하면 됩니다.
- 클래스변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 됩니다.
- 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야 하는 속성의 경우, 클래스변수로 선언해야 합니다.
- 클래스 변수는 인스턴스를 생성하지 않고도 언제라도 바로 사용할 수 있다는 특징이 있습니다. - 지역변수(local variable)
- 메서드 내에 선언되어 메서드 내에서만 사용 가능합니다.
- 메서드가 종료되면 소멸되어 사용할 수 없게 됩니다.
클래스변수와 인스턴스변수
- Card인스턴스는 자신만의 무늬(kind)와 숫자(number)를 유지하고 있어야 하므로 이들을 인스턴스변수로 선언하였습니다.
- 카드의 폭(width)과 높이(height)는 모든 인스턴스가 공통적으로 같은 값을 유지해야 하므로 클래스변수로 선언하였습니다.
- Card클래스의 클래스변수(static변수)인 width, height는 Card클래스의 인스턴스를 생성하지 않고도 '클래스이름.클래스변수'와 같은 방식으로 사용할 수 있습니다.
- Card인스턴스인 c1과 c2는 클래스변수인 width와 height를 공유하기 때문에, c1의 width와 height를 변경하면 c2의 width와 height값도 바뀐 것과 같은 결과를 얻습니다.
- 클래스변수를 사용할 때는 Card.width와 같이 '클래스이름.클래스변수'의 형태로 하는 것이 좋습니다.
- 참조변수 c1, c2를 통해서도 클래스변수를 사용할 수 있지만 이렇게 하면 클래스변수를 인스턴스변수로 오해하기 쉽기 때문입니다.
인스턴스변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.
메서드
- 메서드(method)는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것입니다.
- 메서드는 입력값 또는 출력값(결과값)이 없을 수도 있으며, 심지어 입력값과 출력값 모두 없을 수도 있습니다.
- 그저 메서드가 작업을 수행하는데 필요한 값만 넣고 원하는 결과만 얻으면 될 뿐, 이 메서드가 내부적으로 어떤 과정을 거쳐 결과를 만들어내는지 전혀 몰라도 됩니다.
- 그래서 메서드가 내부가 보이지 않는 블랙박스(black box)라고도 합니다.
메서드를 사용하는 이유
- 높은 재사용성(reusability)
- 한번 만들어 놓은 메서드는 몇 번이고 호출할 수 있으며, 다른 프로그램에서도 사용이 가능합니다. - 중복된 코드의 제거
- 반복되는 문장들 대신 메서드를 호출하는 한 문장으로 대체할 수 있습니다.
- 반복적으로 나타나는 문장들을 메서드로 만들어서 사용하면 코드의 중복이 제거됩니다.
- 또한 변경사항이 발생했을 때 이 메서드만 수정하면 되므로 관리도 쉽고 오류의 발생가능성도 낮아집니다. - 프로그램의 구조화
- 큰 규모의 프로그램에서는 문장들을 작업단위로 나눠서 여러 개의 메서드에 담아 프로그램의 구조를 단순화시키는 것이 필수적입니다.
- main메서드는 프로그램의 전체 흐름이 한눈에 들어올 정도로 단순하게 구조화하는 것이 좋습니다.
메서드의 선언과 구현
- 메서드는 크게 '선언부(header, 머리)'와 '구현부(body, 몸통)'로 이루어져 있습니다.
- 메서드를 정의한다는 것은 선언부와 구현부를 작성하는 것을 뜻합니다.
메서드 선언부(method declaration, method header)
- 메서드 선언부는 메서드의 이름, 매개변수 선어, 그리고 반환타입으로 구성되어 있습니다.
- 예를 들어 아래와 같이 정의된 메서드 add는 두 개의 정수를 입력받아서, 두 값을 더한 결과(int타입의 값)를 반환합니다.
매개변수 선언(parameter declaration)
- 매개변수는 메서드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것입니다.
- 각 변수 간의 구분은 쉼표 ','를 사용합니다.
- 두 변수의 타입이 같아도 변수의 타입을 생략할 수 없습니다.
- 만일 입력해야할 값의 개수가 많은 경우에는 배열이나 참조변수를 사용하면 됩니다.
- 값을 전혀 입력받을 필요가 없다면 괄호( ) 안에 아무것도 적지 않습니다.
메서드의 이름(method name)
- 메서드의 이름은 동사인 경우가 많으며 이름만으로도 메서드의 기능을 쉽게 알 수 있도록 함축적인 이름을 짓는 것이 좋습니다.
반환타입(return type)
- 메서드의 작업수행 결과(출력)인 '반환값(return value)'의 타입을 적습니다.
- 반환값이 없는 경우 반환타입으로 'void'를 적어야 합니다.
메서드의 구현부(method body, 메서드 몸통)
- 메서드의 선언부 다음에 오는 괄호 { }를 '메서드의 구현부'라고 하는데, 여기에 메서드를 호출했을 때 수행될 문장들을 넣습니다.
return문
- 'void'가 아닌 경우, 구현부 { }안에 'return 반환값;'이 반드시 포함되어 있어야 합니다.
- 이 값의 타입은 반환타입과 일치하거나 적어도 자동 형변환이 가능한 것이어야 합니다.
- return문은 출력(반환값)은 최대 하나만 허용합니다.
- return문은 저장된 값을 호출한 메서드로 반환합니다.
지역변수(local variable)
- 서로 다른 메서드라면 같은 이름의 변수를 선언해도 됩니다.
- '지역변수(local variable)'란 메서드 내에 선언된 변수를 의미합니다.
- 다른 메서드에 각기 선언된 변수는 이름만 같을 뿐 서로 다른 변수입니다.
메서드의 호출
- 메서드를 호출해야만 구현부 { }의 문장들이 수행됩니다.
메서드이름(값1, 값2, ...); //메서드를 호출하는 방법
print99danAll(); // void print99danAll()을 호출
int result = add(3, 5); // int add(int x, int y)를 호출하고, 결과를 result에 저장
인자(argument)와 매개변수(parameter)
- 메서드를 호출할 때 괄호( )안에 지정해 준 값들을 '인자(argument)' 또는 '인수'라고 합니다.
- 인자의 개수와 순서는 호출된 메서드에 선언된 매개변수와 일치해야 합니다.
- 인자의 타입은 매개변수의 타입과 일치하거나 자동 형변환이 가능한 것이어야 합니다.
메서드의 실행흐름
- 같은 클래스 내의 메서드끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없습니다.
- 메서드가 호출되면 지금까지 실행 중이던 메서드는 실행을 잠시 멈추고 호출된 메서드의 문장들이 실행됩니다.
- 호출된 메서드의 작업이 모두 끝나면, 다시 호출한 메서드로 돌아와 이후의 문장들을 실행합니다.
- 메서드는 호출시 넘겨받은 값으로 연산을 수행하고 그 결과를 반환하면서 종료됩니다.
- 사칙연산을 위한 4개의 메서드가 정의되어 있는 MyMath클래스를 이용한 예제입니다.
- divide메서드에 선언된 매개변수 타입은 double형인데, 이와 다른 long형의 값인 5L과 3L을 사용해서 호출하는 것이 가능합니다.
return문
- return문은 현재 실행 중인 메서드를 종료하고 호출한 메서드로 되돌아갑니다.
- 원래는 반환값의 유무에 관계없이 모든 메서드에는 적어도 하나의 return문이 있어야 합니다.
- 이때 반환타입이 void인 경우, return문 없이도 아무런 문제가 없었던 이유는 컴파일러가 메서드의 마지막에 'return;'을 자동적으로 추가해 주었기 때문입니다.
- 반환타입이 void가 아닌 경우, 즉 반환값이 있는 경우, 반드시 return문이 있어야 합니다.
반환값(return value)
- return문의 반환값으로 주로 변수가 오긴 하지만 항상 그런 것은 아닙니다.
- 수식도 반환값으로 지정할 수 있는데 이 경우 수식을 계산한 결과가 반환됩니다.
- 간단한 메서드의 경우 if문 대신 조건 연산자를 사용하기도 합니다.
매개변수의 유효성 검사
- 메서드의 구현부 { }를 작성할 때, 제일 먼저 해야 하는 일이 매개변수의 값이 적절한 것인지 확인하는 것입니다.
- 적절하지 않은 값이 매개변수를 통해 넘어온다면 매개변수의 값을 보정하던가, 보정하는 것이 불가능하다면 return문을 사용해서 작업을 중단하고 호출한 메서드로 되돌아가야 합니다.
- 메서드를 작성할 때는 매개변수의 유효성 검사하는 코드를 반드시 넣어야 합니다.
JVM의 메모리 구조
- 응용프로그램이 실행되면, JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리합니다.
- 그중 3가지 주요 영역(method area, call stack, heap)에 대해 알아보도록 하겠습니다.
- 메서드 영역(method area)
- 클래스에 대한 정보(클래스 데이터)를 이곳에 저장합니다.
- 그 클래스의 클래스변수(class variable)도 이 영역에 함께 생성됩니다. - 힙(heap)
- 인스턴스가 생성되는 공간입니다.
- 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성됩니다.
- 즉, 인스턴스변수(instance variable)들이 생성되는 공간입니다. - 호출스택(call stack 또는 execution stack)
- 호출스택은 메서드의 작업에 필요한 메모리 공간을 제공합니다.
- 메서드가 호출되면, 호출스택에 호출된 메서드를 위한 메모리가 할당됩니다.
- 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 비워집니다.
- 각 메서드를 위한 메모리상의 작업공간은 서로 구별됩니다.
- 첫 번째로 호출된 메서드를 위한 작업공간이 호출스택의 맨 밑에 마련되고, 첫 번째 메서드 수행 중에 다른 메서드를 호출하면, 첫 번째 메서드의 바로 위에 두 번째로 호출된 메서드를 위한 공간이 마련됩니다.
- 호툴스택의 제일 상위에 위치하는 메서드는 현재 실행 중인 메서드이며, 나머지는 대기상태에 있게 됩니다.
- 호출 스택을 살펴보도록 하겠습니다.
- 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다.
- 메서드가 수행을 마치고 나면 사용했던 메모리를 반환하고 스택에서 제거됩니다.
- 호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드입니다.
- 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드입니다.
- 반환타입(retun type)이 있는 메서드는 종료되면서 결과값을 자신을 호출한 메서드(caller)에게 반환합니다.
- 대기상태에 있던 호출한 메서드(caller)는 넘겨받은 반환값으로 수행을 계속 진행하게 됩니다.
- main()이 firtstMethod()를 호출하고 firstMethod()는 secondMethod()를 호출합니다.
- 객체를 생성하지 않고도 메서드를 호출할 수 있으려면, 메서드 앞에 'static'을 붙여야 합니다.
- 각 메서드의 시작과 종료의 순서를 확인하는 예제입니다.
- 호출 스택의 구조를 알 수 있습니다.
이번 시간에는 메서드와 JVM의 메모리 구조에 대해 살펴보았습니다.
이렇게 객체지향 파트에 들어와서 여러 부분에 대해 배우면 배울수록 점점 더 자바와 친해지는 느낌이 듭니다.
이번 시간에 배운 메서드와 JVM의 메모리 구조를 잘 파악하여 자바를 100% 활용하여 좋은 프로그램을 만들면 좋을 것 같습니다.
이번 시간은 여기까지입니다.
궁금하신 사항이나 문의하실 사항이 있다면 댓글로 남겨주세요.
끝까지 봐주셔서 감사합니다.😊
728x90
반응형
LIST
'JAVA' 카테고리의 다른 글
자바 오버로딩(overloading)에 대해 알아보자 (0) | 2025.02.06 |
---|---|
자바 매개변수와 메서드와 재귀 호출에 대해 알아보자 (0) | 2025.02.05 |
객체지향언어 자바의 객체와 클래스를 알아보자 (0) | 2025.02.03 |
자바 다차원 배열과 가변 배열에 대해 알아보자 (2) | 2025.01.31 |
자바 String 배열에 대해 알아보자 (0) | 2025.01.30 |