JAVA/기본

#3 변수, 메서드

히포파타마스 2021. 4. 23. 16:00

변수

 

변수는 클래스 변수, 인스턴스 변수, 지역변수가 있다.

 

각 변수의 종류를 결정짓는 중요 요소 중 하나는 변수가 선언된 위치이다.

 

[위치에 따른 변수의 종류]

class Test{
    int test1;         // 인스턴스 변수
    static int test2;  // 클래스 변수

    void plus_one() {
        int test3;    // 지역 변수
    }
}

 

 

[변수의 종류에 따른 위치와 생성시기]

변수의 종류 선언위치 생성시기
클래스 변수 클래스 영역 클래스가 메모리에 올라갔을 때
인스턴스 변수 인스턴스가 생성됐을 때
지역변수 클래스 영역 이외
(메서드, 생성자, 초기화 블럭 등)
변수 선언문이 수행 되었을 때

 

 

1. 클래스 변수

클래스 변수는 선언위치는 인스턴스 변수와 같이 클래스 영역이지만 앞에 static이 붙는다. 

 

클래스 변수는 클래스가 메모리에 올라갈 때 생성되므로 모든 인스턴스에서 동일한 값을 유지하며 인스턴스를 생성하지 않고도 바로 사용할 수 있다.

ex) 클래스.클래스_변수

 

이  때문에 클래스 변수는 모든 인스턴스에 공통으로 유지되어야 될 때 사용된다.

 

 

2. 인스턴스 변수

인스턴스 변수는 인스턴스가 생성될 때 만들어지며, 각 인스턴스마다 독립적으로 존재한다.

 

때문에 인스턴스 변수는 각 인스턴스마다 고유한 값을 가져야 할 때 사용된다.

 

 

3. 지역 변수

지역변수는 메서드 혹은 초기화 블럭에 선언되어 해당 블럭 내에서만 사용 가능하며, 블럭이 끝나면 소멸된다.

 

 

 

메서드

 

메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다.

 

 

1. 메서드 선언과 구현, 호출

 

[메서드 선언]

반환타입 메서드명 (타입 매개변수, ..) {    // 선언부
    메서드 호출 시 수행될 코드
    ..		                    	// 구현부	
    ..
}

선언부에 메서드가 반환할 값의 타입메서드명, 그리고 매개변수를 설정한다.

 

구현부에서는 매개변수를 받아 실행할 코드를 적는다. 

 

 

[메서드 선언과 구현 예시]

int plus(int num1, int num2){
    return num1 + num2;
}

정수형 num1과 num2를 매개변수로 받고, 정수형을 반환하는 plus라는 이름의 메소드를 선언했다.

 

구현부에는 num1 과 num2를 더해서 반환하는 코드를 적었다.  

 

 

[메서드 호출]

public class Main {
    public static void main(String[] args) {

        math test = new math();

        int a = test.plus(1,3);
        System.out.println(a);
    }
}

class math {
    int plus ( int num1, int num2) {
        return num1 + num2;
    }
}

math 클래스에 정수값 두개를 받아 더하는 plus라는 메소드를 구현하였다.

 

math의 인스턴스를 생성하고 '클래스.메소드' 형식으로 메소드를 호출하였다.

 

 

[결과]

4

 

 

■ return문

 

메서드는 반드시 return문을 포함하고 있어야 한다.

 

라는 것은 메서드는 어떤 경우에서든 return문으로 끝날 수 있어야 한다는것을 의미한다.

 

 

[잘못된 return문]

int add (int num1, int num2) {
    if (num1 > 0 && num2 > 0) {
        return num1 + num2;       //return문으로 끝나지 않을 수 있음
    }
}

위의 add 메서드는 num1과 num2가 모두 양수일 때 각 값을 더해서 반환한다.

 

하지만 이 경우 num1과 num2 두 변수중 하나가 양수가 아닐 경우 return값이 적용되지 않기 때문에 에러가 발생한다.

 

 

2. 인스턴스, 클래스 매서드

변수와 같이 메서드 역시 인스턴스 메서드클래스 메서드가 있으며 클래스 메서드는 앞에 static을 붙여주면 된다.

 

변수와 같이 클래스 매서드도 인스턴스 생성 없이 '클래스.클래스_메서드'의 형식으로 사용 할 수 있다.

 

이 때문에 클래스 메서드는 인스턴스 변수를 사용 할 수 없다.

 

왜냐하면 클래스 메서드는 인스턴스 없이 사용 할 수 있기 때문에 경우에 따라서 인스턴스 변수가 존재하지 않을 수도 있기 때문이다.

 

 

[클래스 메서드에서 인스턴스 메서드 호출]

public class Main {
    int plus ( int num1, int num2) {
        return num1 + num2;
    }

    public static void main(String[] args) {
        int a = plus(1,3);
        System.out.println(a);
    }
}

main 메서드는 앞에 static이 붙어있기 때문에 클래스 메서드이다.

 

main 메서드 내에서 인스턴스 메서드인 plus 메서드를 호출해보았다.

 

결과는 아래와 같다.

 

 

[즉시 실패]

java: non-static method plus(int,int) cannot be referenced from a static context

 

 

[클래스 메서드에서 클래스 메서드 호출]

public class Main {
    static int plus ( int num1, int num2) {
        return num1 + num2;
    }

    public static void main(String[] args) {
        int a = plus(1,3);
        System.out.println(a);
    }
}

이번에는 plus메서드를 클래스 메서드로 변경한 후 main 메서드에서 호출해 보았다.

 

결과는 아래와 같다.

 

 

[즉시 성공]

4

 

 

위의 예와 같이 클래스 메서드는 클래스 멤버만 참조할 수 있다.

 

하지만 인스턴스 메서드는 클래스, 인스턴트 멤버 모두 참조 가능하다.

 

따라서 클래스 메소드는 '인스턴스 멤버를 전혀 사용하지' 않고 '인스턴트의 생성 없이 메소드를 사용해야' 할 때 사용된다.

 

 

3. 매개변수와 반환값

메서드의 매개변수와 반환값은 메서드 선언 시 정해진 타입만이 올 수 있다.

 

때문에 매개변수와 반환값에 들어갈 수 있는 값은 적어도 형변환이 이루어져서 정해진 타입으로 변경 가능한 값이여야 한다. 

 

 

[잘못된 매개변수]

public class Main {
    static int plus (int num1, int num2) {
        return num1 + num2;
    }

    public static void main(String[] args) {
        int a = plus(1.0,3.0);
        System.out.println(a);
    }
}

int형 매개변수를 받는 plus 메소드에 double형인 1.0과 3.0을 넣었다.

 

결과는 아래와 같다.

 

 

[즉시 오류]

C:\Users\qkqnt\Desktop\javatest\src\Main.java:7:22
java: incompatible types: possible lossy conversion from double to int

 

 

[형변환 가능한 매개변수]

public class Main {
    static double plus (double num1, double num2) {
        return num1 + num2;
    }

    public static void main(String[] args) {
        double a = plus(1L,3L);
        System.out.println(a);
    }
}

double형 매개변수를 받는 plus 메서드에 long형인 1L과 3L을 넣었다.

 

비록 매개변수의 타입이 double형은 아니지만 long -> double의 관계는 자동으로 형변환이 가능하기 때문에 에러없이 코드가 실행 될 수 있다.

 

결과는 아래와 같다. 

 

 

[즉시 성공]

4.0

double형으로 자동 형변환이 이루어져 1L + 3L => 4.0의 값이 나온것을 확인 할 수 있다.

 

 

참조 매개변수

 

기본형을 매개변수로 받았을 때는 단순히 값이 복사가되어 메서드의 구현부에서 지역변수로 사용되기 때문에 메서드가 끝나면 자연 소멸된다.

 

따라서 기본형의 값을 메서드 내에서 변경해도 메서드 밖의 원 기본형 변수는 변화가 없다.

 

 

[메서드를 통한 기본형 값의 변경]

public class Main {
    static int convert (int num) {
        return num = 5;
    }

    public static void main(String[] args) {
        int a = 10;
        convert(a);
        System.out.println(a);
    }
}

convert라는 함수를 만들어 매개변수로 받은 값을 5로 초기화 시켰다.

 

결과는 아래와 같다.

 

 

[즉시 실패]

10

 

 

하지만 참조형 변수는 주소값이 저장되어있기 때문에 메소드 내애서 변경된 값을 유지 할 수 있다.

 

 

[메서드를 통한 참조형 값의 변경]

public class Main {
    static void convert (test t) {
        t.x = 5;
    }

    public static void main(String[] args) {

        test t = new test();
        t.x = 10;

        convert(t);

        System.out.println(t.x);
    }
}

class test{
    int x;
}

test 클래스를 받아 멤버변수 x를 5로 초기화 시키는 convert함수를 구현하였다.

 

test 클래스의 인스턴스 t의 멤버변수 x를 10으로 초기화 한 뒤 convert함수에 t를 적용하였다.

 

결과는 아래와 같다.

 

 

[즉시 성공]

5

 

 

 

JVM의 메모리 구조

 

1. Method Area

클래스에 대한 정보가 저장되는 장소.

 

따라서 클래스 변수들은 이 영역에 함께 생성된다.

 

 

2. Call stack

메서드 작업에 필요한 메모리 공간.

 

메서드가 호출되면 Call stack에 메모리가 할당되며 호출된 메서드와 그에 필요한 데이터(지역변수)는 순차적으로 쌓이게 된다(stack이니까).

 

메서드가 작업을 마치면 할당된 메모리 공간은 반환되고 비워진다.

 

위와 같은 구조 때문에 메서드를 순차적으로 실행시켰을 때는 제일 나중에 호출된 메소드부터 처리된다.

 

 

3. Heap

인스턴스가 생성되는 공간.

 

따라서 인스턴스 변수들은 이 영역에 생성된다.