변수와 메서드

생성일
속성 
태그 

클래스가 가질수 있는 변수에대해서 알아보자 😃

클래스가 가질 수 있는 변수의 종류

클래스가 가질 수 있는 변수는 총 3개로 나뉠수가 있다,

  • 멤버변수
    • 클래스 변수 static이 붙음
    • 인스턴스 변수 static 붙지 않음
  • 지역변수 → 메서드 안에 있는 변수

이들은 선언 위치에 따라서 역할이 구분된다. 그러므로 어떤 변수인지 파악하기 위해서는

선언된 위치를 눈여겨 보면 좋다.

변수의 종류와 특징

변수의 종류 선언 위치 생성시기
클래스변수 클래스 영역 클래스가 메모리에 올라갈 때
인스턴스 변수 클래스 영역 인스턴스가 생성되었을 때
지역 변수 클래스 영역 이외의 영역 변수 선언문이 수행되었을 때

이중 지역변수는 자주들어봤을 텐데 클래스 변수와 인스턴스 변수는 처음들었을 것이다.

이들의 특징은 다음과 같다.

인스턴스변수

인스턴스 변수는 클래스의 인스턴스를 생성할 때 만들어진다.

인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다.

클래스 변수

클래스 변수는 인스턴스 변수안에 static을 붙인것 이다.

static을 사용했기 때문에 공통된 저장공간을 공유하게 된다.

각 인스턴스가 생성되어도 이값은 각 인스턴스마다 같다.

또한, 인스턴스를 생성하지 않아도 클래스이름.클래스변수와 같이 .을 사용하여 접근 할 수 있다.

결국 static이 붙었기 때문에 전역변수 취급을 받는다.

메서드

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

메서드를 사용하는 이유

  1. 높은 재사용성메서드는 한번 만들어 놓으면 몇번이든 재호출 할 수 있으며 다른프로그램에서도 사용할 수 있다.
  2. 중복된 코드의 제거프로그램을 구성하면 반복되는 코드가 있기 마련이다. 이러한 코드들을 메서드를 만들어 재사용 한다면 코드의 양이 줄어들어 오류가 발생할 가능성이 줄어드는 이점이 있다.
  3. 프로그램의 구조화메서드를 만들어 main 메서드 안에서 모든 문장을 넣는 식으로 프로그램을 작성할 필요가 없다.
  4. 각각의 작업단위를 쪼개서 필요한 클래스를 만들어 그 클래스에 여러 개의 메서드를 담아서 프로그램의 구조를 단순화 시킨다면 나중에 문제가 있을 때 쉽게 찾아 문제를 해결 할 수 있는 장점이 있다.

메서드의 선언

메서드는 선언부(header)구현부(body)로 나뉘어져 있다. 사실 함수를 선언하는 것과 비슷한다.

반환타입 매서드이름 (매개변수){
    //매서드의 코드
}

//예시
int sum (int a, int b){
    return a + b;
}

메서드에서 는 반환타입이 void가 아닌 이상 항상 값을 return해줘야 한다.

메서드에서 반환된 값은 반환 타입과 일치하거나 혹은 자동 형변환을 메서드가 알아서 해준다.

또한, 반환값은 반드시 하나인것을 명시해야 한다.

그리고 메서드는 return을 하면 항상 종료된다 중간에 다른코드가 있거나 밑에 다른코드가 있더라도

값을 반환하면 종료가 된다.

메서드의 호출

메서드는 호출되면 스택과 같은 구조로 쌓인다.

이를 자세히 알기 위해서는 JVM의 메모리 구조에대해서 알아야한다

JVM은 프로램이 실행 되면 프로그램을 수행하는데 필요한 메모리를 할당받는다.

이러한 메모리들은 용도에 따라 달라진다. 보통 다음과 같은 구조에 메모리를 할당한다.

  1. 메서드 영역메서드 영역에서는 클래스파일을 읽고 클래스 데이터를 이곳에 저장한다. 또한, 클래스 변수도 함께 저장한다
  2. 힙은 보통 인스턴스가 생성되는 공간이다 보통의 인스턴스 변수들이 생성된다.
  3. 보통 Stack을 뺀 모든 변수들이 이곳에서 생성이 된다.
  4. Call Stack(호출스택)호출스택은 메서드 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출 될 떄 마다 메서드를 위한 메모리 공간이 할당되며 이러한 메서드의 지역변수연산의 중간결과등을 저장한다.호출스택의 제일위에 있는 메서드는 자신을 실행시킨 메서드이다. 바로 아래에 있는 메서드는 위의 메서드를 호출한 메서드이다.
  5. Call stack 말처럼 stack처럼 쌓이면서 저장되고 작업을 마치면 stack 위에 있던 메서드가 사용한 공간이 반환되며 비워진다.

Stack을 배웠다면 이해하기가 쉬울 것이다.

매개변수의 특징

보통 매개변수는 지역변수취급을 당한다고 생각하면 편하다.

매개변수가 들어와서 작업을 행했을 때 값이 바뀌어도 원래 호출하였던 매개변수의 값은 변하지 않는다.

C/C++ 언어에서는 포인터를 사용하여 Call by Reference를 사용하여 바꿀 수 있지만 자바에서는 포인터가 존재하지 않는다.

하지만 자바에서도 참조형 매개변수가 있다. 이는 매개변수의 타입이 참조형인 매개변수를 뜻한다.

이는 값이 변하면 원본에 영향을 미칠 수 있다.

class Book {int pageNumber;}

public static void main(String[] args){
    Book book = new Book();
  book.pageNumber = 1;
  System.out.printf("pageNumber = %d",book.pageNumber); // 1출력
  nextPage(book);
  System.out.printf("pageNumber = %d",book.pageNumber); // 2출력 -> 값이 변함
}

static void nextPage(Book book){
    book.pageNumber += 1;
}

또한, 이뿐만이 아니라 배열을 매개변수로 이용해도 똑같은 결과를 얻을 수 있다.

그렇기 때문에 밑의 예제와 같이 결과값을 저장하고 싶을때 배열을 매개변수로 사용 할 수 있다.

void add (int a, int b, int[] result){
    result[0] = a + b;
}

참조형의 반환

이뿐만이 아니라 참조형은 반환타입에서도 특별하게 사용된다,

보통 return을 하면 값을 반환하는데 참조형을 반환하면 특별하게 주소를 반환한다,

그렇기 때문에 호출결과를 저장하는 타입의 일치가 필요하다.

재귀 호출

보통 코딩테스트나 백트레킹 기술에 사용되는 기술이다. 영어로는 Recursive call이라 한다.

이는 자기 자신을 메소드에서 호출하는 것이다.

위에서 메서드는 Stack처럼 쌓인다. 라고하였다 이러한 Stack 을 이용하여 쉽게 유추 할 수 있다.

재귀호출을 사용할 때에는 반드시 종료조건을 명시 해줘야한다.

단순히 반복문을 사용해도 되는데 재귀호출을 사용하는 이유는

간혹 몇겹의 반복문을 작성하는 것 보다 재귀호출이 비효율적이더라도 쉽게 알아보기 편하게 작성할 수 있기 떄문이다.

예시로 펙토리얼피보나치 가 있다.

클래스 메서드 & 인스턴스 메서드

변수에도 클래스 변수, 인스턴스 변수가 있듯이 함수에도 존재한다.

변수와 마찬가지로 static이 붙으면 클래스메서드 붙지 않으면 인스턴스 메서드이다.

인스턴스 메서드는 메서드 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드 이다.

클래스 메서드는 메서드 중 인스턴스와 관계없는 메서드를 클래스 메서드라고 정의한다.

하지만 인스턴스를 사용하지 않는다고 해서 반드시 클래스 메서드를 사용해라라는 것은 아니다.

하지만 사용하는 것을 권장한다 왜냐하면 인스턴스를 생성할 때마다 static이 없으면 메서드를 찾는 과정이 추가적으로 필요하기 때문에 static 유무에 시간이 더걸리거나 덜 걸린다.

또한, 클래스 메서드에는 중요한 조건이 있는데 클래스 메서드는 인스턴스 변수를 사용할 수 없다.

단순히 생각하면 쉽다. 클래스 메서드static이라 인스턴스 호출전에 사용이 가능한데

인스턴스 변수는 인스턴스가 생성되지 않으면 존재하지 않을 수도 있기 때문이다.

오버로딩

오버로딩은 같은 클래스 내에 같은 이름의 메서드를 여러 개 정의 하는 것을 말한다.

오버로딩을 하기 위해서는 다음과 같은 조건을 만족해야한다.

  1. 매서드 이름이 같아야한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.

또한, 주의 해야할 점이 매개변수의 개수 또는 타입이 달라야하는 거지 리턴 타입만 다른 경우는

포함 되지 않는다.

오버로딩은 내가 원하는 같은 동작을 매개변수가 달라져도 똑같이 구현이 가능하다는 장점이 있다.

다음과 같은 예를 보자.

int sum(int a, int b){
    return a+b;
}

float sum(float a, float b){
    return a+b;
}

이런식으로 나는 실수와 정수를 똑같은 sum()이라는 매서드를 통해 구별없이 계산하고 싶다.

만약, 오버로딩이 없다면 이를 sumInt() 라는 메서드와 sumFlaot()라는 각기의 메서드로 만들어야 할 것이다.

이뿐 만이 아니라 다른 타입을 구현하고 싶을 떄도 타입의 개수에 따라 엄청나게 같은기능을 하는 이름이 다른 메서드들이 늘어날 것이다.

이는 너무 비효율적이다.

가변인자 & 오버로딩

기존에는 내가 매개변수를 100개를 생성하려면 일일히 100개를 다 적어야했다.

이는 너무 비효율적이다. 이를 해결하기 위해서 JDK 1.5버전부터 매개변수를 동적으로 지정할 수 있게 되었다. 이를 가변인자라고 한다.

예시로 문자열을 합쳐주는 메서드를 만든다고 가정한다. 매개변수가 2개일 경우는 다음과 같다.

String concat(String str1, String str) {};

하지만 만약 매개변수의 갯수가 4개만 되더라도 많이 복잡해진다.

String concat(String str1, String str2, String str3, String str4) {};

이럴 때 가변인자를 사용하면 매개변수를 한번만 써서 구현이 가능하다.

String concat(String... str) {};

이렇게 가변인자로 구현을 한다면 매개변수의 갯수에 구애 받지 않게 할 수 있다.

또한, 배열을 넘겨줄수도 있다.

가변인자를 사용할 때 주의 할점이 있는데 항상 가변 인자는 매개변수의 에 위치해야한다.

String concat(String hello, String... str) {}; -> (o)

String concat(String... str, String hello) {}; -> (x) 

또한, 배열을 매개변수로 넣어준다고 하였는데 허용되지 않는 것도 있다.

String concat (String... str) {}; 

concat(new String[] { "Hello", "world"} -> (o)

concat({"Hello","World"}) -> (X)

제일 밑과 같이 저런 형식으로는 사용이 불가능 하다 배열을 생성하고 넣어주는 것은 괜찮다.

또한, 가변인자를 사용한 메서드의 오버로딩매개변수의 변화를 쉽게 컴파일러가 못알기 때문에

가변인자를 사용했으면 오버로딩을 사용하지 않는 것이 좋다.

이렇게 생각하면 결국 배열을 매개변수로 메서드를 생성하는 것도 가능하지 않을까? 하는 의문점이 들 수있다.

물론 맞는 소리지만 배열을 매개변수로 매서드를 생성했을 때는 반드시 인자를 지정해 줘야한다 이러한 추가적인 불편함이 있기 때문에 가변인자를 사용한다.

Reference

  • 자바의 정석

'Java > Java' 카테고리의 다른 글

[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 클래스와 객체  (0) 2021.09.06
[Java/Study] 자료형  (1) 2021.09.05

+ Recent posts