JAVA 객체지향-클래스 인스턴스 메서드

jadive study·2022년 11월 28일
0

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

Card클래스의 큼래스변수(static변수)인 width, height는 Card끝래스의 인스턴스블 생성하지 않고도 •클래스이름.클래스변수’와 같은 방식으로 사용 할 수 있다.

인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값 유지, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유.

3.3 메서드

특정 작업을 수행하는 일련의 문장들을 하나로묶은 것이다.
드에
넣을 값(입력)과 반환하는 결과(출력)만 알면 되는 것이다. 그래서 메서드를 내부가 보이
지 않는 ‘블랙박스(black box)’라고도 한다.
sqrt()외에도 지금까지 빈번히 사용해온 println()이나 random()과 같은 메서드들 역
시 내부적으로 어떻게 동작하는지 몰라도 사용하는데 아무런 어려움이 없었다.

메서드를 사용하는 이유

1.높은 재사용성 (reusability)

  1. 중복된 코드의 제거
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", 
System.out.printin();
...중간 생략...
for (int i = 0;i<10;i++) 
System.out.printf("%d",numArr[i]);
System.out.printin();
static void printArr(int[] numArr) { 
for(int i=0;i<10;i++)
System.out.printf(n%d", numArr[i]); 
System.out.printin();
}// 여기만 변경
public static void main《String args[]) {
for (int i = 0;i<10;i++)
numArr[i] = (int)(Math.random()*10); 
printArr (numArr); // 배열을 출력 —
...중간생략...
printArr (numArr); // 배열을 출력 — 
}

->반복되는 코드대신 메서드호출

반복적으로 나타나는 문장들을 메서드로 반들이서 시용하면 코드의 중복이 제기
되고, 빈경사항이 발생했을 때 이 메서드만 수정하민 되므로 관리도 쉽고 오류의 능성도 발생가능성도 낮아진다.

3. 프로그램의 구조화

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

public static void main(String args[]) {
int [ ] numArr = new int [10];

initArr (numArr); //배열을초기화
printArr(numArr); //배열을 출력
sortArr(numArr); //배열을 정렬
printArr(numArr);//배열을 츌력

static int showMenu()
static void inputRecord()
static void changeRecord() 
static void deleteRecord()//나중에 내용을 완성한다

public static void main(String args[]) (
switch(showMenu()) {
case    1:    inputRecordf);    break;    //데이터 입력
case    2:    changeRecordO;    break;    //데이터 변경
case    3:    deleteRecordO;    break;    //데이터 삭제
case 4: searchRecordO; break; //데이터 검색
default: showRecordList (); // 데이터의 목록

3.4 메서드의 선언과 구현
선언부(header,머리), 구현부의 body

반환타입메서드이름《타입변수명, 타입변수명,
{
// 메서드 호출시수행될코드
}

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

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

선언부는 '메서드의 이름’과 ‘매개변수 선언’, 그리고 ‘반환타입’으로 구성
아래에 정의된 메서드 add는 두 개의 정수를 입력받아서,두 값을 더한 결과
(int타입의 값)를 반환,메서드의 선 언부를 변경하게 되면, 그 메서드가 호출되는 모든 곳도 같이 변경해야 하기 때문이다.

int add (int x, int y) {
int result = x + y; 
return result; // 결과를 반환
}

매개변수 선언(parameter declaration)

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

메서드의 이름

서드는 특정 작업을
수행하므로 메서드의 이름은 ‘add’처럼 동사인 경우가 많으며. 이름만으로도 메서드의 기능을 쉽게 알 수 있도록 함축적이면서도 의미있는 이름을 짓도록 노력해야 한다.

반환타입(return type)

작업수행 결과(출력)인 ‘반환값(return value/의 타입을 적는다. 반환값이 없는 경우 반환타입으로 ‘void’를 적어야한다.
아래에 정의된 메서드 ‘print99danAir은 구구단 전체를 출력하는데,작업을 수행하는데 필요한 값도,작업수행의 결과인 반환값도 없다. 그래서 반환타입이 ‘void’이다.

 void print99danAll () {
for(int i=l;i<=9;i++) {
for(int j = 2;j< = 9;j++) { 
System.out.printin(j+"*"+i+"="+(j*i)+"");
}
System.out.println();
  }}

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

메서드의 선언부 디욤에 오는 괄회}를 ‘메서드의 구현부’라고 하는데,여기에 메서드늄
호출했을 때 수행될 문장들을 넣는다. 우리가 그동안 작성해온 문장들은 모두 main메서
드의 구현부{}에 속한 것들이었으므로 지금까지 하던 대로만 하면 된다.

return 문

‘void’가 아닌 경우,구현부{}안에 return 반환값;’이 반드시 포함되
어 있어야 힌다. 이 문장은 작업을 수행한 결과인 반환값을 호출한 메서드로 전달하는데, 이 값의 타입은 반환타입과 일치하거나 적어도 자동 형변환이 가능한 것
변수를 선언한 수 있는 매개변수와 달리 return문은 단 하나의 값만 반환한
수 있는데, 에서드로의 입력(매개변수)은 여러 개인 수 있어도 출력(반환값)은 최대 하나만 허용

-타입이 일치해야한다

지역변수(local variable)

서로 다른 메서드 라면 같은 이름의 변수를 선언해도 된다. 이처럼 메서드 내에 선언된 변수를 ‘지역변수 (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;
}

add와 multiply에 각기 선언된 변수,x,y,result는 이름만 같을 뿐 서로 다른 변수이다.

3.5 메서드의 호출

메서드를 호출해야만 구현부{}의 문장들이 수행된다. 메서드를 호출하는 방법은 다음과 같다.

print99danAll (); // void print99danAll(void)를 호출
int result = add (3, 5); // int add (int x, int y)를 호출하고, 걸과 result에저장

인자와 매개변수(parameter)

메서드를 호출할 때 괄호()안에 지정해준 값들을 '인자 (argument)’ 또는 '인수’라고 하는 데, 인자의 개수와 순서는 호출된 메서드에 선인된 매개변수와 일치해야 한다.

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

메서드의 실행흐름

서로 호출이 가능하지만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다.

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

long value = add(lL, 2L);
► long value = 3L;
add메서드의 매개변수의 타입이 long이므로 long 또는 long으로 자동 형변환이 가능한 값을 지정해야 한다 . 호출시 매개변수로 지정된값은 메서드의 매개변수로 복사된다. 위의 코드에서는 1L과 2L의 값이 long타입의 매개변수 a와 b에 각각 복사된다.

연산을 수행하고 그 결과를 반환하면서 종료된다. 반환된 값은 대입연산자에 의 해서 변수 value에 저장된다 . 메서드의 결과를 저장하기 위한 변수 value역시 반환값과 같은타입이거나 반환값이 자동 형변환되어 저장될 수 있는 타입이어야 한다.

class MyMathTest {
long add(long a, long b) { 
long result = a+b; 
return result;
// return a + b; // 위의 두 줄을 이와 같이 한 줄로 간단히 할 수 있다. 
}
long subtract (long a, long b) { return a - b; } 
long multiply (long a, long b) { return a * b; } 
double divide(double a, double b) {
  return a/b;
 }
}
4개 의 메서드가 정의되어 있는 MyMath클래스를 이용한 예제이다
divide(double a, double b)를 호출하는 부분이다. divide메 
서드에 선언된 매개변수 타입은 double형인데, 이와 다른 long형의 값인 5L3L을 사용 해서 호줄하는 것이 가능하다.
double result4 = mm.divide ( 5L , 3L ); 
double divide(double a, double b) {
return a / b;
}  

double a = 5L;’을 수행 했을 때와 같이 long형의 값인 5L 은 double형 값인 5.0으로 자동 형변환되어 divide의 매개변수 a에 저장된다.
그래서, divide메서드에 두 개의 정수값(5L, 3L)을 입력하여 호출하였음에도 불구하고 연산결과가 double형의 값이 된다.

3.6 return문

반환타입이 void가 아닌 경우. 즉 반환값이 있는 경우,반드시 return문이 있어야 한다. return문이 없으면 컴파일 에러(error: missing return statement)가 발생한다.

int multiply (int x, int y) { 
int result = x * y;
return result;      // 반환 타입이 void가 아니므로 생략불가 
}
int max (int a, int b) { 
if (a > b)
return a; // 조건식이 참일 때 실행된다. 
else
return b; // 조건식이 거짓일 때 실행된다.
  }

반환값(return value)

매개변수의 유효성 검사
메서드 divide는 매개변수 x를 yS 나눈 결과산 실수(float타입)로 반환
하는데,0으로 나누는 것은 금지되어 있기 때문에 계산 전에 y의 값이 0인지 확인해야 한다. 그래서 y의 값이 0이면, 나누기를 계산할 수 없으므로 return문을 이용해서 작업을 중단하고 메서드를 빠져나와야 한다. 그렇지 않으면, 나누기를 하는 문장에서 프로그램이 비정상적으로 종료된다.

float divide(int x, int y) {
// 작업을 하기전에나누는 수 (y)가 0인지확인한다. 
if(y==0) {
System.out.println (0으로 나눌 수 없습니다.);
return 0; // 매개변수가 유효하지 않으므로 메서드를 종료한다.
}return x / (float)y;
}  

적절하지 않은 값이 매개변수를 통해 넘어온다면 메개변수의 값을 보정하던가,보정하는 것이 불가능하다면 return문을 사용해서 작업을 중단하고 호출한 메서드로 되돌아가야한다.

3.7JVM의 메모리 구조

1. 메서드 영역 (method area)

  • 프로그램 실행 중 어떤 클래스가 사용되면. JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장한다. 이 때. 그 클래스의 클래스변수(class variable)도 이 영역에 함께 생성

2. 힙 (heap)

  • 인스턴스가 생성되는 공간. 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다. 즉, 인스턴스변수(instance variable)이 생성되는 공간

3. 호출스택 (call stack 또는 execution stack)

  • 호출스택은 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면, 호출스택 에 호출된 메서드를 위한 메모리가 할당되며. 이 메모리는 메서드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는데 사용된다. 그리고 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 비워진다.
  • 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다.
  • 메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다.
  • 호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드이다.
  • 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다.

반환타입(return type)이 있는 메서드는 종료되면서 결과값을 자신을 호출한 메서드 (caller)에게 반환한다. 대기상태에 있던 호출한 메서드(caller)는 넘겨받은 반환값으로 수행을 계속 진행하게 된다.

class CallStackTest {
public static void main(String[] args) {
firstMethodO; // static메서드는 객체 생성없이 호출가능하다 . 
}
static void firstMethod () {
secondMetho();
static void secondMetho() {
  System.out.printin ("secondMethod() ");}}

main( )이 firstMothod()를 호출하고 firstMethod()는 secondMethod()를 호출한다. 객체를 생성하지 않고도 메서드를 호출한 수 있으려면, 메서드 앞에 ‘static’을 붙여야 한다.

class CallStackTest2 {
public static void main (String[] args) {
System.out.pr丄ntln ("main (Stringf) args)이 시작되었음. "); 
firstMethod ();
System.out .printin ("main (String[] args)0| 끝났음. ); 
}
static void firstMethod () (
System.out .printin ("firstMethod (》이 시작되었움. "); 
secondMethod();
System.out .printin (^firstMethod () 이 끝났음. "); 
}
static void secondMethod() (
System.out .pr in tin (HsecondMethod()0| 시작되었음.")System.out .printIn ("secondMethod。이 끝났음. ");  
  }
}

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

자바에서는 메서드를 호출할 때 매개변수로 지정한 값을 메서드의 매개변수에 복사해서넘겨준다. 매개변수의 타입이 기본형(primitive type)일 때는 기본형 값이 복사되겠지만,참조형 (reference type)이면 인스턴스의 주소가 복사된다.

기본형 매개변수 변수의 값을 읽기만 할 수 있다.(read only)
참조형 매개변수 변수의 값을 읽고 변경할 수 있다. (read & write)

class Data { int x; }
class PrimitiveParamEx {
public static void main(Str丄ng[】 args) { 
Data d = new Data();
d.x = 10;
System.out.printin("main() : x =+ d.x); 
change(d.x);
System.out.println("After change(d.x)"); 
System.out.println("main() : x = " + d.x);
}
  static void change (int x) {             // 기본형 매개변수 
x = 1000;
System.out.println("change() : x = " + x); 
}

  class Data { int x; }
class ReferenceParamEx {
public static void main(String[] args) { 
Data d = new Data();
d.x = 10;
System.out.printIn("main() : x = " + d.x); 
change(d);
System.out .printin (''After change (d)"); 
System.out.printin(umain() : x = n + d.x);
  }
static void change (Data d) { //참조형 매개변수
  d.x = 1000;
  System.out.println("change():x = " + d.x);
  }}

change메서드률 호출한 후에 d.x의 값이 빈경되었다. change에시드의
매개변수가 참조형이라서 값이 아니라 ‘값이 저장된 주소’를 change메서드에게 남겨주었기 때문에 값을 읽어오는 것뿐만 아니라 변경히는 것도 가능하다.

change메서드의 매개변수를 참조형으로 선언했기 때문에,x의 값이아닌 주소가 매개변수 d에 복사되었다. 이제 main메서드의 참조변수 d와 change메서드의 참조변수 d는 같은 객체를 가리키게 된다. 그래서 매개변수 d로 표의 값을 읽는 것과 변 경하는 것이 모두 가능한 것이다. 이 두 예제를 잘 비교해서 차이를 완전히 이해해야 한다.

class ReferenceParamEx2 {
public static void main(String[] args)
int[] x = {10};        // 크기가 1 인배열. x[0] = 10; 
System.out.printin("main() : x = " + x[0]);
change(x);
System.out.printin("After change(x)n);
System.out.printIn("main()  :  x  =  "  +  x[0]);
  }
static void change (int [] x) ( // 참조형 매개변수 
x[0] = 1000;
System.out.printin("change() : x = " + x[0]); 
  }}

참조형 매개변수 예제를 Data클래스의 인스턴스 대신 길이가 1인 배열 x를 사용 하도록 변경한 것이다. 배열도 객체와 같이 참조변수를 통해 데이터가 저장된 공간에 접근한다는 것을 이미 배웠다. 이전 에제의 Data클래스 타입의 참조변수 선와 같이 변수 x도 int배열타입의 참조변수이 기 때문에 같은 결과를 얻는다.
->예제 6-12

메서드로 배열을 다루는 여러 가지 방법을 보여주는 예제이다. 매개변수의 타입이 배열이니까, 참조형 매개변수이다. 그래서 sortArr메서드에서 정렬한 것이 원래의 배열에 영향을 미친다. 그 외에는 따로 설명하지 않아도 충분히 이해가 될 것이다.
->예제 6-13

class ReturnTest {
public static void main(String[] args) ( 
ReturnTest r = new ReturnTest ();
int result = r.add(3,5); 
System.out.printIn(result);
  
int [] result2 = (0); // 배열올 생성하고 result2[0]의 값을 0으로 초기화 
r.add(3,5,rewult2);//배열을 add메서드의 메게변수로 전달
  system.out.println(result2[0]);
  }
  int add(int a, int b)
  

반환값이 있는 메서드를 반환값이 없는 메서드± T-J- 방법을 보여준다. 앞서 배운 참조형 매개변수를 활용하면 반환값이 없어도 메시, 이행결과를 얻어 올 수 있다.

3.9 참조형 반환타입

매개변수뿐만 아니라 반환타입도 참조형이 될 수 있다. 반환타입 이 참조형 이라는 것은 반 환하는 값의 타입이 참조형이라는 얘긴데,모든 참조형 타입의 값은 ‘객체의 주소’이므로 그저 정수값이 반환되는 것일 뿐 특별할 것이 없다.

class Data { int x; }
class ReferenceReturnEx {
public static void main(String[] args) { 
Data d = new Data();
d.x = 10;
Data d2 = copy(d);
Sys tern, out .print In ("d.x ="+d.x); 
System.out.printin("d2.x="+d2,x);
}
static Data copy(Data d) { 
Data tmp = new Data();
tmp.x = d.x; 
return tmp;}}

copy메서드는 새로운 객체를 생성한 다음에, 매개변수로 넘겨받은 객체에 저장된 값을 복사해서 반환한다. 반환하는 값이 Data객체의 주소이므로 반환 타입이 ‘Data'인 것이다.

3.10 재귀호출(recursive call)

void method() {
method (); // 재귀호출. 메서드 자신을 호출
}

'메서드 호출’이라는 것이 그저 특정 위치에 저장되어 있는 명령들을 수행하는 것일 뿐이기 때문이다.
호출된 메서드는 ‘값에 의한 호출(call by value)’을 통해, 원래의 값이 아닌 복사된 값으 로 작업하기 때문에 호출한 메서드와 관계없이 독립적인 작업수행이 가능하다.

void method(int n) { 
if (n = = 0)
return; // n의 값이 0일 때, 메서드를 종료한다. 
System.out.printIn(n);
method (--n);        // 재귀호출. method (int n) 을 호출 
}

이 코드는 매개변수 n을 1씩 감소시켜가면서 재귀호출을 하다가 n의 값이 0이 되면 재귀 호출을 중단하게 된다

이번엔 ‘factorial(2)’를 호출했을 때의 실행과정을 살펴보자. 매개변수의 값이 1이 아니므 로 조건식이 거짓이 되어 그 다음 문장인 return 2 factorial(l);’이 수행되고,이 식을 계산하는 과정에서 다시 factorial(l)이 호출된다.
① factorial⑵를 호출하면서 매개변수 n에 2가 복사된다.
② ‘return 2
factorial(1);을 계산하려면 factorial(1)을 호출한 결과가 필요하다.
그래서 factorial⑴이 호출되고 매개변수 n에 10| 복사된다.
③ if문의 조건식이 참이므로 1을 반환하면서 메서드는 종료된다. 그리고 factorial(1)을 호출한
곳으로 되돌아간다.
④ 이제 factorial(l)의 결과값인 1을 얻었으므로. ret니이문이 다음의 과정으로 계산된다.
return 2 ★ factorial(1);
return 21;
—♦ return 2;

반복문은 그저 같은 문장을 반복해서 수행히는 것이지만, 메서드를 호출하는 것은 반복문 보다 몇가지과정 ,예를들면 매개변수복사와 종료후 복귀할 주소저장등,이 추가로 원 요하기 때문에 반복문보다 재귀호출의 수행시간이 더 오래 걸린다.

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

메서드 앞에 static이 붙어 있으면 클래스메서드이고 붙어 있지 않으면 인스턴스 메서드이다.
클래스 메서드도 클래스변수처럼,객체를 생성하지 않고도 ‘클래스이름.메서드이름(매개변수)’와 같은 식으로 호출이 가능하다. 반면에 인스턴스 메서드는 반드시 객체를 생성해야만 호출할 수 있다.

인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는 데 인스턴스 변수를 필요로 하는 메서드이다. 그런데 인스턴스 변수는 인스턴스(객체)를 생성해야만 만들어지므로 인스턴스 메서드 역시 인스턴스를 생성해야만 호출할 수 있는 것이다.
반면에 메서드 중에서 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드(static메서드)로 정의한다

  1. 클래스를 설계할 때,멤버변수중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
  2. 클래스 변수(static변수)는 인스턴스를 생성하지 않아도 사용할 수 있다.
  3. 클래스 메서드《static메서드》는 인스턴스 변수를 사용할 수 없다.
  4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면,static을 붙이는 것을 고려한다.메서드의 작업내용 중에서 인스턴스변수를 필요로 한다면,static을 붙일 수 없다. 반대로 인 스턴스변수를 필요로 하지 않는다면 static을 붙이자. 메서드 호출시간이 짧아지므로 성능이향상된다.
  • 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴 보고 있으면, static을 붙여준다.
  • 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려한다.

->예제 6-10

3.12 클래스 멤버와 인스턴스 멤버간의 참조와 호출

  class Testclass {
  void instanceMethodO {} 
static void staticMethod() 
void instanceMethod2() {
instanceMethod(); 
I staticMethodO;
static void staticMethod2() 
instanceMethod(); 
staticMethod();
  } // end of class

같은 클래스 내의 인스턴스 메서드와 static메서드 간의 호출에 대해서 설명
하고 있다. 같은 클래스 내의 메서드는 서로 객체의 생성이나 참조변수 없이 직접 호출이 가능하지만 static메서드는 인스턴스 메서드를 호출할 수 없다.

class TestClass2 {
int iv;
static int cv; // 클래스 변수
void instanceMethodO { 
System.out.println(丄v); 
System.out.printin(cv);
static void staticMethodO { 
Sys tem.out.printin(iv);
System.out.println(cv);}}

->예제 6-20

인스턴스멤버(인스턴스변수와 인스턴스메서드)는 반드시 객체를 생성한후에만
참조 또는 호출이 가능하기 때문에 클래스멤버가 인스턴스멤버를 참조, 호출하기 위해서
는 객체를 생성하여야 한다.
하지만,인스턴스멤버간의 호출에는 아무런 문제가 없다. 하나의 인스턴스멤버가 존재한다는 것은 인스턴스가 이미 생성되어있다는 것을 의미하며, 즉 다른 인스턴스멤버들도모두존재하기 때문이다.

MemberCall c = new MemberCall();
int result = c.instanceMethodl();

->int result = new MemberCall.instanceMethod()

4.오버로딩(overloading)

4.1 오버로딩?

름의 메서드를 여러 개 정의하는 것을 메서드 오버로딩

4.2 오버로딩의 조건

  1. 메서드 이름이 같아야 한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.
    오버로딩된 메서드들은 매개변수에 의해서만 구별될 수 있으므로 반환 타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다는 것에 주의하자.

4.3 오버로딩의 예

실제로는 printin메서드를 호출할 때 매개변수로 지정하는 값의 타입에 따라서
호출되는 printin메서드가 달라진다.
'f(x) = x + r과 'f(a) = a + 1’이 같은 표현인 것과 같다.
컴파일하면,'add(int.int) is already defined(이미 같은 메서드가 정의되었다).’라는 메시지가 나타날 것이다.

int add(int a, int b) { return a+b; }
long add(int a, int b) { return (long) (a + b); }

4.4 오버로딩의 장점
한 클래스내의 모든 메서드들은 이름이 달라야한다. 그렇다면, 이전에 예로 들던 10가지의 printin메서드들은 각기 다 른 이름을 가져야 한다.
예를 들면, 아래와 같은 방식으로 메서드 이름이 변경되어야 할 것이다.

void printin ()
void printlnBoolean(boolean x)
void printlnChar(char x)
void printlnDouble(double x)
void printlnString (String x)
  

기본적으로는 같은 기능을 하는 메서드들이지만, 서로 다른 이름을 가져야 하기 때 문에 메서드를 작성하는 쪽에서는 이름을 짓기도 어렵고. 메서드를 사용하는 쪽에서는 이름을 일일이 구분해서 기억해야하기 때문에 서로 부담이 된다.

4.5 가변인자(varargs)와 오버로딩

가변인자(variable arguments)’라고 한다.
가변인자는 ‘타입… 변수명’과 같은 형식으로 선언하며,PrintStreani클래스의 printf() 가 대표적인 예이다.
public Printstream printf(String format, Object... args) { ... }

가변인자 외에도 매개변수가 더 있다면, 가변인자를 매개변수 중에서 제일 마
지막에 선언해야 한다. 그렇지 않으면,컴파일 에러가 발생한다. 가변인자인지 아닌지를 구별함 방법이 없기 때문에 허용하지 않는 것이다.
// 컴파일 에러발생 - 가변인자는 항상마지막 매개변수이어야한다.
public Printstream printf(Object... args, String format) {
}

이 메서드를 호출할 때는 아래와 같이 인자의 개수를 가변적으로 할 수 있다. 심지어는 인자가 아예 없어도 되고 배열도 인자가 될 수 있다.

System.out.printin(concatenate());
System.out.printin(concatenate("a"));
System.out.printin(concatenate("a" "b"));
System.out .printin (concatenate (new String []{"A","B"}));  

가변인자는 내부적으로 배열을 이용하는 것이다. 그래서 가변인자가 선언된 메서드를 호출할 때마다 배열이 새로 생성된다. 가변 인자가 편리하지만,이런 비효율이 숨어있으므로 꼭 필요한 경우에만 가변인자를 사용하자.
String concatenate(String[] str) { ... }
String result = concatenate (new String[0]); // 인자로 배열을 지정
String result = concatenate (null); // 인자로 null을 지정
String result = concatenate (); // 에러 . 인자가 필요함
매개변수의 타입을 배열로 하면, 반드시 인자를 지정해 줘야하기 때문에, 위의 코드에서 처럼 인자를 생략할 수 없다. 그래서 null이나 길이가 0인 배열을 인자로 지정해줘야 하는 불편함이 있다.

5.생성자

생성자는 인스턴스가생성될 때 호출되는 '인스턴스 초기화 메서드'이다

1.생성자의이름은 클래스의 이르모가 같아야한다.
2.생성자 리턴 값이 없다
생성자는 다음과 같이 정의한다. 생성자도 오버로딩이 가능하므로 하나의 클래스에 여러
개의 생성자가 존재할 수 있다.
클래스이름(타입변수명, 타입변수명, ... ) {
// 인스턴스 생성 시 수행될 코드,
// 주로인스턴스변수의초기화코드틀 적는다.
}

class Card {
Card() {                     // 매개변수가없는생성자. 
}
Card (String k, int num) (                              // 매개변수가 있는생성자.  }}

연산자 new가 인스턴스를 생성하는것이지 생성자가 인스턴스를 생성하는 것이 아니다. 생성자라는 용어 때문에 오해하기 쉬운데. 생성자는 단순히 인스턴스변수들의 초기화에 사용되는 조금 특법한 메서드입 뿐이다. 생성자가 갖는 몇 가시 특징만 제외하면 메서드와 다르지 않다.

Card c = new Card();
1.연산자 new에 의해서 메모리 (heap)에 클래스 인스턴스가 생성된다.
2.생성자 Card가 호출되어 수행된다.
3.연산자 new의결과로 , 생성된 card인스턴스의 주소가 반환되어 참조변수c에 저장된다

5.2 기본 생성자(default constructor)

사실 모든 클래스에는 반드시 하나 이상의 생성자가 정의되어 있어야 한다.
그러나 지금까지 클래스에 생성자를 정의하지 않고도 인스턴스를 생성할 수 있었던 이유는 컴파일러가 제공하는 ‘기본 생성자(default constructor)' 덕분이었다.

클래스이름() { }
Card() { }

인스턴스 초기화 작업이 요구되어지지 않는다면 생성자를 정의하지 않고 컴
파일러가 제공하는 기본 생성자를 사용하는 것도 좋다.

컴파일 하면 위와 같은 에러메시지가 나타난다. 이것은 Data2에서 Data2()라
는 생성자를 찾을 수 없다는 내용의 에러메시지인데, Data2에 생성자 Data2()가 정의되어 있지 않기 때문에 에러가 발생한 것

Data1에는 정의되어 있는 생성자가 하나도 없으므로 컴파일러가 기본 생성자
를 추가해주었지만,Data2에는 이미 생성자 Data2(int x)가 정의되어 있으므로 기본 생성자가추가되지 않았기 때문이다.

Datal dl = new Datal();
Data2 d2 = new Data2 (); // 에러
->

Datal dl = new Datal ();
Data2 d2 = new Data2(10); // OK
Data2의 인스턴스를 생성할 때 생성자 Data2(int x)를 사용하던가,아니면 클래스 Data2에 생성자 Data2()를 추가로 정의해주면 된다.

5.4 생성자에서 다른 생성자 호출하기 - this(), this

  • 생성자의 이름으로 클래스이름 대신 this를 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.
profile
개발 메모창고

0개의 댓글