[Java] 객체지향 프로그래밍(oop) - 변수와 메서드

SolChan Kim·2023년 11월 27일

📖선언위치에 따른 변수의 종류

변수의 선언위치에따라 변수의 종류가 나뉘어진다.

즉, 변수가 어디에 선언되었는가에 따라 변수의 종류와 범위(scope)가 결정되는 것이다.
범위 : 변수가 유효한 범위(변수를 사용할 수 있는 범위)를 말한다.

변수의 선언위치에 따라 결정되는 변수의 종류는 클래스변수, 인스턴스변수, 지역변수다.

class Variables{
	// 인스턴스 변수
	int instanceVariable;
    
    // 클래스변수(static 변수, 공유가능한 변수)
    static int staticVariable; 
    
    // 메서드(method)
    puvlic void method{
    	// 메서드 영역(method Area)
        
        // 지역 변수(local Variable)
    	int localVariable = 0;
    }
}

클래스(class)or스태틱(static)변수(variable)

  • 클래스의 구성요소(멤버)라서 멤버변수라고 부른다.

  • 같은 클래스의 모든 인스턴스들이 공유하는 변수다.

  • 클래스가 메모리에 올라갈 때 자동으로 생성되기 때문에,
    인스턴스 변수와 다르게, 인스턴스를 생성하지 않고 바로 사용이 가능하다.

    • 프로그램이 종료되면 클래스 변수는 소멸
  • 클래스 변수를 선언하는 방법 : stiatc + 인스턴스변수

  • 클래스 변수 접근 방법 : 클래스이름.클래스변수명


인스턴스변수(instance variable)

  • 클래스 구성요소(멤버)리서 멤버변수라고 부른다.

  • 인스턴스를 생성할 때 만들어지기 때문에 인스턴스 변수의 값을 읽어 오거나
    저장하려면 먼저 인스턴스를 생성해야 한다.

  • 각 인스턴스의 개별적인 저장공간을 가지고 있어서 인스턴스마다 다른 값을 저장할 수 있다.

  • 인스턴스 변수 접근 방법 : 참조변수명.인스턴스 변수명

  • 인스턴스를 생성할 때 인스턴스 변수가 생성되고, 인스턴스를 참조하는 참조변수가 없을 때
    가비지 컬렉터에 의해서 자동으로 제거된다.


지역변수(local variable)

  • 메서드 영역에서 선언되며, 메서드가 종료되면 지역변수도 소멸한다.

    • 조건문, 반복문의 블럭{}내에 선언된 지역변수들은 블럭을 벗어나면 소멸한다.
  • 지역변수에는 static을 붙일 수 없다.


📖클래스 변수와 인스턴스 변수

인스턴스변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있다.

클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로 항상 공통된 값만을 갖는다.

Class Car{
	// 자동차 브랜드 명(회사명) : 클래스 변수
	static String brandName = JavaCar;
    
    // 자동차 이름, 색상, 가격 : 인스턴스 변수
    String name, color, price;
}

자동차 클래스를 분석해보면 자동차 클래스에 정의될 수 있는 속성에는
브랜드 이름, 차 이름, 색상, 가격 등의 속성이 있을 수 있다.

이 중에서 차 이름, 색상, 가격은 자동차 종류마다 가져야 하는 고유의 값이지만
브랜드 명은 모든 자동차가 가져야하는 공통적인 속성이기 때문에

자동차 이름, 색상, 가격은 인스턴스변수로 선언하고 브랜드명은 static을 붙여서 클래스변수로 선언해야 한다.
-> 하나의 자동차 회사(브랜드)에서 생산되는 자동차들의 브랜드명이 각각 달라져서는 안되기 때문이다.


예제

1. CarTest클래스의 main메서드가 호출되면서 프로그램이 시작된다.


2. Car클래스의 인스턴스를 생성하기 위해 먼저 Car클래스가 메모리에 로드된다, 이 때, Car클래스의 클래스변수인 BrandName이 메모리에 생성되고 "Java"란 값으로 초기화된다.


3. Car인스턴스가 생성되고, 멤버변수인 name, color, price가 기본값인 null로 초기화된다. 그리고 생성된 인스턴스의 주소가 car01에 저장된다.


4. car01.name = "car01", car01.color = "red", car01.price = "500만원"으로 값을 변경한다.


5. 새로운 Car인스턴스가 생성되고, 멤버변수인 name, color, price가 기본값인 null로 초기화된다. 그리고 생성된 인스턴스의 주소가 car02에 저장된다.


6. car02.name = "car02", car02.color = "blue", car02.price = "1000만원"으로 값을 변경한다.


7. car01, car02의 값을 화면에 출력한다.


🤔클래스 변수의 접근 방법은 "클래스명.클래스 변수명"이었다. 그런데 접근 방법을 "참조변수명.클래스 변수명"으로 변경해도 문제가 발생하지 않는 이유는 무엇일까?

// System.out.println("Brand : " + Car.brandName);
System.out.println("Brand : " + car01.brandName);
  • 모든 인스턴스는 자신을 생성한 클래스의 주소를 가지고 있기 때문이다.
    • Car클래스 주소 : 0xbbbb
    • car01, car02가 참조하고 있는 인스턴스가 가지고 있는 클래스 주소 : Car클래스 주소

📖메서드(Method)

메서드란?

  • 작업을 수행하기 위한 명령문들을 묶어 놓은 것

  • 메서드는 함수, function과 같은 의미인데 객체지향언어에서는 보통 메서드라고 부른다.

  • 메서드는 일반적으로 어떤 값을 입력받아서 작업하고 그 결과를 돌려준다.

    • 덧셈을 하는 메서드는 더할 숫자를 입력받아서 더한 다음 그 결과를 돌려준다.
    • 메서드가 수행하는 작업에 따라 입력값이나 결과값이 없을 수도 있다.

메서드의 장점과 작성지침

  • 반복적인 코드를 줄이고 코드의 관리가 용이하다.

    • 동일한 작업을 하는 코드를 여러 곳에 반복해서 넣는 것보다
      코드들을 메서드에 넣고 호출하도록 변경하면 코드도 간결해지고
      나중에 코드에 변경사항이 생겨도 한 곳에서 관리가 되기 때문에 변경이 쉽다.
  • 하나의 메서드가 하나의 작업을 수행하도록 작성하는 것이 재사용하기에 좋다.

  • 여러 번 반복해서 사용되지 않는 코드라도 주요 작업단위로 묶어서
    메서드로 만들어 놓으면 프로그램의 전체적인 흐름이 간결하게 정리된다.


메서드를 정의하는 방법

  • 메서드는 클래스 영역에서만 정의할 수 있다.

  • 메서드 내에서는 또다른 메서드를 정의할 수 없다.

메서드를 정의하는 방법인데요. 메서드는 클래스 영역에만 정의할 수 있고요. 메서드 내에 메서드를 정의할 수 없다.


메서드의 선언부와 구현부

  • 메서드는 크게 선언부와 구현부 두 부분으로 나뉜다.

  • 선언부 : 메서드의 이름과 리턴타입 매개변수를 정의하는 곳

    • 선언부의 괄호에는 메서드가 수행되는데 필요한 입력값을 받아올 변수를 선언한다.
      입력값이 없는 경우 빈활호만 적으면 된다.
  • 구현부 : 메서드가 호출되었을 때 실제로 수행되는 코드를 적는 곳

int add(int num1, int num2){
	int result = num1 + num2;
    // 호출한 메서드로 결과를 반환한다.
    return result; 
}

// 반환값이 없는 경우 리턴타입 대신 void를 사용한다.
public void speedUp(){
	speed++;
}

add메서드는 두 개의 값을 받아서 더한 다음 그 결과를 반환하는 메서드다.

add메서드를 호출할 때, 두 개의 값 num1와 num2를 입력받아서 더한 결과를
변수 result에 담아서 반환한다.

return문은 메서드의 수행결과를 호출한 곳으로 반환한다.

add메서드에 사용된 변수 num1, num2, result는 선언된 곳이 모두
메서드 내에서 선언되었으므로 모두 지역변수이고 메서드가 종료되면 자동으로 소멸한다.

메서드 이름앞에 int는 반환하는 값의 타입을 적어주는 것이다.

만일 반환값이 없을 때는 speedUp메서드처럼 void라고 적어주면 된다.
-> void는 '비어있다’는 의미로 반환값이 없음을 뜻한다.


📖return문

메서드가 정상적으로 종료되는 경우

  • 메서드의 문장들을 수행하고 더이상 수행할 코드가 없는 경우

    • 메서드의 블럭{}의 끝에 도달했을 경우
  • 수행중에 return문을 만났을 경우

    • 메서드의 블럭{}을 수행 도중 return문을 만났을 경우

return문

  • 메서드 내에서만 사용할 수 있는 문장으로 현재 실행중인 메서드를 종료하고
    호출한 곳으로 되돌아간다.

반환값이 없는 메서드일 경우

  • return문만 써주면 된다.
return;

반환값이 있는 경우

  • return문 뒤에 반환값을 같이 써줘야 한다.
    • 반환값은 메서드에 정의된 반환 타입과 일치하거나 자동변환이 가능한 것이어야 한다.
return 반환값;

return문의 주의사항

  • 반환값이 있는 메서드는 반드시 모든 경우에 결과값을 반환하도록 해야한다.
int max(int a, int b){
	// a > b면
	if(a > b){
    	// a값 반환
    	return a;
    // b가 a보다 크면 
    }else{
    	// b값 반환
    	return b;
    }
}
  • 하나의 메서드 내에서 return문의 개수는 최소화 하는 것이 좋다.
int max(int a, int b){
	int result = 0;
    
    // a가 b보다 크면 
    if(a > b){
    	// result = a;
    	result = a;
    // b가 a보다 크면    
    }else{
    	// result = b;
    	result = b;
    }
    // result값 반횐
    return result;
}

📖메서드 호출

메서드 호출방법

  • 참조변수.메서드 이름(); : 메서드에 선언된 매개변수가 없는 경우

  • 참조변수.메서드 이름(값1, 값2...); : 메서드에 선언된 매개변수가 있는 경우

public class Math {
	public int add(int a, int b) {
		int result = a + b;
		return result;
	}
	
	public static void main(String[] args) {
		Math math = new Math();
		
		int value = math.add(1, 2);
	}
}
  • add메서드가 정의되어 있을 때 이 메서드를 호출하기 위해서는
    먼저 add메서드가 정의되어 있는 Math클래스의 인스턴스를 생성한 다음에
    참조변수(math)를 통해 add메서드를 호출하면 된다.

  • add메서드는 입력값으로 int타입의 변수a, b를 선언했으므로
    호출할 때는 두 개의 int타입의 값을 제공해야한다.(math.add(1, 2))

  • 호출할 때 제공된 값은 메서드의 매개변수a, b에 복사되고
    이 값들을 이용해서 작업을 한다.public int add(int a(1), int b(2))

  • 작업이 끝나면 결과값인 result가 메서드를 호출한 곳으로 반환되어
    변수 value에 저장된다.(int value = 3)

이처럼 결과값이 있는 메서드를 호출하는 경우에는
메서드를 호출한 결과를 저장할 변수가 필요하다.
-> 메서드만 호출해서는 아무런 결과도 얻을 수 없다.

결과값을 저장할 변수 value 역시 add메서드의 리턴타입인 int로 지정해야 한다.

여기서 add메서드를 호출할 때 입력값으로 1과 2를 지정했으니까
1과 2는 각각 변수 a와 b에 저장된다.

변수 result에는 a + b의 결과인 3이 저장된다.

그 다음 return문에 의해서 result에 저장된 값 3이 호출한 곳으로 반환되어
변수 value에 add메서드의 호출결과인 3이 저장된다.


📖기본형 매개변수와 참조형 매개변수

  • 기본형 매개변수 : 변수의 값을 읽기만 할 수 있다.(read only)

    • 기본형타입의 변수는 저장된 값을 복사하는 것이기 때문에
      그 값이 어디서 온건지 알 수 없다.
  • 참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다.(read & write)

    • 참조형타입의 변수는 값이 저장되어 있는 곳의
      주소값을 복사하는 것이기 때문에 값이 저장된 위치를 알 수 있다.

예시 : 기본형 매개변수

1. ParameterTest클래스가 메모리에 로드되고, ParameterTest클래스의 main메서드가 호출되면서 프로그램이 시작된다.


2. Data클래스가 메모리에 로드되고, Data타입의 참조변수 d가 main메서드의 지역변수로 생성된다. Data클래스의 인스턴스가 생성되고, 생성된 인스턴스의 주소가 참조변수 d에 저장된다.


3. Data인스턴스의 멤버변수 x의 값 10을 저장하고, println메서드를 호출해서 d.x의 값을 출력한다.(println메서드 출력 내용 생략)


4. change메서드를 호출하면서 매개변수로 참조변수 d가 가리키고 있는 인스턴스의 멤버변수 x(d.x)의 값을 넘겨준다. d.x의 값인 10이 change메서드의 매개변수(x)에 복사된다.


5. change메서드의 지역변수 x에 1000을 저장한다. c의 값이 10에서 1000으로 변경된다.


6. println메서드를 호출하여 x의 값을 출력한다. x의 값인 1000이 출력된다.


7. change메서드의 수행이 끝났으므로 change메서드가 사용하던 공간은 호출스택에서 제거되고 다시 main메서드로 돌아가 change메서드를 호출한 다음 문장이 수행된다.


8. println메서드를 호출하여 d.x의 값을 출력한다. d.x의 값은 10이므로 "main() x " 10"을 출력한다.


9. println메서드의 수행이 끝났으로 println메서드가 사용하던 공간은 호출스택에서 제거되고 다시 main메서드로 돌아간다. main메서드에서도 더이상 수행할 문장이 없기 때문에 호출스택에서 main메서드가 사용하던 공간이 제거되고 프로그램이 종료된다.


예시 : 참조형 매개변수

1. ParameterTest2클래스가 메모리에 로드되고, ParameterTest2클래스의 main메서드가 호출면서 프로그램이 시작된다.


2. Data클래스가 메모리에 로드되고, Data타입의 참조변수d가 main메서드의 지역변수로 생성된다. Data클래스의 인스턴스가 생성되고, 생성된 인스턴스의 주소가 참조변수 d에 저장된다.


3. d.x에 10을 저장하고, println메서드를 호출해서 d.x의 값을 출력한다.(출력 내용 : main() x : 10)


4. change메서드를 호출하면서 매개변수로 참조변수 d를 넘겨준다. main메서드의 참조변수 d의 값(Data인스턴스 주소)을 change메서드의 매개변수 d에 복사된다.


5. 매개변수로 받은 d(참조변수)에 멤버변수 x의 값을 1000으로 변경하고, println메서드를 호출해서 d.x의 값을 출력한다.(d는 참조변수기 때문에 참조하고 있는 인스턴스의 클래스 타입인 Data클래스에 멤버변수 x에 값이 1000으로 변한다. 메서드 호출내용 : change() x : 1000)


6. println메서드가 종료되어 호출스택에서 제거되고, println메서드를 호출한 change메서드로 돌아간다. change메서드도 더이상 수행할 문장이 없기 때문에 호출스택에서 제거된다. change메서드를 호출한 main메서드로 돌아간 다음 남은 문장을 수행한다.

  • println메서드 호출(호출내용 : After change(d))

    • println메서드 호출스택에서 제거
  • println메서드 호출(호출내용 : main() x : 1000)

    • println메서드 호출스택에서 제거
  • main메서드에서 더이상 수행할 문장이 없으므로 main메서드 호출스택에서 제거, 프로그램 종료


📖클래스 메서드(static메서드)와 인스턴스 메서드

  • 클래스변수, 인스턴스 변수가 있는 것처럼 메서드에도
    클래스메서드, 인스턴스 메서드가 있다.

클래스 메서드

  • 대표적인 메서드 : main메서드

  • 인스턴스 생성없이 클래스이름.메서드이름()으로 호출 가능하다.

  • 인스턴스 변수(객체변수)나 인스턴스메서드와 관련없는 작업을 하는 메서드다.

  • 메서드 내에서 인스턴스 변수를 사용할 수 없다.

  • 메서드 내에서 인스턴스변수를 사용하지 않는다면 static을 붙이는
    것을 고려한다.


인스턴스메서드

  • 인스턴스 생성 후 참조변수.메서드이름()으로 호출

  • 인스턴스 변수나 인스턴스 메서드와 관련된 작업을 하는 메서드

  • 메서드 내에서 인스턴스 변수 사용 가능


클래스메서드와 인스턴스메서드의 사용방법과 차이 이해

public class MyMath {
	long a, b;
	
	// 인스턴스 메서드
	public long add() {
		return a + b;
	}
	
	// 클래스(스태틱) 메서드
	static long add(long a, long b) {
		return a + b;
	}
}

public class MyMathTest {
	public static void main(String[] args) {
		// 클래스 메서드 호출
		System.out.println(MyMath.add(200L, 300L));
		
		// 인스턴스 생성
		MyMath mm = new MyMath();
		mm.a = 100L;
		mm.b = 400L;
		
		// 인스턴스 메서드 호출
		System.out.println(mm.add());
	}
}

// result
500
500

MyMath클래스에 두개의 add메서드가 각각
인스턴스메서드이고, 클래스메서드로 정의되어 있다.

인스턴스메서드는 인스턴스변수 a와 b를 더하는 작업을 하기 때문에
별도의 입력값이 필요하지 않다.

클래스메서드는 인스턴스변수를 사용하는 대신
입력받은 두개의 값을 더해서 반환하는 작업을 한다.

인스턴스 메서드와는 달리 클래스메서드에서는
인스턴스변수 a, b를 사용하지 않았기에 static을 붙일 수 있었다.

MyMathTest클래스에서 메서드들을 각각 호출했다.
클래스메서드는 인스턴스를 생성하지 않고도 바로 호출이 가능하다.

인스턴스메서드는 먼저 인스턴스를 생성하고
인스턴스변수 a와 b에 각각 값을 저장하고 인스턴스메서드를 호출한다.

인스턴스 메서드는 인스턴스변수 a와 b의 합을 결과로 주게 된다.


📖멤버간의 참조와 호출

같은 클래스의 멤버간에는 객체생성이나 참조변수 없이 참조할 수 있다.
그러나 static멤버들은 인스턴스 멤버들을 참조할 수 없다.

메서드의 호출

public class MethodCallTest {
	// 인스턴스 메서드
	public void instanceMethod() {}
	
	// static메서드
	static void staticMethod() {}
	
	// 인스턴스 메서드
	public void instanceMethod2() {
		// 다른 인스턴스 메서드 호출 가능
		instanceMethod();
		// static메서드 호출 가능
		staticMethod();
	}
	
	// static메서드
	static void staticMethod2(){
		// Error발생 : 스태틱 메서드에서는 인스턴스 메서드 호출 불가능
		// instanceMethod();
		// 다른 static메서드 호출 가능
		staticMethod();
	}
}
  • 하나의 클래스에 정의된 멤버들은 서로 관련이 깊기 때문에
    클래스 내에서는 이름만으로도 접근, 호출이 가능하다.

  • static멤버들은 인스턴스멤버를 이름만으로 접근, 호출이 불가능하다.

    • 클래스멤버들은 인스턴스를 생성하지 않고도 사용할 수 있기 때문에
      인스턴스를 생성해야만 사용할 수 있는 인스턴스멤버들을 사용하지 못하게 되어 있기 때문이다.

    • 같은 클래스 내의 멤버들끼리는 서로 객체생성이나 참조변수 없이 참조할 수 있지만 static멤버들은 인스턴스멤버들을 참조할 수 없다.


변수의 접근

public class VariableTest {
	// 인스턴스 변수
	int iv;
	
	// 클래스(static)변수
	static int cv;
	
	// 인스턴스 메서드
	public void instanceMethod() {
		// 인스턴스 변수 사용 가능
		System.out.println(iv);
		// 클래스변수 사용 가능
		System.out.println(VariableTest.cv);
	}
	
	// 클래스 메서드
	static void staticMethod() {
		// Error : 클래스메서드에서 인스턴스 변수 사용 불가
		// System.out.println(iv);
		
		// 클래스메서드에서 클래스변수 사용 가능 
		System.out.println(cv);
	}
}
  • 인스턴스메서드 instanceMethod()에서는 iv와 cv를 모두 사용할 수 있다.

  • 클래스메서드인 staticMethod()는 인스턴스변수인 iv를 사용할 수 없다.

0개의 댓글