[JAVA] 객체지향프로그래밍1

2020. 8. 11. 23:09백엔드/JAVA

728x90

1.객체지향언어

1-1. 객체지향언어의 역사

초창기에는 컴퓨터가 주로 과학실험,미사일 발사실험과 같은 모의 실험을 목적으로 사용됨.

객체지향이론의 기본 개념은 '실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물간의 상호작용이다.'라는 것.

객체지향이론은 추상화 개념을 중심으로 점차 구체적으로 발전되었으며 1960년대 중반에 시뮬라(Simula)라는 최초의 객체지향언어가 탄생함.

그 당시 절차적 언어들이 주류를 이루었지만 프로그램의 규모가 점점 커지고 사용자들의 요구가 빠르게 변화해가며 객체지향언어를 이용한 개발방법론이 입지를 넓혀 갔고 자바가 1995년에 발표되고 인터넷의 발전과 함께 객체지향언어는 이제 프로그래밍언어의 주류로 자리 잡음.

1-2. 객체지향언어

  • 언어의 재사용성이 높음

    새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성가능

  • 코드의 관리가 용이

    코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있음

  • 신뢰성이 높은 프로그래밍을 가능하게 함

    제어자와 메서드를 이용해서 데이터를 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오작동을 방지할 수 있음

객체지향언어의 가장 큰 장점은 '코드의 재사용성이 높고 유지보수가 용이하다.'는 것.

앞으로 상속, 다형성과 같은 객체지향개념을 학습할 때 재사용성, 유지보수, 중복된 코드의 제거. 이 세 가지 관점엣 보면 보다 쉽게 이해할 수 있음.

 

 

 


 

2. 클래스와 객체

 

2-1. 클래스와 객체의 정의와 용도

  • 클래스란 객체를 정의해 놓은 것
  • 클래스는 객체를 생성하는 데 사용됨
  • 객체는 실제로 존재하는 것. 사물 또는 개념

클래스를 한 번만 잘 만들어 놓기만 하면, 매번 객체를 생성할 때마다 어떻게 객체를 만들어야 할지를 고민하지 않아도 됨.

JDK(Java Development Kit)에서는 프로그래밍을 위해 많은 수의 유용한 클래스를 기본적으로 제공.

 

2-2. 객체와 인스턴스

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

예를 들면, Tv클래스로부터 만들어진 객체를 Tv클래스의 인스턴스라고 함. 결국 인스턴스는 객체와 같은 의미지만, 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖고 있으며, 인스턴스는 어떤 클래스로부터 만들어진 것인지를 강조하는 보다 구체적인 의미를 갖고 있음.

 

2-3. 객체의 구성요소 - 속성과 기능

객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 다수의 기능을 가짐. 즉, 객체는 속성과 기능의 집합이라고 할 수 있음. 그리고 객체가 가지고 있는 속성과 기능을 그 객체의 멤버(구성원, memeber)라고 함.

클래스란 객체를 정의한 것이므로 클래스에는 객체의 모든 속성과 기능이 정의되어있음. 클래스로부터 객체를 생성하면, 클래스에 정의된 속성과 기능을 가진 객체가 만들어짐.

  • 속성(property) : 멤버(member variable), 특성(attribute), 필드(field), 상태(state)
  • 기능(function) : 메서드(method), 함수(function), 행위(behavior)

객체지향프로그래밍에서는 속성과 기능을 각각 변수와 메서드로 표현함.

 

2-4. 인스턴스의 생성과 사용

2-4-1. 인스턴스(객체)의 생성

클래스명 변수명; //클래스의 객체를 함조하기 위한 참조변수를 선언
변수명 = new 클래스명(); //클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장

Tv t; //Tv클래스 타입의 참조변수 t를 선언
t = new Tv(); //Tv인스턴스를 생성한 후, 생성된 Tv인스턴스의 주소를 t에 저장

  • Tv클래스를 선언한 것은 Tv설계도를 작성한 것에 불과하므로, Tv인스턴스를 생성해야 제품(Tv)을 사용할 수 있음.
  • 객체의 생성은 클래스(설계도)에 작성된 대로 생성되고 , 참조변수는 객체(제품)를 사용하기 위한 리모콘과 같은 역할을 함

2-4-2. 객체의 사용

t.channe; = 7; //Tv인스턴스의 멤버변수 channel의 값을 7로 함
t.channelDown(); //Tv인스턴스의 메서드 channelDown()을 호출함
System.out.println("현재 채널은 " + t.channel + " 입니다.");

2-4-3. 객체의 생성예제

//두 개의 객체를 각각 만들었기 때문에 두개의 객체는 별도의 저장공간을 생성
Tv t1 = new Tv();
Tv t2 = new Tv();
t1.channel = 7;

두개의 객체 생성 예제

 

근데 만약 아래와 같이 코드를 수정한다면?

Tv t1 = new Tv();
Tv t2 = new Tv();
t2 = t1;

참조변수 t1에 있는 주소값을 참조변수 t2에 담았기 때문에 t2가 t1의 주소값이 가리키는 객체를 참조하게 되고 기존에 t2가 참조하던 객체는 자신을 참조하는 객체가 사라졌기 때문에 사용이 불가능하므로 이렇게 사용할 수 없는 메모리는 주기적으로 가비지컬렉터가 없애줌(객체는 참조변수(리모컨)가 없이는 절대 사용 불가능함)

만약 t1.channel = 7로 변경시 t2.channel도 7로 변경됨

하나의 인스턴스를 여러 개의 참조변수가 가리키는 것은 가능하지만,

여러 인스턴스를 하나의 참조변수가 가리키는 것은 불가능함(변수는 '하나의 값'만 저장이 가능함)

 

//235p 예제6-1
package obectOrientedProgramming1;

class Tv {
	//Tv의 속성(멤버변수)
	String color;	//색상
	boolean power;	//전원상태
	int channel;	//채널
	
	//Tv의 기능(메서드)
	void power() {power = !power;}	//Tv를 켜거나 끄는 기능을 하는 메서드
	void channelUp() {++channel;}	//Tv의 채널을 높이는 기능을 하는 메서드
	void channelDown() {--channel;}//Tv의 채널을 낮추는 기능을 하는 메서
}

class TvTest {
	public static void main(String[] args) {
		Tv t;	//인스턴스를 참조하기 위한 변수
		t = new Tv(); //Tv인스턴스를 생성
		t.channel = 7; //Tv인스턴스의 멤버변수
		t.channelDown(); //Tv인스턴스의 멤버변수 channel의 값을 7로 함
		System.out.println("현재 채널은 "+t.channel+" 입니다.");
	}
}

이 예제는 Tv클래스로부터 인스턴스를 생성하고 인스턴스의 속성(channel)과 메서드(channelDown)를 사용하는 방법을 보여줌.

  1. Tv t;

    클래스 타입의 참조변수 t를 선언. 메모리에 참조변수 t를 위한 공간이 마련됨. 아직 인스턴스가 생성되지 않았으므로 참조변수로 아무것도 할 수 없음.

  2. t = new Tv();

    연산자 new에 의해 Tv클래스의 인스턴스가 메모리의 빈 공간에 생성됨. 주소가 0x100인 곳에 생성되었다고 가정할 때, 멤버변수는 각 자료형에 해당하는 기본값으로 초기화 됨. color는 참조형이므로 null로 power는 boolean이므로 false로, 그리고 channel은 int이므로 0으로 초기화 됨.

    그 다음에는 대입연산자(=)에 의해서 생성된 객체의 주소값이 참조변수 t에 저장됨. 이제는 참조변수 t를 통해 Tv인스턴스에 접근할 수 있음

    (인스턴스를 다루기 위해서는 참조변수가 반드시 필요)

  3. t.channel = 7;

    참조변수 t에 저장된 주소에 있는 인스턴스의 멤버변수 channel에 7을 저장. 여기서 알 수 있듯이 인스턴스의 멤버변수(속성)을 사용하려면 '참조변수.멤버변수'와 같이 하면 됨

  4. t.channelDown();

    참조변수 t가 참조하고 있는 Tv인스턴스의 channelDown메서드를 호출. channelDown메서드는 멤버변수 channel에 저장되어 있는 값을 1 감소시킴.

  5. System.out.println("현재 채널은 " +t.channel+ " 입니다.");

    참조변수 t가 참조하고 있는 Tv인스턴스의 멤버변수 channel에 저장되어 있는 값을 출력함. 현재 channel의 값은 6이므로 '현재 채널은 6 입니다'가 화면에 출력됨

인스턴스와 참조변수의 관계는 마치 우리가 일상생활에서 사용하는 Tv와 Tv리모콘의 관계와 같음. Tv리모콘(참조변수)을 사용하여 Tv(인스턴스)를 다루기 때문. 다른 점이라면, 인스턴스는 오직 참조변수를 통해서만 다룰 수 있다는 것.

그리고 Tv를 사용하려면 Tv리모콘을 사용해야하고, 에어콘을 사용하려면, 에어콘 리모콘을 사용해야 하는 것처럼 Tv인스턴스를 사용하려면, Tv클래스 타입의 참조변수가 필요한 것.

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

 

//237p 예제6-2
package obectOrientedProgramming1;

class Tv {
	//Tv의 속성(멤버변수)
	String color;	//색상
	boolean power;	//전원상태
	int channel;	//채널
	
	//Tv의 기능(메서드)
	void power() {power = !power;}	//Tv를 켜거나 끄는 기능을 하는 메서드
	void channelUp() {++channel;}	//Tv의 채널을 높이는 기능을 하는 메서드
	void channelDown() {--channel;}//Tv의 채널을 낮추는 기능을 하는 메서
}

class TvTest {
	public static void main(String[] args) {
		
		Tv t1 = new Tv();
		Tv t2 = new Tv();
		System.out.println("t1의 channel값은 "+ t1.channel + "입니다.");
		System.out.println("t1의 channel값은 "+ t2.channel + "입니다.");
		
		t1.channel = 7; //channel의 값을 7로 한다.
		System.out.println("t1의 channel값을 7로 변경하였습니다.");
		
		System.out.println("t1의 channel값은 "+ t1.channel + "입니다.");
		System.out.println("t2의 channel값은 "+ t2.channel + "입니다.");
		
	}
}

 

위의 예제는 Tv클래스의 인스턴스 t1과 t2를 생성한 후에, 인스턴스 t1의 멤버변수인 channel의 값을 변경

 

package obectOrientedProgramming1;

class Tv {
	//Tv의 속성(멤버변수)
	String color;	//색상
	boolean power;	//전원상태
	int channel;	//채널
	
	//Tv의 기능(메서드)
	void power() {power = !power;}	//Tv를 켜거나 끄는 기능을 하는 메서드
	void channelUp() {++channel;}	//Tv의 채널을 높이는 기능을 하는 메서드
	void channelDown() {--channel;}//Tv의 채널을 낮추는 기능을 하는 메서
}

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

		//238p 예제6-3
		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에 저장
		t1.channel = 7; //channel의 값을 7로 함
		System.out.println("t1의 channel의 값은 " + t1.channel + "입니다.");
		System.out.println("t2의 channel의 값은 " + t2.channel + "입니다.");
		
	}
}

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

 

2-5. 객체배열

많은 수의 객체를 다뤄야할 때, 배열로 다루면 편리하듯이 객체 역시 배열로 다루는 것이 가능하며, 이를 '객체 배열'이라고 함. 그렇다고 객체 배열 안에 객체가 저장되는 것은 아니고, 객체의 주소가 저장됨. 사실 객체 배열은 참조변수들을 하나로 묶은 참조변수 배열인 것. (객체배열 == 참조변수배열)

 

// 1.길이가 3인 Tv타입의 참조변수 배열 생성

Tv[] tvArr = new Tv[3]; //각 요소는 참조변수의 기본값인 null로 초기화됨



// 2.객체를 생성해서 배열의 각 요소에 저장

tvArr[0] = new Tv();

tvArr[1] = new Tv();

tvArr[2] = new Tv();



//(1번) 단순히 객체를 다루기 위한 참조변수들이 만들어진 것(아직 객체가 저장되지 않은상태. 객체 사용불가)

//(2번) 객체를 생성해서 객체 배열의 각 요소에 저장하는 과정

//2번의 과정을 거쳐야 각 객체를 사용이 가능함



// 1번과 2번을 한번에 작성

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

 

 

 

길이가 3인 객체 배열 tvArr을 아래와 같이 생성하면, 각 요소는 참조변수의 기본값인 null로 자동 초기화 됨.

package obectOrientedProgramming1;

public class TvTest4 {

	public static void main(String[] args) {
		Tv[] tvArr = new Tv[3];
		for(Tv a : tvArr) {
			System.out.println(a);
		}

	}

}

 

그리고 이 객체 배열은 3개의 객체, 정확히는 객체의 주소를 저장할 수 있음.

객체 배열을 생성하는 것은, 그저 객체를 다루기 위한 참조변수들이 만들어진 것일 뿐, 아직 객체가 저장되지 않은 상태임. 객체를 생성해서 객체 배열의 각 요소에 저장하는 것을 잊으면 안됨.

모든 배열이 그렇듯이 객체 배열도 같은 타입의 객체만 저장할 수 있음.

//객체를 생성해서 객체 배열의 각 요소에 저장하는 방법1
		Tv[] tvArr1 = new Tv[3];
		tvArr1[0] = new Tv();
		tvArr1[1] = new Tv();
		tvArr1[2] = new Tv();

		//객체를 생성해서 객체 배열의 각 요소에 저장하는 방법2
		Tv[] tvArr2 = new Tv[3];
		for(Tv a : tvArr2) {
			a = new Tv();
		}	
		
		//객체를 생성해서 객체 배열의 각 요소에 저장하는 방법3
		Tv[] tvArr3 = {new Tv(), new Tv(), new Tv()};
package obectOrientedProgramming1;

public class TvTest4 {

	public static void main(String[] args) {
		
		//242p 예제6-4
		Tv[] tvArr = new Tv[3]; //길이가 3인 Tv객체 배열
		
		//Tv객체를 생성해서 Tv객체배열의 각 요소에 저장
		for(int i=0; i<tvArr.length; i++) {
			tvArr[i] = new Tv();
			tvArr[i].channel = i+10; //tvArr[i]의 channel에 i+10을 저장
		}
		
		for(int i=0; i<tvArr.length; i++) {
			tvArr[i].channelUp();
			System.out.println(tvArr[i].channel);

		}
	}

}

 

2-6. 클래스의 또 다른 정의

2-6-1. 클래스

  • 설계도
  • 데이터와 함수의 결합
  • 사용자정의타입

클래스는 '객체를 생성하기 위한 틀'이며 '클래스는 속성과 기능으로 정의되어 있다.'라고 함. 이것은 객체지향이론의 관점에서 내린 정의이고, 이번엔 프로그래밍적인 관점에서 클래스의 정의와 의미를 살펴보고자 함

 

2-6-2. 데이터와 함수의 결합

프로그래밍언어에서 데이터 처리를 위한 데이터 저장형태의 발전과정은 다음과 같음.

변수 —————————> 배열 —————————> 구조체 —————————> 클래스

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

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

그래서 자바와 같은 객체지향언어에서는 변수(데이터)와 함수를 하나의 클래스에 정의하여, 서로 관계가 깊은 변수와 함수들을 함께 다룰 수 있게 함.

서로 관련된 변수들을 정의하고 이들에 대한 작업을 수행하는 함수들을 함께 정의하는 것이 바로 클래스인 것.

C언어에서는 문자열을 문자의 배열로 다루지만, 자바에서는 String이라는 클래스로 문자열을 다룸.

문자열을 단순히 문자의 배열로 정의하지 않고 클래스로 정의한 이유는 문자열과 문자열을 다루는 함수들을 함께 묶기 위해서임

 

2-6-3. 사용자정의 타입(user-defined type)

프로그래밍언어에서 제공하는 자료형(primitive type)외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것을 사용자정의 타입(user-defined type)이라고 함.

다른 프로그래밍언어에서도 사용자정의 타입을 정의할 수 있는 방법을 제공하고 있으며 자바와 같은 객체지향언어에서는 클래스가 곧 사용자 정의 타입임. 기본형의 개수는 8개로 정해져 있지만 참조형의 개수가 정해져 있지 않은 이유는 이처럼 프로그래머가 새로운 타입을 추가할 수 있기 때문.

package obectOrientedProgramming1;

public class Time {
	
	private int hour;
	private int minute;
	private float second;
	
	public int getHour() { return hour; }
	public int getMinute() { return minute; }
	public float getSecond() { return second; }

	public void setHour(int h) {
		if(0<h || h>23) return;
		hour = h;
	}
	
	public void setMinute(int m) {
		if(0<m || m>59) return;
		minute = m;
	}
	
	public void setSecond(float s) {
		if(0.0f<s || s>59.9f) return;
		second = s;
	}

 

 

2-7. 클래스 작성방법

 

하나의 소스파일에 여러 클래스 작성시

 

-올바른 작성

public클래스가 있을 경우 : 'public' 이 붙은 클래스와 '소스파일명'이 일치해야함

public클래스가 없을 경우 : 두개의 클래스가 작성되어 있다고 가정하면, 두개의 클래스명 중 하나와 '소스파일명'이 일치해야함

 

-잘못된 작성

하나의 소스파일에 둘 이상의 public class가 존재하면 안됨

소스파일의 이름이 public class의 이름과 일치하지 않는 경우

소스파일의 이름과 publc class의 이름이 일치하지 않는경우

 

 


3. 변수와 메서드

 

3-1. 선언위치에 따른 변수의 종류

클래스에 정의된 영역을 두 가지영역으로 볼 수 있음

클래스영역  : 선언문만 가능, 선언문의 순서는 상관없음(일반적으로는 변수선언이 먼저)

  •    인스턴스변수(iv)
  •    클래스변수(cv) : 앞에 'static'이 붙은 변수

메서드영역

  •    지역변수

클래스변수(cv) : 클래스가 메모리에 올라갈 때 클래스변수가 생성됨 ( 객체생성 필요없음 , 아무때나 사용가능)

인스턴스변수(lv) : 인스턴스가 생성되었을 때 인스턴스변수가 생성됨(객체(인스턴스)는 인스턴스변수를 묶어놓은것)

지역변수(iv) : 메서드 내의 영역에서만 사용가능

 

 

3-2. 클래스변수와 인스턴스변수

객체의 속성 중에 공통 속성 -> 클래스변수 사용

객체의 속성 중에 개별 속성 -> 인스턴스변수 사용

 

  • 인스턴스변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 가짐
  • 클래스변수는 '클래스이름.변수명'으로 사용('객체.변수명'으로 사용 가능하지만 인스턴스변수와 혼동될 수 있음)
  • 인스턴스변수는 '객체.변수명'으로 사용
package com.java.oop1;

//예제6-5. 248p
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.println("c1의 kind는 "+c1.kind+", number는 " +c1.number+", width는 "+c1.width+", height는 "+c1.height+"입니다.");
		System.out.println("c2의 kind는 "+c2.kind+", number는 " +c2.number+", width는 "+c2.width+", height는 "+c2.height+"입니다.");
		
        //클래스변수
		//c1.width = 50; // '객체.변수명'으로 클래스변수를 변경할 경우 클래스변수인지 인스턴스변수인지 혼돈될수 있음
		//c1.height = 80;
        Card.width = 50; //클래스변수는 '클래스.변수명'으로 사용하는 것이 바람직함
        Card.height = 80;
		
		System.out.println("c1의 kind는 "+c1.kind+", number는 " +c1.number+", width는 "+c1.width+", height는 "+c1.height+"입니다.");
		System.out.println("c2의 kind는 "+c2.kind+", number는 " +c2.number+", width는 "+c2.width+", height는 "+c2.height+"입니다.");

	}

}

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

 

 

3-3. 메서드

 

메서드란?

문장들을 묶어놓은 것 (작업단위로 문장들을 묶어서 이름 붙인 것)

값(입력)을 받아서 처리하고, 결과를 반환(출력)

메서드(클래스안에 있어야함) 는 객체지향개념에서 함수(클래스에 독립적)를 지칭하는 용어라고 생각하면됨

 

메서드의 장점

코드의 중복을 줄일 수 있음(코드중복제거)

관리 용이

재사용 가능

 

메서드의 작성

반복적으로 수행되는 여러 문장을 메서드로 작성

하나의 메서드는 한 가지 기능만 수행하도록 작성

 

메서드 = 선언부 + 구현부

매개변수(타입 변수명)는 작업에 필요한 값들인데 여러개일 수도 있고 한 개도 없을 수도 있음(0개 ~n개)

반환타입은 작업결과의 타입을 의미 / 출력값 (0개(반환타입:void) ~ 1개 )

*만약 작업결과가 여러 개라면 배열객체로 묶어서 반환할 수 있음

 

지역변수(lv)

메서드 내에 선언된 변수

메서드 영역에서만 유효함(여러 메서드에서 같은 이름의 변수가 있어도 가능->각각의 메서드 내에서만 유효하기 때문)

메서드 정의 시 괄호안의 값을 '매개변수(parameter,복사본)'라고 함

매개변수도 지역변수에 속함 

 

 

3-4. 메서드의 호출

메서드를 호출하는 방법

메서드이름(값1, 값2, ...);  

메서드 호출시 괄호안의 값을 '인자( argument,원본)'이라고 함

작업결과가 없을 경우는 변수에 따로 담을 필요 없지만, 작업결과(반환값)이 있을 경우 주로 변수에 담아서 사용함 (변수에 담지 않는다고 에러가 발생하진 않지만 작업결과를 활용하기 위해서는 필요)

 

 

메서드의 실행흐름

 

3-5. return문

return문

  • 실행 중인 메서드를 종료하고 호출한 곳으로 되돌아감
  • 반환타입이 void가 아닌 경우를 제외하고(void인 경우도 원칙상으로는 return문이 있어야 하지만 생략되는것임) , 반드시 return문 필요함(조건문 사용시 주의해야함. 참이던 거짓이던 return문이 실행될 수 있도록 작성해야함.)          

3-6. 호출스택(call stack)

 

스택(stack) 

밑이 막힌 상자 위에 차곡차곡 쌓임

 

 

호출스택

메서드 수행에 필요한 메모리가 제공되는 공간

메서드가 호출되면 호출스택에 메모리 할당되고 종료되면 해제됨

아래에 있는 메서드가 위의 메서드를 호출한 것

맨 위의 메서드 하나만 실행되고 나머지 메서드는 대기중

*thread는 thread마다 스택을 하나씩 가지고 있기 때문에 멀티쓰레드 프로그래밍을 하면 스택이 여러개가 생길 수 있지만, 여기선 싱글쓰레드라고 가정하여 스택이 한 개인 상태라고 보면 됨(하나의 스택에서는 한 개의 메서드만 실행되고 나머지 메서드는 대기상태임)

 

 

3-7. 기본형 매개변수와 참조형 매개변수

기본형 매개변수 : 변수의 값을 읽기만 할 수 있음(read only)

참조형 매개변수 : 변수의 값을 읽고 변경할 수 있음 (read & write)

 

package com.java.oop1;

//참조형 반환타입
public class ReferenceReturn {

	public static void main(String[] args) {
		Data3 d = new Data3();
		d.x = 10;
		
		Data3 d2 = copy(d); //static메서드이기도하고 같은 클래스내에 있어서 참조변수 없이도 호출가능
		System.out.println("(1)d.x = " + d.x);	 //10
		System.out.println("(1)d2.x = " + d2.x); //10
		
		d2.x = 30;
		System.out.println("(2)d.x = " + d.x);   //10
		System.out.println("(2)d2.x = " + d2.x); //30
	}
	
    //static메서드는 객체생성없이 호출가능
	static Data3 copy(Data3 d) {
		Data3 tmp = new Data3();	//새로운 객체 tmp를 생성
		tmp.x = d.x;				//d.x의 값을 tmp.x에 복사
		return tmp;					//복사한 객체의 주소를 반환
	}
}

class Data3 {int x;}

 

3-8. 인스턴스메서드와 static메서드

인스턴스 메서드 

  • 앞에 static이 붙지 않은 메서드
  • 인스턴스 생성 후, '참조변수.메서드이름()'으로 호출
  • 인스턴스 멤버(iv, im)와 관련된 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용가능

static메서드 

  • 앞에 static이 붙은 메서드
  • 객체생성없이 '클래스이름.메서드이름()'으로 호출
  • 인스턴스 멤버(iv, im)와 관련없는 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용불가

static을 언제 붙여야 할까?

  • 속성(멤버변수) 중에서 공통 속성에 static을 붙임
  • 인스턴스 멤버(iv, im)을 사용하지 않는 메서드(명령문집합)에 static을 붙임 
class MyMath2{
	long a, b; //인스턴스변수(iv)
    
    long add(){ //인스턴스메서드(인스턴스변수 사용)
    	return a + b; //인스턴스변수
    }
    
    static long add(long a, long b){//클래스메서드/staic메서드(인스턴스변수 사용하지 않음)
    	return a + b; //지역변수(lv)
    }
}

class MyMathTest2{
	public static void main(String args[]){
    	System.out.println(MyMath2.add(200L,100L); //클래스메서드 호출(클래스이름.메서드이름())
        MyMath2 mm = new MyMath2();	 //인스턴스 생성
        mm.a = 200L;
        mm.b = 100L;
        System.out.println(mm.add()); //인스턴스메서드 호출(참조변수.메서드이름())
   }
}

인스턴스메서드는 인스턴스변수를 사용하므로 매개변수를 사용하지 않고 메서드 정의

인스턴스메서드는 인스턴스변수를 사용하므로 객체를 생성해야 호출가능(참조변수.메서드이름()) 

클래스메서드는 인스턴스변수를 사용하지 않고 매개변수(지역변수)를 사용해서 메서드를 정의

클래스메서드는 인스턴스변수를 사용하지 않기 때문에 객체생성없이 메서드호출가능(클래스변수.메서드이름())

*객체는 인스턴스변수의 묶음

인스턴스메서드와 static메서드의 가장 큰 차이는 인스턴스변수를 사용하는지 사용하지 않는지로 판단할 수 있음

 

메서드 간의 호출과 참조

  • static메서드는 인스턴스 변수(iv)를 사용할 수 없음 (static메서드는 객체생성 없이 호출 가능(헝성 호출가능)하지만 인스턴스 변수는 객체생성해야만 호출할 수 있기 때문에 static메서드 호출 시 객체 생성되어 있다는 보장이 없기 때문에 static메서드는 인스턴스 변수를 사용할 수 없음)
class TestClass2{
	int iv; //인스턴스 변수
    static int cv; //클래스 변수
    
    void instanceMethod(){ //인스턴스 메서드
    	System.out.println(iv); //인스턴스변수를 사용할 수 있음
        System.out.println(cv); //클래스변수를 사용할 수 있음
    }
    
    static void staticMethod(){ //클래스메서드/static메서드
    	System.out.println(iv); //에러!!인스턴스변수를 사용할 수 없음
        System.out.println(cv); //클래스변수는 사용할 수 있음
    }
 }
  • static메서드는 인스턴스 메서드(im)를 호출할 수 없음
class TestClass{
	void instanceMethod(){} //인스턴스메서드
    static void staticMethod(){} //static메서드
    
    void instanceMethod2(){ //인스턴스메서드
    	instanceMethod(); //다른 인스턴스메서드를 호출가능
        staticMethod(); //static메서드를 호출가능
    }
    
    staic void staticMethod2(){ //static메서드
    	instanceMethod(); //에러발생!! 인스턴스메서드를 호출할 수 없음
   		staicMethod(); //static메서드는 호출가능
    }
}

 


4. 오버로딩(overloading)

4-1. (메서드)오버로딩(overloading)

오버로딩 : 한 클래스 안에 같은 이름의 메서드 여러 개를 정의 

대표적인 예) void println(), void println(boolean x), void println(char x), void println(char[] x), void println(double x),...

만약 오버로딩이 존재하지 않는다면 , 메서드 이름이 모두 달라야하므로 외우기도 어렵고, 오타치기도 쉽고 어려움이 많음

*자바에서는 메서드오버로딩만 구현가능하기 때문에 그냥 오버로딩이라고 함

(연산자 오버로딩은 기능을 제공은 하지만 이미 구현되어있는 것을 사용 (예)'+'연산자 -> 부호,덧셈,문자열결합)

 

4-1-1. 오버로딩이 성립하기 위한 조건

  • 메서드 이름이 같아야 함
  • 매개변수의 개수 또는 타입이 달라야 함
  • 반환 타입은 영향이 없음
//오버로딩이 성립하디 않는 예1 -> 중복정의
//add(int,int) is already defined 
int add(int a, int b){return a+b;}
int add(int x, int y){return x+y;}

//오버로딩이 성립하디 않는 예2 -> 중복정의
//add(int,int) is already defined 
int add(int a, int b){return a+b;}
int add(int a, int b){return (long)(a+b);}

//오버로딩이 성립하는 예
long add(int a, long b) {return a+b;}
long add(long a, int b) {return a+b;}
//만약 add(3,3);이라고 호출 시 컴퓨터가 판단 불가능->에러발생(ambigouous,모호한)
//add(3,3L);-> 올바른 호출(첫번째)
//add(3L,3);->올바른 호출(두번째)

 

4-1-2. 오버로딩의 올바른 예 - 매개변수는 다르지만 같은 의미의 기능수행

class MyMath3{
	int add(int a, int b){
    	System.out.print("int add(int a,int b)");
        return a+b;
     }
     
     long add(long a, long b){
     	System.out.print("long a,long b)");
        return a+b;
     }
     
     int add(int[] a){
     	System.out.print("int[] a)");
        int result = 0;
        for(int i=0; i<a.length; i++){
        	result += a[i];
            return result;
      }
 }

 

 

 


 

5. 생성자(contructor)

5-1. 생성자(contructor)

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

인스턴스 생성시 수행할 작업(iv 초기화)에 사용 -> 편리

 

Time t = new Time(); //생성자 호출(기본생성자)
t.hour = 12;  //변수 초기화
t.minute = 34;//변수 초기화
t.second = 56;//변수 초기화

Time t = new Time(12,34,56); //생성자 호출하면서 변수 초기화(직접 생성자 추가해야함)

 

5-1-1. 생성자 특징

  • 이름이 클래스 이름과 같아야 함
  • 리턴값이 없음(void 안붙임) -> 생성자는 무조건 반환값이 없으므로 생략
  • 모든 클래스는 반드시 생성자를 가져야 함(기본생성자는 생략가능 컴파일러가 클래스 내에 생성자가 하나도 없을경우 자동으로 기본생성자를 생성해줌)
class Card { //클래스 이름

    //생성자 오버로딩
    Card(){ //매개변수 없는 생성자 
    	//인스턴스 초기화 작업
    }
    
    //생성자 오버로딩
    Card(String kind, int number) {//매개변수 있는 생성자
    	//인스턴스 초기화 작업
     }
 }
    

 

5-2. 기본 생성자(default contructor)

  • 매개변수가 없는 생성자
  • 생성자가 하나도 없을 때만 컴파일러가 자동 추가(그래도 왠만하면 기본생성자를 반드시 작성해주는게 좋음)
package com.java.oop1;

//예제 6-11
class Data_1{
	int value;
}

class Data_2{
	int value;
	
	Data_2(int x){ //매개변수가 있는 생성자
		value = x;
	}
}
public class Ex6_11 {

	public static void main(String[] args) {
		Data_1 d1 = new Data_1();//Data_1클래스에는 생성자가 하나도 없으므로 컴파일러가 기본생성자 자동 추가됨
		Data_2 d2 = new Data_2(); //compile error발생(Data_2클래스에는 이미 매개변수가 있는 생성자가 있으므로)
	}

}

 

 

5-3. 매개변수가 있는 생성자

 

5-4. 생성자에서 다른  생성자 호출 - this(), this

생성자의 이름으로 클래스이름 대신 this를 사용

한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능함

 

package com.java.oop1;

//예제6-25 296p
class Car {
	String color; //색상
	String gearType; //변속기 종류 - auto(자동), manual(수동)
	int door;	//문의 개수
	
	Car(){
		this("white","auto",4);//Car(String color, String gearType, int door) 호출
	}
	
	Car(String color){
		this(color, "auto", 4); //Car(String color, String gearType, int door) 호출 
	}
	
	Car(String color, String gearType, int door){
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}
}

public class CarTest2 {
	public static void main(String[] args) {
		Car c1 = new Car();
		Car c2 = new Car("blue");
		
		System.out.println("c1의 color는 " + c1.color + " c1의 gearType은 " + c1.gearType + " c1의 door는 " + c1.door + " 입니다.");
		System.out.println("c2의 color는 " + c2.color + " c2의 gearType은 " + c2.gearType + " c2의 door는 " + c2.door + " 입니다.");		
	}
}

생성자 Car()에서 또 다른 생성자 Car(String color, String gearType, int door)를 호출하였는데 생성자간의 호출에는 생성자 이름 개신 this를 사용해야만 하므로 'Car' 대신 'this'를 사용하였고, Car()의 첫째 줄에서 호출함

 

위의 코드를 실생활에서 대입 해보면, 자동차를 생산할 때 아무런 옵션도 주지 않으면, 기본적으로 흰색(white)에 자동변속기어(auto) 그리고 문의 개수가 4개인 자동차가 생산되도록 하는 것에 비유할 수 있음

 

같은 클래스 내의 생성자들은 일반적으로 서로 관계가 깊은 경우가 많아서 서로 호출하도록 유기적으로 연결해주면 더 좋은 코드를 얻을 수 있음

 

위의 코드에서 Car(String color, String gearType, int door) 생성자가 정의된 부분을 살펴보면 인스턴스변수 앞에 'this'를 사용하였는데, 이는 매개변수로 선언된 변수의 이름이 인스턴스 변수의 이름과 같은 경우 이름만으로 구분이 안되기 때문에 인스턴스 변수 앞에 'this'를 사용하여 왼쪽의 인스턴스변수와 오른쪽의 매개변수로 지정된 지역변수로 서로 구별이 가능함. 이렇게 'this'를 사용해서 구별되도록 하는것이 매개변수의 이름을 다르게 하는 것보다 더 의미가 명확하고 이해하기 쉬움

'this'는 참조변수로 인스턴스 자신을 가리키는데 참조변수를 통해 인스턴스의 멤버에 접근할 수 있는 것처럼, this로 인스턴스변수에 접근할 수 있음 

하지만, 'this'를 사용할 수 있는 것은 인스턴스멤버뿐이고 static메서드(클래스 메서드)에서는 인스턴스 멤버들을 사용할 수 없는 것처럼, 'this'역시 사용 불가능함

왜냐하면 static메서드는 인스턴스를 생성하지 않고도 호출될 수 있으므로 static메서드가 호출된 시점에 인스턴스가 존재하지 않을 수도 있기 때문

 

사실 생성자를 포함한 모든 인스턴스메서드에는 자신이 관련된 인스턴스를 가리키는 참조변수 'this'가 지역변수로 숨겨진 채로 존재함

 

  • this : 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있음. 모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재
  • this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용

 

 

5-5. 생성자를 이용한 인스턴스의 복사

package com.java.oop1;

//예제6-26 298p
class Car3{
	String color; //색상
	String gearType; //변속기 종류 - auto(자동), manual(수동)
	int door; //문
	
	Car3(){
		this("white", "auto", 4);
	}
	
	Car3(Car3 c){
		color = c.color;
		gearType = c.gearType;
		door = c.door;
	}
	
	Car3(String color, String gearType, int door){
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}
}

public class CarTest3 {

	public static void main(String[] args) {
		
		Car3 c = new Car3();
		Car3 c2  = new Car3("blue", "manual", 2);
		Car3 c3 = new Car3(c2);

		System.out.println("c의 color는 " + c.color + " c의 gearType은 "+ c.gearType + " c의 door는 "+ c.door + "입니다.");
		System.out.println("c2의 color는 " + c2.color + " c2의 gearType은 "+ c2.gearType + " c2의 door는 "+ c2.door + "입니다.");
		System.out.println("c3의 color는 " + c3.color + " c3의 gearType은 "+ c3.gearType + " c3의 door는 "+ c3.door + "입니다.");
	}

}

 

인스턴스를 생성할 때의 2가지 결정사항

  • 클래스 : 어떤 클래스의 인스턴스를 생성할 것인가?
  • 생성자 : 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가?

 

 


 

6. 변수의 초기화

6-1. 변수의 초기화

변수를 선언하고 처음으로 값을 저장하는 것을 '변수의 초기화'라고 함

멤버변수는 초기화를 하지 않아도 자동적으로 변수의 자료에 맞는 기본값으로 초기화가 이루어지므로 초기화하지 않고 사용해도 되지만, 지역변수는 사용하기 전에 반드시 초기화해야함.

멤버변수(클래스변수와 인스턴스변수)와 배열의 초기화는 선택적이지만, 지역변수의 초기화는 필수적

 

자료형 기본값
boolean false
char '\u000'
byte, short, int 0
long 0L
float 0.0f
double 0.0d 또는 0.0
참조형 변수  null

 

 

6-2. 멤버변수의 초기화 방법

  • 명시적 초기화(explicit initialization)
  • 생성자(constructor)
  • 초기화 블럭(initialization block)     : 인스턴스 초기화 블럭(인스턴스변수를 초기화 하는데 사용) , 클래스 초기화 블럭(클래스를 초기화 하는데 사용)

6-2-1. 명시적 초기화(explicit initialization)

변수를 선언과 동시에 초기화하는 방법

가장 기본적이면서도 간단한 초기화 방법

명시적 초기화가 간단하고 명료하긴 하지만, 보다 복잡한 초기화 작업이 필요할 때는 '초기화블럭' 또는 생성자를 사용해야 함

 

6-2-2. 초기화 블럭(initialization block) 

  • 클래스 초기화 블럭 : 클래스변수의 복잡한 초기화에 사용됨
  • 인스턴스 초기화 블럭 : 인스턴스변수의 복잡한 초기화에 사용됨

초기화 블럭을 작성하려면, 인스턴스 초기화 블럭은 단순히 클래스 내에 블럭{}을 만들고 그 안에 코드를 작성하기만 하면 되고, 클래스 초기화 블럭은 인스턴스 초기화 블럭 앞에 단순히 static을 덧붙이기만 하면 됨.

클래스 초기화 블럭은 클래스가 메모리에 처음 로딩될 때 한번만 수행되며, 인스턴스 초기화 블럭은 생성자와 같이 인스턴스를 생성할 때 마다 수행됨

그리고 생성자 보다 인스턴스 초기화 블럭이 먼저 수행됨

클래스가 처음 로딩될 때 클래스변수들이 자동적으로 메모리에 만들어지고, 곧바로 클래스 초기화블럭이 클래스변수들을 초기화함

 

주로 인스턴스 변수의 초기화는 주로 생성자를 사용하고, 인스턴스 초기화 블럭은 모든 생성자에 공통으로 수행되어야 하는 문장들이 있을 때 , 이 문장들을 각 생성자마다 써주기 보다는 인스턴스 블럭에 넣어줌

 

 

6-3. 멤버변수의 초기화 시기와 순서

  • 클래스변수의 초기화시점 : 클래스가 처음 로딩될 때 단 한번 초기화 됨
  • 인스턴스변수의 초기화시점 : 인스턴스가 생성될 때마다 각 인스턴스별로 초기화가 이루어짐
  • 클래스변수의 초기화순서 : 기본값 -> 명시적초기화 -> 클래스 초기화 블럭
  • 인스턴스변수의 초기화순서 : 기본값 -> 명시적초기화 -> 인스턴스 초기화 블럭 -> 생성자

 

 

 

출처 : 자바의 정석[도우출판 - 남궁성 지음] (교재) , 자바의 정석 기(유튜브)

[객체의 생성과 사용] www.youtube.com/watch?v=p1ZZnM715ao&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=53

[객체배열] www.youtube.com/watch?v=GSVbcmVw1i0&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=54

[클래스의 정의] www.youtube.com/watch?v=ML4CO32-bts&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=55

[클래스 작성방법] www.youtube.com/watch?v=hTHFeUTyIEo&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=52

[선언위치에 따른 변수의 종류/클래스변수와 인스턴스변수] www.youtube.com/watch?v=qA0D-nAcAvQ&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=56

[메서드/메서드의호출]www.youtube.com/watch?v=GXo3Ej24974&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=58

[return문]www.youtube.com/watch?v=CiEYqbwgqZ0&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=60

[호출스택]www.youtube.com/watch?v=-mqL3LJ4iVc&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=61

[기본형 매개변수와 참조형매개변수]www.youtube.com/watch?v=c9rXj3b9rKI&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=63

[인스턴스메서드와 static메서드]www.youtube.com/watch?v=Fl4TzjPKAMU&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=64

[오버로딩]www.youtube.com/watch?v=2rDeHSO4bdw&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=65

[생성자]www.youtube.com/watch?v=HXh2ZSgg-oQ&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=66

[생성자 this(), 참조변수 this]www.youtube.com/watch?v=LqCkLdlcC7M&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=67

[변수의 초기화] www.youtube.com/watch?v=ayRKMT6x-ms&list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp&index=68

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90