# JAVA Ch06. 객체지향 프로그래밍1_1

uuuu.jini·2022년 2월 14일
0

JAVA -자바의 정석

목록 보기
5/18
post-thumbnail

목차

  1. 객체지향언어
  2. 클래스와 객체
  3. 변수와 메서드

1. 객체지향언어

1.1] 객체지향언어의 역사

과학자들은 모의실험을 위해 실제 세계와 유사한 가상 세계를 컴퓨터 속에 구현하고자 노력하였으며 이러한 노력은 객체지향이론을 탄생시켰다. 객체지향언어의 기본 개념은 실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물간의 상호작용이다. 라는 것이다. 실제 사물의 속성과 기능을 분석한 다음, 데이터(변수)와 함수로 정의함으로써 실제 세계를 컴퓨터 속에 옮겨 놓은 것과 같은 가상 세계를 구현하고 이 가상세계에서 모의실험을 함으로써 많은 시간과 비용을 절약할 수 있었다.

객체지향이론은 상속,캡슐화,추상화 개념을 중심으로 점차 구쳊거으로 발전되었으며 여러 객체지향언어가 발표되면서 사용자들의 요구가 빠르게 변화해가는 상황을 절차적언어로는 극복하기 어렵다는 한계를 느끼고 객체지향언어를 이용한 개발방법론이 대안으로 떠오르게 되면서 조금씩 입지를 넓혀가고 있었다.

자바가 발표되고 인터넷의 발전과 함께 크게 유행하면서 객체지향언어는 이제 프로그래밍언어의 주류로 자리잡았다.

1.2] 객체지향언어

객체지향의 주요 특징은 다음과 같다.
1. 코드의 재사용성이 높다.
2. 코드의 관리 용이하다.
3. 신뢰성이 높은 프로그래밍을 가능하게 한다.

객체지향언어의 가장 큰 장점은 코드의 재사용성이 높고 유지보수가 용이하다는 것이다. 이러한 장점은 개발과 유지보수에 드는 시간과 비용을 획기적으로 개선하였다.


2. 클래스와 객체

2.1] 클래스와 객체의 정의와 용도

클래스란 객체를 정의해놓은 것 또는 객체의 설계도 또는 틀이라고 정의할 수 있다. 클래스는 객체를 생성하는데 사용하며 객체는 클래스에 정의된 대로 생성된다.

객체는 실제로 존재하는것, 사물 또는 개념 이며 사물과 같은 유형적인 것 뿐만 아니라, 개념이나 논리와 같은 무형적인 것도 객체로 간주한다. (클래스에 정의된 내용대로 메모리에 생성된 것을 뜻한다. ) 객체의 용도는 가지고 있는 기능과 속성에 따라 다르다.

클래스와 객체의 관계를 우리가 살고 있는 실생활에 예를 들면, 제품 설계도와 제품과의 관계라고 할수 있다. ( TV설계도-클래스,TV-객체 )

클래스는 단지 객체를 생성하는데 사용될 뿐, 객체 그 자체는 아니다. 우리가 원하는 기능의 객체를 사용하기 위해서는 클래스로부터 객체를 생성하는 과정이 선행되어야 한다. ( 먼저 클래스 작성 -> 객체를 생성 -> 사용 )

클래스를 사용하는 이융는 객체를 만들기 쉬워지기 때문이다. 즉, 클래스를 한번만 잘 만들어 놓기만 하면, 매번 객체를 생성할 때마다 어떻게 객체를 만들어야 할지 고민하지 않아도 된다. 그냥 생성해서 사용하기만 하면 됨!

JDK에서는 많은 수의 유용한 클래스를 기본적으로 제공하며, 이 클래스들을 이용해서 원하는 기능의 프로그램을 보다 쉽게 작성할 수 있다.

2.2] 객체와 인스턴스

클래스로 부터 객체를 만드는 과정을 클래스의 인스턴스화 라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(Instance)라고 한다.

인스턴스와 객체는 같은 의미이지만 객체는 모든 인스턴스를 대표한느 포괄적인 의미를 갖고있으며, 인스턴스는 어떤 클래스로부터 ㅁ나들어진 것인지를 강조하는 보다 구체적인 의미를 갖고 있다.

2.3] 객체의 구성요소 - 속성과 기능

객체는 속성과 기능 , 두 종류의 구성요소로 이루어져 있으며, 다수의 속성과 다수의 긴으을 갖는다. ( 속성과 기능의 집합이다. ) 객체가 가진 속성과 기능을 그 객체의 멤버라고 한다.

클래스는 객체를 정의한 것이므로 객체의 모든 속성과 기능이 정의되어있다. 클래스로부터 객체를 생성시 클래스에 정의된 모든 속성과 기능을 가진 객체가 만들어지는 것이다. ( 속성 - 멤버변수,특성,필드,상태/ 기능 - 메서드 , 함수, 행위 )

객체지향에서는 속성과 기능을 각각 변수와 메서드로 표현한다. 일반적으로 메서드보다는 변수를 먼저 선언하고 멤버 변수끼리 , 메서드끼리 모아 놓는 것이 일반적이다.

2.4] 인스턴스의 생성과 사용

클래스를 생성한것은 설계도를 작성한것과 마찬가지 이므로 인스터를 생성해야 사용할 수 있다.

	클래스명 변수명;
    변수명 = new 클래스명();

변수명 = new 클래스명(); 실행시 연산자 new에 의해 클래스의 인스턴스가 메모리의 빈공간에 생성된다. 이때, 멤버변수는 각 자료형에 해당하는 기본값으로 초기화 된다. ( 각 멤버변수,메서드의 메모리가 할당됨 ) 그 다음에는 대입연산자(=)에 의해 생성된 객체의 주소값이 참조변수에 저장된다. 이 참조변수를 이용하여 인스턴스에 접근할 수 있다 ( 반드시 필요 )

인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조 변수의 타입은 인스턴스의 타입과 일치해야 한다.

같은 클래스로부터 인스턴스를 생성하면 각 인스턴스의 속성(멤버변수)는 서로 다른 값을 유지할 수 있으며 메서드의 내용은 모든 인스턴스에 대해 동일하다.

참조하지 않는 인스턴스는 더 이상 사용될수 없으므로 가비지 컬렉터 에 의해서 자동적으로 메모리에서 제거된다.

참조변수에는 하나의 값(주소)만이 저장될 수 있으므로 둘 이상의 참조 변수가 하나의 인스턴스를 가리키는 것은 가능하지만 하나의 참조변수가 여러개의 인스턴스를 가리키는 것은 가능하지 않다.

package ch06;

public class TvTest3 {
public static void main(String args[]) {
		Tv t1 = new Tv();
		Tv t2 = new Tv();
		System.out.println("t1의 channel 값은 " + t1.channel);
		System.out.println("t2의 channel 값은 " + t2.channel);
		
		t2 = t1; //t1의 주소값을 t2에 저장한다.
		// t2와 t1은 같은 인스턴스를 가리키게 된다.
		// 기존 t2 인스턴스는 참조한느 변수가 없어지게 되어 사라진다. 
		t1.channel = 7;
		System.out.println("t1의 channel 값은 " + t1.channel);
		System.out.println("t2의 channel 값은 " + t2.channel);
	}
}

2.5] 객체 배열

많은 수의 객체를 다뤄야 할때 배열로 다루는 것이 가능하며 이를 객체 배열 이라고 한다. 객체 배열에는 객체가 직접 저장되는 것이 아닌 객체의 주소가 저장된다. ( 참조 변수들을 하나로 묶은 참조변수배열 인 것이다. )

	클래스[] 배열이름 = new 클래스[ 수 ] ;

참조변수의 기본값은 null이다. 객체 배열을 생성하였으면 객체 배열의 각 요소에 저장하는 것을 잊으면 안된다.

	Tv[] tvArr = new Tv[3];
    tvArr[0] = new Tv();
    tvArr[1] = new Tv();
    tvArr[2] = new Tv();

	Tv[] tvArr = {new Tv(), new Tv(), new Tv() } ;

다뤄야할 객체의 수가 많을 때는 for문을 사용하도록 하자. 모든 배열이 그렇듯 객체배열도 같은 타입의 객체만 저장할 수 있다.

2.6] 클래스의 또 다른 정의

프로그래밍적의 관점에서 클래스의 정의와 의미를 배워보았다.

1. 클래스 - 데이터와 함수의 결합

  • 변수 : 하나의 데이터를 저장할 수 있는 공간
  • 배열 : 같은 종류의 여러 데이터를 하나의 집합으로 저장
  • 구조체 : 서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장
  • 클래스 : 데이터와 함수의 결합(구조체+함수)

그동안 데이터와 함수가 서로 관계가 없는 것처럼 데이터는 데이터끼리 함수는 함쑤끼리 따로 다루어져 왔지만, 사실 함수는 주로 데이터를 가지고 작업을 하기 떄문에 많은 경우에 있어서 데이터와 함수는 관계가 깊다.

그래서 개겣지향언어에서는 변수와 함수를 하나의 클래스에 정의하여 함께 다룰 수 있게 하였다. 즉, 서로 관련된 변수를 정의하고 이들에 대한 작업을 수행하는 함수들을 함꼐 정의한 것이 바로 클래스이다.

2. 클래스 - 사용자정의 타입(user-defined type)

프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것을 사용자정의 타입이라고 한다. 자바같은 경우 클래스가 곧 사용자정의 타입이다.

시간 타입 [ Time ]
시,분,초가 하나의 단위로 묶인 클래스로 시분초는 모두 0보다 크거나 같아야 하며, 시의 범위는 0~23,초의 범위는 0~59이다.


3. 변수와 메서드

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

변수는 클래스변수,인스턴스변수,지역변수 모두 세 종류가 있다. 변수의 종류를 결정짓는 중요한 요소는 변수의 선언된 위치 이다. 멤버변수를 제외한 모든 변수는 지역변수이며 static이 붙은 것은 클래스변수 붙지 않은 것은 인스턴스 변수이다.

각각의 생성시기는 클래스변수는 클래스가 메모리에 올라갈떄, 인스턴스변수는 인스턴스가 생성될떄, 지역변수는 변수 선언문이 수행되었을떄 이다.

1. 인스턴스변수(Instance variable)

클래스 영역에 선언되며 인스턴스가 생성될 떄 만들어진다. 그러므로 인스턴스변수 사용을 이해서는 인스턴스가 생성되어야 한다. ( 인스턴스마다 서로 다른 값을 가질 수 있다. - 고유상태 유지속성시 사용)

2. 클래스변수(class variable)

인스턴스 변수앞에 static을 붙인것으로 클래스가 메모리에 올라갔을 때 생성된다. 클래스변수는 모든 인스턴스가 공통된 저장공간을 공유하게 된다. 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우 사용한다. 인스턴스를 생성하지 않고도 사용이 가능하며 클래스이름.클래스변수와 같은 형태로 사용한다. ( 클래스 메모리에 로딩 시 생성 - 종료까지 유지 / public 붙일시 어디서든 접근 가능 전역변수 )

3. 지역변수 ( local variable )

메서드내에 선언되어 메서드내에서만 사용 가능하며 , 메서드 종료시 소멸되어 사용할 수 없게된다.

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

카드게임을 예로들어 설명한다. 카드 클래스를 작성시 폭,넓이,무늬,숫자의 변수가 있다면 각각 어떤 변수에 해당하는 가

폭과 넓이는 클래스 변수로 모두 공유하며 무늬와 숫자는 인스턴스 변수로 인스턴스마다 서로 다른값을 저장해야 할것이다.

package ch06;


class Card{
	String kind;
	int number;
	static int width = 100;
	static int height = 250;
}

public class CardTest {

	public static void main(String[] args) {
		System.out.println("Card.width : " + Card.width);
		System.out.println("Card.height: " + Card.height);
		
		Card c1 = new Card();
		c1.kind = "Heart";
		c1.number = 7;
		
		Card c2 = new Card();
		c2.kind = "Spade";
		c2.number = 4;
		
		System.out.printf("c1은 %s, %d 이며, 크기는 (%d , %d) %n",c1.kind,c1.number,c1.width,c1.height);
		System.out.printf("c2은 %s, %d 이며, 크기는 (%d , %d) %n",c2.kind,c2.number,c2.width,c2.height);
		
		
		System.out.println("c1의 width 와 height를 각각 50,80으로 변경");
		c1.width = 50;
		c1.height = 80;
		
		System.out.printf("c1은 %s, %d 이며, 크기는 (%d , %d) %n",c1.kind,c1.number,c1.width,c1.height);
		System.out.printf("c2은 %s, %d 이며, 크기는 (%d , %d) %n",c2.kind,c2.number,c2.width,c2.height);
		
	}

}

클래스변수인 width와 height는 인스턴스의 생성없이도 사용이 가능하며 인스턴스인 c1,c2는 클래스변수인 width,height를 공유하므로 한 인스턴스의 변수를 변경하여도 다른 인스턴스의 변수도 함께 변하는 것과 같은 결과를 얻는다. (즉 , c1의 width,height와 c2의 width,height는 모두 동일한 저장공간을 참조한다. )

클래스변수를 사용할 때는 Card.width 와 같이 클래스이름.클래스변수로 사용하는 것이 좋다. 인스턴스변수는 인스턴스가 생성될때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된값을 갖는다.

3.3 ] 메서드

메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다. 어떤 값으로 작업을 수행해서 결과를 반환한다. 메서드에 넣을 값과 반환하는 결과만 알면 내부를 알필요가 없는 블랙박스라고도 한다.

메서드를 사용하는 이유

  1. 높은 재사용성 ( reusability )
    한번 만들어놓은 메서드는 여러번 호출하여 재사용이고 가능하다.

  2. 중복된 코드의 제거
    같은 내용의 문장들이 여러곳에 반복해서 나타나는 것을 메서드를 호출함으로서 한문장으로 대체할 수 있다. 전체소스코드의 길이가 짧아지고 수정해야할 코드의 양이 줄어들어 오류 발생률이 줄어든다.

  3. 프로그램의 구조화
    몇천줄, 몇 만줄이 넘는 프로그램을 작성시에 문장들을 작업단위로 나눠서 여러개의 메서드에 담아 프로그램구조를 단순화 시키는 것이 필수적이다. main메서드는 프로그램의 전체 흐름이 한눈에 들어올 정도로 단순하게 구조화하는 것이 좋다. (문제가 발생해도 쉽게 찾아서 해결 가능 )

3.4 ] 메서드의 선언과 구현

메서드는 크게 선언부(header)구현부(Body) 로 이루어져 있다. 메서드를 정의한다는 것은 선언부와 구현부를 작성하는 것을 뜻한다.

	반환타입 메서드이름 (타입 변수명, 타입 변수명 ... ){ -- 선언부
    // 수행할 코드 -- 구현부
    }

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

메서드의 이름매개변수 선언, 반환타입 으로 구성되어 있다. 메서드가 작업을 수행하기 위해 어떤 타입이 필요하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공한다. 메서드의 선언부는 변경사항이 발생하지 않도록 조심해야 한다. ( 선언부 변경시 모든 호출부분에서 변경이 필요 )

매개변수 선언 ( parameter declaration )

매개변수는 메서드가 작업을 수행하는 데 필요한 값들을 제공받기 위한 것으로 필요한 값의 개수만큼 변수를 선언하며 쉼표로 구분한다. 변수의 타입은 항상 생략이 불가능하다. 선언할 수 있는 매개변수의 수는 제한이 없지만 너무 많은 경우에는 배열이나 참조변수를 사용한다. 아무것도 받지 않는 경우 빈괄호로 작성한다.

메서드의 이름 ( method name )

변수의 명명규칙대로 작성하며 된다. 동사인 경우가 많으며 기능을 쉽게 알수 있도록 함축적이며 의미있는 이름을 짓도록 노력해야 한다.

반환타입(return type)

메서드의 작업수행 결과인 반환값의 타입을 적는다. 없는 경우 void를 적어야 한다.

메서드의 구현부(method body)

메서드의 선언 다음에 오는 괄호{}를 메서드의 구현부 라고 한다. 여기에 메서드 호출시 수행할 모든 작업을 넣는다.

return 문

메서드의 반환타입이 void가 아닌 경우에 구현부 안에 return 반환값 이 반드시 필요하다. 이 값의 타입은 반환타입과 같거나 적어도 형변환이 가능한것이어야 한다. 단 하나의 값만 반환할 수 있다.

지역변수(local varaible)

메서드 내에서 선언된 변수이다. 메서드 내에서만 사용이 가능하다.

3.5 ] 메서드의 호출

메서드를 정의했어도 호출하지않으면 아무일도 일어나지 않는다. 메서드를 호출해야만 구현부{}의 문장들이 수행된다. 메서드이름(값1,값2..) 형식으로 호출한다.

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

메서드 호출시 괄호안에 지정해준 값들을 인자 또는 인수 하고 한다. 호출된 메서드에 선언된 매개변수와 일치해야 한다. 인자는 메서드가 호출되면서 매개변수에 대입되므로 인자의 타입은 매개변수의 타입과 일치하거나 자동 형변환이 가능한 것이어야 한다. (개수가 많지 않거나 타입이 다른 값을 넣으면 컴파일러가 에러륿 발생시킨다. )

메서드의 실행흐름

같은 클래스내의 메서드끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다.

메서드가 호출되면 지금까지 실행 중이던 메서드는 실행을 잠시 멈추고 호출된 메서드의 문장들이 수행된다. 호출된 메서드의 작업이 모두 끝나면, 다시 호출한 메서드로 돌아와 이후의 문장들을 실행한다.

3.6 ] return 문

현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아간다. 원래는 반환값의 유무에 관계없이 모든 메서드에는 적어도 하나의 return문이 있어야 한다. 반환값이 void인 경우 return 문없이 문제가 없었던 이유는 컴파일러가 자동으로 return;을 추가해주기 때문이다.

반환값이 있는 경우에는 반드시 return 문이 있어야하며 없을 경우 컴파일러 에러가 발생한다.

반환값 (return value)

반환값에는 변수만 오는것이 아니라 수식도 올수 있다. 즉 수식을 계산할 결과가 반환되는 것이다.

	int diff(int x, int y){
    	return abs(x-y);
	}

간단한 메서드의 경우 if문 대신 조건연산자를 사용하기도 한다. return x>=0?x:-x;

매개변수의 유효성 검사

메서드의 구현부 작성시 제일 먼저 해야하는 하는 일은 매개변수의 값이 적절한 것인지 확인하는 것이다. 호출하는 쪽에서 적적할 값을 넣어주지 않을 가능성이 있기 떄문이다. 가능한 모든 경우의 수에 대해 고민하고 그에 대비한 코드를 작성해야 한다. 적절하지 않은 값이 매개변수를 통해 넘어온다면 매개변수의 값을 조정해주거나 return 문을 사용해서 작업을 중단하고 호출한 메서드로 되돌아가야한다.

3.7 ] JVM의 메모리 구조

응용프로그램이 실행되면 JVM은 시스텡으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.

1. 메서드 영역 ( method area )

프로그램 실행 중 어던 클래스가 사용되면, JVM은 해당 클래스의 클래스 파일을 읽어서 분석하여 클래스에 대한 정보를 이곳에 저장한다. 클래스의 클래스변수도 이영역에 함꼐 생성된다.

2. 힙 ( head )

인스턴스가 생성되는 공간으로 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다. 인스턴스 변수들이 생성되는 곳이다.

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

메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면 호출스택에 호출된 메서드를 위한 메모리가 할당되며 이 메모리는 메서드가 작업을 수행하는 동안 지역변수들과 연산의 중간결과 등을 저장하는데 사용된다. 작업을 완료시에 할당된 메모리공간은 반환되어 비워진다. 스택이므로 나중에 호출된 메서드가 위의 공간을 차지하게 된다.

  • 호출스택의 특징 :
    메소드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다.
    메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다.
    호출스택의 제일 위에 있는 메서드가 현재 실행중인 메서드이다.
    아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다.

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

객체를 생성하지 않고 메서드를 호출하려면 앞에 static 을 붙여야 한다.

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

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

즉, 기본형으로 선언하면 단순히 저장된 값을 얻지만, 참조형일 경우에는 값이 저장된 곳의 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능하다.

기본형 매개변수참조형 매개변수
변수의 값으 읽기만 할 수 있다.변수의 값을 읽고 변경할 수 있다.
package ch06;
class Data{
	int x;
}
public class ReferenceParamEx {

	public static void main(String[] args) {
		Data d = new Data();
		d.x = 10;
		System.out.println("main() : x = " + d.x);
		
		change(d);
		System.out.println("change() main() : x = "+d.x);
	}
	
	static void change(Data d) {
		d.x = 1000;
		System.out.println("Change() : x = "+d.x);
	}

}

change메서드의 매개변수가 참조형이라서 값이 아니라 값이 저장된 주소 를 change 메서드에 넘겨주었기 떄문에 값을 읽어오는 것뿐만 아니라 변경하는 것도 가능하다. ( change메서드의 참조변수 d가 main 함수의 d와 같은 값을 가리키게 된다. )

배열도 객체와 같이 참조변수를 통해 데이터가 저장된 공간에 접근하므로 매개변수로 값을 변경하는 것이 가능하다.

반환값이 있느 메서드를 반환값이 없는 메서드로 바꾸는 방법

package ch06;
public class ReturnTest {
	public static void main(String[] args) {
		ReturnTest r = new ReturnTest();
		int result1 = r.add(3, 5);
		System.out.println("result1 : "  + result1);		
		int[] result2 = {0};
		r.add(3, 5,result2);
		System.out.println("result2 : " + result2[0]);
	}	
	int add(int a, int b ) {
		return a+b;
	}
	void add(int a, int b , int[] result) {
		result[0] = a+ b;
	}
}

3.9 ] 참조형 반환타입

매개변수 뿐만 아니라 반환타입도 참조형이 될 수 있다. 반환하는 값의 타입이 참조형이라는 말이며 모든 참조형 타입은 객체의 주소 이므로 그저 정수값이 반환되는 것일 뿐 특별한 것이 없다. 반환하는 타입이 참조형변수타입이기 때문에 호출결과를 저장하는 변수의 타입 역시 참조형변수 타입이어야 한다. 반환타입이 참조형이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미한다.

3.10 ] 재귀 호출 ( recursive call )

메서드 내부에서 메서드 자신을 다시 호출하는 것을 재귀호출 이라 하고 재귀호출을 하는 메서드를 재귀 메서드 라고 한다. 메서드 입장에서 자신을 호출하는 것은 다른 메서드를 호출하는 것과 차이가 없다. 그저 특정 위치에 저장되어 있는 명령들을 수행하는 것일 뿐이기 떄문이다.

호출된 메서드는 '값에 의한 호출'을 통해 원래의 값이 아닌 복사된 값으로 작업하기 때문에 호출한 메서드와 관계없이 독립적인 작업수행이 가능하다.

하지만 오로지 재귀호출 뿐이면 무한 호출이 발생할 수 있다. 재귀호출은 조건문이 필수적으로 따라다닌다. 재귀호출은 반복문과 유사한 점이 많으며, 대부분의 재귀호출은 반복문으로 작성하는 것이 가능하다. 반복문보다 재귀호출의 수행시간이 더 오래 걸린다.

왜 굳이 사용하는가 그 이유는 바로 재귀호출이 주는 논리적 간결함 때문이다. 몇 겹의 반복문으로 복잡하게 작성된 코드가 재귀호출을 통해 단순한 구조로 바뀔수 있다.

팩토리얼 예제

f(n) = n * f(n-1) ( 단 n =1 이면 f(1) = 1)

package ch06;

public class FactorialTest {

	public static void main(String[] args) {
		int result = 0;
		
		result = factorial(4);
		System.out.println("result = " + result);
	}
	
	static int factorial(int n) {

		if(n==1) 
			return 1;
		
		return n*factorial(n-1);
	}

}

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

변수에서 그랬던 것과 같이, 메서드 앞에 static 이 붙어 있으면 클래스 메서드이고 붙어 있지 않으면 인스턴스 메서드이다. 클래스 메서드는 객체를 생성하지 않고 클래스이름.클래스메서드(매개변수이름) 로 호출이 가능하다. 반면에 인스턴스 메서드는 객체를 생성해야 지만 사용이 가능하다.

클래스는 데이터(변수)와 데이터에 관련된 메서드의 집합 이므로 , 같은 클래스 내에 있는 메서드와 멤버변수는 아주 밀접한 관계가 있다.

  • 인스턴스 메서드 : 인스턴스 변수와 관련된 작업을 하는 , 즉 메서드의 작업을 수행하는데 인스턴스 변수를 핖요로 하는 메서드 이다.

  • 클래스 메서드 : 인스턴스와 관계없는 ( 인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드(static 메서드) 로 정의한다.

  • 클래스 설계시 멤버 변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다. : 모든 인스턴스에서 값은 값을 유지해야 하는 변수

  • 클래스 변수는 인스턴스를 생성하지 않아도 사용할 수 있다.

  • 클래스 메서드는 인스턴스 변수를 사용할 수 없다. ( 인스턴스 변수는 인스턴스가 존재해야만 사용이 가능하고 클래스메서드는 인스턴스 생성없이 사용이 가능하므로 , 인스턴스 변수나 메서드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능 )

  • 메서드 내에서 인스턴스 변수를 사용하지 않는다면 , static 을 붙이는 것을 고려한다. : 메서드 작업 내에서 인스턴스변수를 필요로 한다면 static을 붙일 수 없다. 반대로, 인스턴스 변수를 항상 필요로 하지않는다면 static을 붙여야 성능이 향상된다.

클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면, static을 붙여준다. 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려한다.

package ch06;

class MyMath2{
	long a,b;
	
	// 인스턴스 변수 a,b만을 사용하므로 매개변수가 필요없다. 
	long add() {
		return a+b;
	}
	long subtract() {
		return a-b;
	}
	long multiply() {
		return a*b;
	}
	double divide() {
		return a/b;
	}
	
	//인스턴스 변수와 관계없이 매개변수만으로 작업이 가능하다.
	static long add(long a, long b) {return a+b;}
	static long subtract(long a, long b) {return a-b;}
	static long multiply(long a, long b) {return a*b;}
	static double divide(long a, long b) {return a/b;}
	
	
}


public class MyMathTest2 {

	public static void main(String[] args) {
		System.out.println(MyMath2.add(200L, 100L));
		System.out.println(MyMath2.subtract(200L,100L));
		System.out.println(MyMath2.multiply(200L,100L));
		System.out.println(MyMath2.divide(200L,100L));
		
		MyMath2 mm = new MyMath2();
		mm.a = 200L;
		mm.b = 100L;
		
		System.out.println(mm.add());
		System.out.println(mm.subtract());
		System.out.println(mm.multiply());
		System.out.println(mm.divide());
		
	}

}

인스턴스 메서드인 add(),subtract(),multiply(),divide()는 인스턴스 변수인 a,b 만으로 충분히 작업이 가능하므로 매개변수를 필요로 하지않아 괄호()에 매개변수를 선언하지 않았다. 반면에 static메서드는 인스턴스변수 없이 매개변수만으로 작업을 수행해야하므로 static을 붙여 클래스메서드로 선언하였다. ( 객체생성없이 메서드호출 가능 )

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

같은 클래스에 속한 멤버들 간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능하다. ( 클래스 멤버가 인스턴스 멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 한다. ) 인스턴스 멤버가 존재하는 순간에는 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 순간에는 인스턴스 멤버가 존재하지 않을 수도 있기 때문이다.

같은 클래스 내의 메서드는 서로 객체의 생성이나 참조변수없이 직접 호출이 가능하지만 static메서드는 인스턴스 메서드를 호출할 수 없다. 동일하게 인스턴스 메서드는 인스턴스 변수를 사용할수 있지만 static메서드는 인스턴스 변수를 사용할 수 없다.

클래스멤버(변수&메서드) 는 언제나 참조 또는 호출이 가능하기 때문에 인스턴스멤버가 클래스멤버를 사용하는 것은 아무런 문제가 안된다. 클래스멤버간의 참조 호출또한 아무런 문제가 없다. 그러나 클래스멤버가 인스턴스 멤버를 참조,호출하기 위해서는 반드시 객체를 생성해야 한다. 인스턴스 멤버간의 호출에는 아무런 문제가 없다. 하나의 인스턴스멤버가 존재한다는 것은 인스턴스가 이미 생성되었다는 것을 의미하므로 다른 인스턴스 멤버들도 모두 존재하기 때문이다.

c = new MemberCall(); 인경우 c.instanceMethod();에서 c대신 new MewmberCall()이 사용 가능하다.
new MemberCall().instaceMethod();

profile
멋쟁이 토마토

0개의 댓글