[자바의 정석] chapter06 객체지향 프로그래밍1/ 3. 변수와 메서드(3.1~3.6)

임대진·2022년 2월 27일
0
post-custom-banner

3. 변수와 메서드

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

  • 변수는 클래스변수, 인스턴스변수 지역변수 모두 세 종류가 있다.
class Variables
{
  int iv;        // 인스턴스변수
  static int cv; // (static변수, 공유변수)
  
  void method()
  {
     int lv = 0; // 지역변수 
   }
 }

변수의 종류와 특징

  1. 인스턴스변수(instance variable)
  • 클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어진다.
  • 인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다.
  • 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우, 인스턴스변수로 선언한다.
  1. 클래스변수(class variable)
  • 클래스 변수를 선언하는 방법은 인스턴스변수 앞에 static을 붙이기만 하면된다.
  • 클래스변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다.
  • 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우, 클래스변수로 선언해야 한다.
  • 클래스 변수는 인스턴스변수와 달리 인스턴스를 생성하지 않고도 언제라도 바로 사용할 수 있다
  • '클래스이름.클래스변수'와 같은 형식으로 사용한다.ex) Variables클래스의 클래스변수 cv를 사용하려면 'Variables.cv'와 같이 하면 된다.
  • public을 앞에 부티면 같은 프로그램 내에서 어디서나 접근할 수 있는 '전역변수(global variable)'의 성격을 갖는다.
  1. 지역변수(local variable)
  • 메서드 내에 선언되어 메서드 내에서만 사용 가능하며, 메서드가 종료되면 소멸되어 사용 할 수 없게 된다. ex) for문 또는 while문의 블럭 내에 선언된 지역변수가 선언된 블럭 {} 내에서만 사용 가능하며, 블럭{}을 벗어나면 소멸되어 사용할 수 없게 된다.

3.2 클래스변수(class variable)와 인스턴스변수(instance variable)

class CardTest{
  public static void main(String args[]){
      System.out.println("Card.width = " + Card.width);
      System.out.println("Card.height = " + Card.height); // 클래스변수(static변수)는 객체 생성
                                                          // '클래스이름.클래스변수'로 직접 
                                                          // 사용 가능하다.
      
      Card c1 = new Card();
      c1.kind = "Heart";
      c1.number = 7;
      
      Card c2 = new Card();
      c2.kind = "Spade";    // 인스턴스변수의 값을 변경한다.
      c2.number = 4;        // 인스턴스변수의 값을 변경한다. 
      
      System.out.println("c1은 " + c1.kind + ", " + c1.number
                     + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
      System.out.println("c2는 " + c2.kind + ", " + c2.number
                     + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
      System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
      c1.width = 50;   // 클래스변수의 값을 변경한다.
      c1.height = 80;  // 클래스변수의 값을 변경한다. 
      
      System.out.println("c1은 " + c1.kind + ", " + c1.number
                    + "이며, 크기는 (" + c1.width + ", " + c1.heiht + ")");
      System.out.println("c2는 " + c2.kind + ", " + c2.number
                    + "이며, 크기는 (" + c2.width + ", " + c2.height + ")");
     }
}

class Card {
      String kind;  // 무늬 (인스턴스변수)
      int number;   // 숫자 (인스턴스변수)
       
      static int width = 100;  // 폭 (클래스변수)
      static int height = 250; // 높이 (클래스변수)
 }
  • 인스턴스변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.

3.3 메서드

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

메서드를 사용하는 이유

  1. 높은 재사용성(resusability)한번 만들어 높은 메서드는 몇 번이고 호출할 수 있으며, 다른 프로그램에서도 사용이 가능하다.
  2. 중복된 코드의 제거 프로그램을 작성하다보면, 같은 내용의 문장들이 여러 곳에 반복해서 나타나곤 한다. 이렇게 반복되는 문장들을 묶어서 하나의 메서드로 작성해 높으면, 반복되는 문장들 대신 메서드를 호출하는 한 문장으로 대체할 수 있다.전체 소스코드의 길이가 짧아진다.변경사항이 발생했을 때 수정해야할 코드의 양이 줄어들어 오류가 발생할 가능성도 줄어든다.
public static void main(String args[]){
    ...
    for (int i = 0; i<10;i++)
       numArr[i] = (int) (Math.random()*10);
    for (int i = 0; i<10;i++)
       System.out.printf("%d", numArr[i]);
    System.out.println();
        ...중간 생략...
    for (int i = 0;i<10;i++)
       System.out.printf("%d", numArr[i]);
    System.out.println();
  }
static void printArr(int [] numArr) {
   for(int i = 0;i<10;i++)
      System.out.printf("%d", numArr[i]);
   System.out.println();
}

public static void main(String args[]){
  ...
  for(int i = 0;i<10;i++)
    numArr[i] = (int) (Math.random()*10);
  printArr(numArr); // 배열을 출력 (반복되는 코드 대신 메서드를 호출)
        ...중간 생략...
  printArr(numArr); // 배열을 출력 (반복되는 코드 대신 메서드를 호출)

3. 프로그램의 구조화

  • 길어야 100줄 정도 밖에 안 되는 작은 프로그램을 작성할 때는 이렇게 해도 별 문제가 없지만,

몇천줄, 몇 만 줄이 넘는 프로그램도 이런 식으로 작성할 수는 없다.

큰 규모의 프로그램에서는 문장들을 작업단위로 나눠서 여러 개의 메서드에 담아 프로그램의 구조를 단순화시키는 것이 필수적이다.

public static void main(String args[]) {
     int[] numArr = new int[10];
     initArr(numArr);  // 1. 배열을 초기화
     printArr(numArr); // 2. 배열을 출력 
     sortArr(numArr);  // 3. 배열을 정렬
     printArr(numArr); // 4. 배열을 출력
}
  • 이처럼 main메서드는 프로그램의 전체 흐름이 한눈에 들어올 정도로 단순하게 구조화하는 것이

    좋다.

그래야 나중에 프로그램에 문제가 발생해도 해당 부분을 쉽게 찾아서 해결 할 수 있다.


3.4 메서드의 선언과 구현

  • 메서드는 '선언부(header,머리)'와 '구현부(body, 몸통)'로 이루어져 있다.
  • 메서드를 정의한다는 것은 선언부와 구현부를 작성하는 것

선언부

반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)

구현부

{

// 메서드 호출시 수행될 코드

}
int add(int a, int b)  //선언부
//구현부
{
     int result = a + b;
     return result; //호출한 메서드로 결과를 반환한다.
}

메소드 선언부(method declaration, method header)

  • 메서드 선언부는 '메서드의 이름'과 '매개변수 선언', 그리고 '반환타입'으로 구성되어 있다.
  • 메서드가 작업을 수행하기 위해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한정보를 제공한다.
int add (int x, int y) { // 반환타입(출력) 메서드이름 (매개변수선언(입력))
    int result = x + y;
    
    return result; //결과를 반환

※ 메서드의 선언부는 후에 변경사항이 발생하지 않도록 신중히 작성해야한다. 메서드의 선언부를 변경하게 되면,   그 메서드가 호출되는 모든 곳도 같이 변경해야 하기 때문이다.

매개변수 선언(parameter declaration)

  • 매개변수는 메서드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것이며, 필요한 값의 개수만큼 변수를 선언하며 각 변수 간의 구분은 쉼표','를 사용한다.

※ 일반적인 변수선언과 달리 두 변수의 타입이 같아도 변수의 타입을 생략할 수 없다

int add(int x, int y) {...} // OK
int add(int x, y)     {...} // 에러, 매개변수 y의 타입이 없다.

메서드의 이름(method name)

  • 변수의 명명규칙대로 작성
  • 이름만으로도 메서드의 기능을 쉽게 알 수 있도록 함축적이면서도 의미있는 이름

반환타입(return type)

  • 메서드의 작업수행 결과(출력)인 '반환값(return value)'의 타입을 적는다.
  • 반환값이 없는 경우 반환타입으로 'void'를 적어야 한다.

메소드의 구현부(method body, 메서드 몸통)

  • 메서드의 선언부 다음에 오는 괄호{}를 '메서드의 구현부'라고 하는데, 여기에 메서드를 호출했을 때수행될 문장들을 넣는다.

return문

  • 메서드의 반환티입이 'void'가 아닌 경우, 구현부{}안에 'return'반환값;'이 반드시 포함되어 있어야 한다.
  • 반환값의 타입은 반환타입과 일치하거나 적어도 자동 형변환이 가능한 것이어야 한다.
  • 여러 개의 변수를 선언할 수 있는 매개변수와 달리 return문은 단 하나의 값만 반환 할 수 있는데, 메서드로의 입력(매개변수)은 여러 개일 수 있어도 출력(반환값)은 최대 하나만 허용하는 것이다.
int add(int x, int y)
{
   int result = x + y;
   return result; // 작업 결과(반환값)를 반환한다. 
 } //int와 result 타입 일치

지역변수(local variable)

  • 메서드 내에 선언된 변수들은 그 메서드 내에서만 사용할 수 있으므로 서로 다른 메서드라면 같은 이름의 변수를선언해도 된다.
  • 매개변수도 메서드 내에 선언된 것으로 간주되므로 지역변수이다.
int add(int x, int y) {
    int result = x + y;
    return result; 
 }
 
 int multiply(int x, int y)  {
     int result = x * y;
     return result;
 }

3.5 메서드의 호출

메소드이름(값1, 값2, ...); // 메서드를 호출하는 방법
print99danAll(); // void print99danAll()을 호출
int result = add(3,5); // int add(int x, int y)를 호출하고, 결과를 result에 저장

인자(argument)와 매개변수(parameter)

  • 메서드를 호출할 때 괄호()안에 지정해준 값들을 '인자(argument)'또는 '인수'라고 하는데,인자의 개수와 순서는 호출된 메서드에 선언된 매개변수와 일치해야 한다.
  • 인자는 메서드가 호출되면서 매개변수에 대입되므로, 인자의 타입은 매개변수의 타입과 일치하거나 자동 형변환이 가능한 것이어야 한다.
public static void main(String args[ ])  {
      ...
      int result = add(3, 5);// 3, 5  --> 인자(argument)
      ...
int add(int x, int y) // x, y --> 매개변수(parameter)
{
     int result = x + y;
     return result;
}

• 메서드에 선언된 매개변수의 개수보다 많은 값을 괄호()에 넣거나 타입이 다른 값을 넣으면 컴파일러가 에러를 발생시킨다.

int result = add(1, 2, 3);  // 에러. 메서드에 선언된 매개변수의 개수가 다름
int result = add(1.0, 2.0); // 에러. 메서드에 선언된 매개변수의 타입이 다름

• 반환타입이 void가 아닌 경우, 메서드가 작업을 수행하고 반환한 값을 대입연산자로 변수에 저장하는 것이 보통이지만, 저장하지 않아도 문제가 되지 않는다.

int result = add(3, 5);  // int add(int x, int y)의 호출결과를 result에 저장
add(3, 5);                 // OK. 메서드 add가 반환한 결과를 사용하지 않아도 된다.
class MyMathTest { 
  public static void main(String args []) {
      MyMath mm = new MyMath();
      long result1 = mm.add(5L, 3L);
      long result2 = mm.substract(5L, 3L);
      long result3 = mm.multiply(5L, 3L);
      double result4 = mm.divide(5L, 3L);
      
      System.out.println("add(5L, 3L) = " + result);
      System.out.println("subtract(5L, 3L) = " + result2);
      System.out.println("multiply(5L, 3L) = " + result3);
      System.out.println("divide(5L, 3L) = " + result4);
      
     }
    }
    
    class MyMath {
      long add(long a, long b) {
          long result = a+b;
          return result; 
         // return a + b; // 위의 두 줄을 이와 같이 한 줄로 간단히 할 수 있다. 
        }
        
        long substract(long a, lon b) {return a -b;}
        long multiply(long a, long b) {return a * b;}
        double divide(double a, double b) {return a / b;}
        }
     }
MyMath mm = new MyMath(); //먼저 인스턴스를 생성한다.
long value = mm.add(1L, 2L); // 메서드를 호출한다.

long add(long a, long b) {
         long result = a + b; 
         return result;
}
  1. main메서드에서 메서드 add를 호출한다. 호출시 지정한 1L과 2L이 메서드 add의 매개변수 a,b에 각각 복사(대입)된다.
  2. 메서드 add의 괄호{}안에 있는 문장들이 순서대로 수행된다.
  3. 메서드 add의 모든 문장이 실행되거나 return문을 만나면, 호출한 메서드(main메서드)로 되돌아와서 이후의 문장들을 실행한다.

3.6 return문

  • return문은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아간다.
  • 반환타입이 void인 경우, return문 없이도 아무런 문제가 없었던 이유는 컴파일러가 메서드의 마지막에 'return;'을 자동적으로 추가해주었기 때문이다.
void printGugudan(int dan) {
     for(int i = 1; i <= 9; i++) {
         System.out.printf("%d * %d = %d%n", dan, i, dan * i);
     }
     // return; // 반환 타입이 void이므로 생략가능, 컴파일러가 자동추가
     }
  • 반환값이 있는 경우 return문이 있어야 한다.
  • return문이 없으면 컴파일 에러(err0r: missing return statement)가 발생한다.
int multiply(int x, int y) {
    int result = x * y;
    return result; // 반환타입이 void가 아니므로 생략불가
   }
  • 두 값 중에서 큰 값을 반환하는 메서드이다. 이 메서드의 리턴타입이 int이고 int타입의 값을 반환하는return문이 있지만, return문이 없다는 에러가 발생한다.
int max(int a, int b) {
     if(a > b) 
        return a; // 조건식이 참일 때만 실행된다.
 }

• 이런 경우 다음과 같이 if문의 else블럭에 return문을 추가해서, 항상 결과값이 반환되도록 해야 한다.

int max(int a, int b) {
    if( a > b)
          return a; // 조건식이 참일 때 실행된다. 
    else
          return b; // 조건식이 거짓일 때 실행된다. 
    }

반환값(return value)

  • return문의 반환값으로 주로 변수가 오긴 하지만 항상 그런 것은 아니다.
  • 예제2 처럼 수식으로 적어도 수식이 반환되는 것이 아니라 수식을 계산한 결과가 반환된다.
int add(int x, int y) {
      int result = x + y;
      return result;
}
int add(int x, int y) {
    return x + y;
    }

매개변수의 유효성 검사

  • 매개변수의 값이 적절한 것인지 확인
float divide(int x, int y) {
   // 작업을 하기 전에 나누는 수(y)가 0인지 확인한다. 
   if(y==0) {
        System.out.println("0으로 나눌 수 없습니다.");
        return 0; // 매개변수가 유효하지 않으므로 메서드를 종료한다.
        }
        
        return x / (float)y;
        }
  • y의 값이 0이면, 나누기를 계산할 수 없으므로 return문을 이용해서 작업을 중단하고 메서드를 빠져나와야 한다.그렇지 않으면, 나누기를 하는 문장에서 프로그램이 비정상적으로 종료가된다.
profile
신입개발자 공부기록 블로그
post-custom-banner

0개의 댓글