Chapter6. 객체지향 프로그래밍1

개발빼-엠·2023년 1월 30일

Java

목록 보기
6/8
post-thumbnail

1.객체지향언어

객체지향언어의 특징

  • 기존의 프로그래밍언어와 크게 다르지 않다.
    • 기존의 프로그래밍 언어에 몇가지 규칙을 추가한 것일 뿐이다.
  • 코드의 재사용성이 높다.
    • 새로운 코드를 작성할 때 기존의 코드를 이용해서 쉽게 작성할 수 있다.
  • 코드의 관리가 쉬워졌다.
    • 코드간의 관계를 맺어줌으로써 보다 적은 노력으로 코드변경이 가능하다.
  • 신뢰성이 높은 프로그램의 개발을 가능하게 한다.
    • 제어자와 메서드를 이용해서 데이터를 보호하고, 코드의 중복을 제거하여 코드의 불일치로 인한 오류를 방지할 수 있다.

객체지향개념을 학습할 때 재사용성, 유지보수, 중복된 코드의 제거 세 가지 관점에서 보면 쉽게 이해할 수 있다.

개념에 얽매여서 고민하기보다 프로그램을 기능적으로 완성한 다음 객체지향적으로 코드를 개선할 수 있을지를 고민.

2.클래스와 객체

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

  • 클래스의 정의: 객체를 정의해 놓은 것
  • 클래스의 용도: 객체를 생성하는데 사용
  • 객체의 정의: 실제로 존재하는 것. 사물 또는 개념
  • 객체의 용도: 객체가 가지고 있는 기능과 속성에 따라 다름

객체와 인스턴스

객체 === 인스턴스

객체는 인스턴스를 포함하는 일반적인 의미

인스턴스화

클래스로부터 인스턴스를 생성하는 것

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

  • 객체는 속성과 기능으로 이루어져 있다.
    • 객체는 속성과 기능의 집합이며, 속성과 기능을 객체의 멤버(member, 구성요소)라고 한다.
      • 속성(property): 멤버변수(member variable), 특성(attribute), 필드(field), 상태(state)
      • 기능(function): 메서드(method), 함수(function), 행위(behavior)
  • 속성은 변수로, 기능은 메서드로 정의하다.

인스턴스의 생성과 사용

  • 생성방법 클래스명 참조변수명; 참조변수명 = new 클래스명();
  • 참조변수가 없으면 인스턴스를 사용할 수 없고, 사용하지 않는 인스턴스는 JVM의 가비지 컬렉션에 의해 적절한 시기에 자동적으로 메모리에서 제거가 되어 사용되지 않는 인스턴스 제거를 신경쓰지 않아도 되는 java의 장점이있다.
  • 인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야한다.
  • 하나의 인스턴스를 여러 개의 참조변수가 가르키는 경우(가능)
  • 여러 개의 인스턴스를 하나의 참조변수가 가르치는 경우(불가능)

클래스의 또 다른 정의

클래스: 데이터와 함수의 결합

변수(하나의 데이터를 저장할 수 있는 공간)

→ 배열(같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간)

→ 구조체(서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장할 수 있는 공간)

→ 클래스(데이터와 함수의 결합. 구조체+함수)

3.변수와 메서드

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

변수의 종류선언위치생성시기
클래스변수클래스영역클래스가 메모리에 올라갈 때
인스턴스변수클래스영역인스턴스가 생성되었을 때
지역변수클래스 영역 이외의 영역변수 선언문이 수행되었을 때
class Variables{
	int iv;         // 인스턴스 변수
	static int cv;  // 클래스변수(static변수, 공유변수)

	void method(){  
		int lv = 0;   // 지역변수
	}
}

지역변수에는 static을 붙일 수 없다.

  • 인스턴스 변수(instance variable)
    • 각 인스턴스의 개별적인 저장공간. 인스턴스마다 다른 값 저장가능
    • 인스턴스 생성 후, ‘참조변수.인스턴스변수명’으로 접근
    • 인스턴스를 생성할 때 생성되고, 참조변수가 없을 때 가비지컬렉터에 의해 자동제거됨
  • 클래스 변수(class variable)
    • 같은 클래스의 모든 인스턴스들이 공유하는 변수
    • 인스턴스 생성없이 ‘클래스이름.클래스변수명’으로 접근
    • 클래스가 로딩될 때 생성되고 프로그램이 종료될 때 소멸
  • 지역변수(local variable)
    • 메서드 내에 선언되며, 메서드의 종료와 함께 소멸
    • 조건문, 반복문의 블럭{} 내에 선언된 지역변수는 블럭을 벗어나면 소멸

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

  • 참고 이미지

메서드

  • 메서드란?
    • 작업을수행하기 위한 명령문의 집합
    • 어떤 값을 입력받아서 처리하고 그 결과를돌려준다.(입력받는 값이 없을 수도 있고 결과를 돌려주지 않을 수도 있다.)
  • 메서드의 장점과 작성지침
    • 반복적인 코드를 줄이고 코드의 관리가 용이하다.
    • 반복적으로 수행되는 여러 문장을 메서드로 작성한다.
    • 하나의 메서드는 한 가지 기능만 수행하도록 작성하는 것이 좋다.
    • 관련된 여러 문장을 메서드로 작성한다.
  • 메서드를 정의하는 방법: 클래스 영역에만 정의할 수 있다.

메서드의 호출

인자의 타입은 매개변수의 타입과 일치하거나 자동 형변환이 가능한 것이어야 한다.

  • return문 반환값의 유무에 관계없이 모든 메서드에는 적어도 하나의 return문이 있어야한다. 반환타입이 void인 경우, return문 없이도 아무런 문제가 없었던 이유는 컴파일러가 메서드의 마지막에 ‘return;’을 자동적으로 추가해주었기 때문이다. void타입이 아니고 return문이 없는 경우 컴파일 에러가 발생한다.

JVM의 메모리 구조

  • 메서드 영역(method area)
    • 클래스 정보와 클래스변수가 저장되는 곳
  • 호출스택(call stack, execution stack)
    • 메서드의 작업공간. 메서드가 호출되면 메서드 수행에 필요한 메모리공간을 할당받고 메서드가 종료되면 사용하던 메모리를 반환한다.
  • 힙(heep)
    • 인스턴스가 생성되는 공간. new연산자에 의해서 생성되는 배열과 객체는 모두 여기에 생성된다.

*호출스택의 특징

  • 메서드가 호출되면 수행에 필요한 메모리를 스택에 할당받는다.
  • 메서드가 수행을 마치면 사용했던 메모리를 반환한다.
  • 호출스택의 제일 위에 있는 메서드가 현재 실행중인 메서드다. 나머지 메서드는 대기중이다.
  • 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드다.

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

  • 기본형 매개변수 - 변수의 값을 읽기만 할 수 있다.(read only)
    • 단순히 저장된 값을 복사한 것이기 때문에 값이 어디서 온 것인지 알 수 없다.
  • 참조형 매개변수 - 변수의 값을 읽고 변경할 수 있다.(read & write)
    • 값이 저장되어있는 곳의 주소값을 복사해오는 것이기 때문에 값이 저장된 위치를 알 수 있어 값을 읽어올 수도, 변경할 수도 있다.

모든 참조형 타입의 값은 ‘객체의 주소'이다.

반환타입이 ‘참조형'이라는 것은 메서드가 ‘객체의 주소'를 반환한다는 것을 의미한다.

매개변수의 타입이 기본형.
매개변수에 값을 복사해서 넘겨준다.

매개변수의 타입이 참조형.
인스턴스의 주소가 복사된다.

재귀호출(Recursive Call)

재귀호출이란?

  • 메서드 내에서 자기자신을 반복적으로 호출하는 것
  • 재귀호출은 반복문으로 바꿀 수 있으며 반복문보다 성능이 나쁨
  • 이해하기 쉽고 간결한 코드를 작성할 수 있다.

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

  • 인스턴스메서드
    • 인스턴스 생성 후, ‘참조변수.메서드이름()’으로 호출
    • 인스턴스변수나 인스턴스메서드와 관련된 작업을 하는 메서드
    • 메서드 내에서 인스턴스변수 사용가능
  • 클래스메서드(static메서드)
    • 객체생성없이 ‘클래스이름.메서드이름()’으로 호출
    • 인스턴스변수나 인스턴스메서드와 관련없는 작업을 하는 메서드
    • 메서드 내에서 인스턴스변수를 사용하지 않는다면 static을 붙이는 것을 고려한다.

메서드의 작업에 인스턴스변수를 사용하면 인스턴스메서드, 사용하지 않으면 클래스메서드이다.

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

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

*멤버변수: 클래스 영역에 선언된 변수를 멤버변수라 한다. 멤버변수는 인스턴스변수와 static변수를 모두 통칭하는 말로 멤버변수 중에 staic이 붙은 것은 클래스변수, 붙지 않은 것은 인스턴스변수라 한다.

  1. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
  2. 클래스변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
  3. 클래스 메서드는 인스턴스 변수를사용할 수 없다.
  4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.

멤버간의 참조와 호출

같은 클래스의 멤버간에는 객체생성이나 참조변수 없이 참조할 수 있다. 그러나 static멤버들은 인스턴스 멤버들을 참조할 수 없다. 281page 참고

메서드의 호출

class TestClass{
	void instanceMethod() {}            // 인스턴스 메소드
	static void staticMethod() {}       // static(클래스) 메소드

	void instanceMethod2() {            // 인스턴스 메서드
		instanceMethod();                 // 다른 인스턴스메서드를 호출한다. ok
		staticMethod();                   // static메서드를 호출한다. ok
	}

	static void statieMethod2() {       // static 메서드
		instanceMethod();                 // 인스턴스 메서드를 호출할 수 없다. err
		staticMethod();                   // static메서드는 호출할 수 있다. ok
	}
}

변수의 접근

class TestClass2{
	int iv;            // 인스턴스 변수
	static int cv;     // static(클래스) 변수

	void instanceMethod() {            // 인스턴스 메서드
		System.out.println(iv);          // 인스턴스변수를 사용할 수 있다.
		System.out.println(cv);          // 클래스변수를 사용할 수 있다.
	}

	static void statieMethod() {       // static 메서드
		System.out.println(iv);          // 인스턴스변수를 사용할 수 없다. err
		System.out.println(cv);          // 클래스변수를 사용할 수 있다.
	}
}

*같은 클래스 내에서 클래스멤버가 인스턴스멤버를 참조 또는 호출해야 하는 경우는 드무므로 그런 경우가 발생한다면, 인스턴스메서드로 작성해랴할 메서드를 클래스메서드로 한 것은 아닌지 한 번 더 생각해봐야 한다.

⭐️알아두면 좋은것

MemberCall c = new MemberCall();
int result = c.method();
// 위 두줄을

int result = new MemberCall().method();
// 한 줄로 줄일 수 있다.

4.오버로딩

메서드 오버로딩(method overloading)이란?

하나의 클래스에 같은 이름의 메서드를 여러 개 정의하는 것을 메서드 오버로딩, 간단히 오버로딩이라고 한다.

오버로딩의 조건

  • 메서드의 이름이 같아야한다.
  • 매개변수의 개수 또는 타입이 달라야 한다.
  • 매개변수는 같고 리턴타입이 다른 경우는 오버로딩이 성립되지 않는다.
  • 매개변수의 이름이 다른 것은 오버로딩이 아니다.
  • 리턴타입은 오버로딩 성립조건이 아니다.

오버로딩의 장점

  • 근본적으로 기능이 같은 메서드들을 기억하기 쉽고 이름도 짧게 할 수 있어 오류의 가능성을 줄일 수 있다.
  • 메서드의 이름을 절약할 수 있다.
  • 이름을 짓는 고민을 덜어준다.

가변인자(varargs)

✅ 가능하면 가변인자를 사용한메서드는 오버로딩하지 않는것이 좋다.

메서드의 매개변수 개수가 고정적이아닌 동적으로 지정해 줄 수 있게 된 기능을 ‘가변인자’라고 한다.

‘타입… 변수명'과 같은형식으로 선언한다.

가변인자를 매개변수 중에서 제일 마지막에 선언한다. 그렇지 않으면 가변이자인지 아닌지를 구분할 방법이 없어 컴파일 에러가 발생한다.

5.생성자(Constructor)

생성자란?

  • 인스턴스가 생성될 때마다 호출되는 ‘인스턴스 초기화 메서드’
  • 인스턴스 변수의 초기화 또는 인스턴스 생성시 수행할 작업에 사용
  • 몇가지 조건을 제외하고는 메서드와 같다.
  • 모든 클래스에는 반드시 하나 이상의 생성자가 있어야 한다.

*인스턴스 초기화 - 인스턴스 변수에 적절한 값을 저장한는 것.

Card c = new Card();
  1. 연산자 new에 의해 메모리(heap)에 Card클래스의 인스턴스가 생성된다.

    참조변수 c가 선언되고 연산자 new에 의해 Card인스턴스가 생성된다

  2. 생성자 Card()가 호출되어 수행된다.

    인스턴스의 생성이 생성자가 아닌 new 연산자에의해 생성된다.

    연산자 new가 인스턴스를 생성하는 것이지 생성자가 인스턴스를 생성하는 것은 아니다.

  3. 연산자 new의 결과로, 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장된다.

생성자의 조건

  • 생성자의 이름은 클래스의 이름과 같아야 한다.
  • 생성자는 리턴값이 없다.(하지만 void를 쓰지 않는다.) void를 붙여야 하지만, 모든 생성자가 리턴값이 없으므로 생략할 수 있게 된 것이다.
  • 하나의 클래스에 여러개의 생성자를 생성할 수 있다. → 이름이 같아야 하므로 오버로딩이다.

기본 생성자(default constructor)

💙 모든 클래스에는 반드시 하나 이상의 생성자가 있어야 한다.

  • 매개변수가 없는 생성자
  • 클래스에 생성자가 하나도 없으면 컴파일러가 기본 생성자를 추가함으로써 모든 클래스에 하나 이상의 생성자가 있어야 하는 원칙을 지켜준다. (생성자가 하나라도 있으면 컴파일러는 기본 생성자를 추가하지 않는다.)
  • 기본 생성자가 컴파일러에 의해서 추가되는 경우는 클래스에 정의된 생성자가 하나도 없을 때 뿐이다.

매개변수가 있는 생성자

양쪽 코드 모두 같은 내용이지만, 오른쪽의 코드가 더 간결하고 직관적이다.

클래스를 작성할 때 다양한 생성자를 제공함으로써 인스턴스 생성 후에 별도로 초기화를 하지 않아도 되도록 하는 것이 바람직하다.

class Car{
	String color;
	String gearType;
	int door;

	Car() {}
}

Car c = new Car();
c.color = "white";
c.gearType = "auto";
c.door = 4;
class Car{
	String color;
	String gearType;
	int door;

	Car(String c, String g, int d) {
		color = c;
		gearType = g;
		door = d;
	}
}

Car c = new Car("white", "auto", 4);

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

this(): 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다. 다른 생성자 호출은 생성자의 첫 문장에서만 가능하다.

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

this: 인스턴스 자신을 가르키는 참조변수. 인스턴스의 주소가 저장되어있다. 모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재한다.

  • 참조변수로 인스턴스 자신을 가리킨다.
  • ‘this’를 사용할 수 있는 것은 인스턴스멤버뿐이다.

생성자의 매개변수로 선언된 변수의 이름과 인스턴스변수 이름이 구분 되지 않을 경우 인스턴스 변수 앞에 ‘this’를 사용하면 된다.

this.color는 인스턴스변수, color는 생성자의 매개변수로 정의된 지역변수로 서로 구별이 가능하다.

Car(String c, String g, int d) {
	color = c;
	gearType = g;
	door = d;
}
Car(String color, String gearType, int door) {
	this.color = color;
	this.gearType = gearType;
	this.door = door;
}

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

사용하고 있는 인스턴스와 같은 상태를 갖는 인스턴스를 하나 더 만들고자 할 때 생성자를 이용할 수 있다.

두 인스턴스가 같은 상태를 갖는다는 것은 두 인스턴스의 모든 인스턴스 변수가 동일한 값을 갖고 있다는 것을 뜻한다.

  • 인스턴스간의 차이는 인스턴스변수의 값 뿐 나머지는 동일하다.
  • 생성자에서 참조변수를 매개변수로 받아서 인스턴스변수들의 값을 복사한다.
  • 똑같은 속성값을 갖는 독립적인 인스턴스가 하나 더 만들어진다.

복사하여 생성된 인스턴스는 서로 같은 상태를 갖지만, 서로 독립적으로 메모리공간에 존재하는 별도의 인스턴스이므로 값들이 변경되어도 서로에게 영향을 받지 않는다.

⭐️인스턴스를 생성할 때는 다음의 2가지 사항을 결정해야한다.

  1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가
  2. 생성자 - 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가

6.변수의 초기화

변수의 초기화

  • 변수를 선언하고 처음으로 값을 저장하는 것
  • 멤버변수(인스턴스변수, 클래스변수)와 배열은 각 타입의 기본값으로 자동초기화되므로 초기화를 생략할 수 있다.
    • 자료형의 초기화값
      자료형기본값
      booleanfalse
      char‘\u0000’
      byte0
      short0
      int0
      long0L
      float0.0f
      double0.0d 또는 0.0
      참조형 변수null
  • 지역변수는 사용전에 꼭 초기화를 해주어야한다.

멤버변수의 초기화 방법

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

    class Car {
    	int door = 4;               // 기본형 변수의 초기화
    	Engine e = new Engine();    // 참조형 변수의 초기화
    }
  2. 생성자(constructor)

    Car(String color, String gearType, int door) {
    	this.color = color;
    	this.gearType = gearType;
    	this.door = door;
    }
  3. 초기화 블럭(initialization block)

    • 인스턴스 초기화 블럭({})
      • 생성자에서 공통적으로 수행되는 작업에 사용되며 인스턴스가 생성될 때 마다 (생성자보다 먼저) 실행된다.
    • 클래스 초기화 블럭(static {})
      • 클래스변수의 복잡한 초기화에 사용되며 클래스가 로딩될 때 실행된다.

멤버변수의 초기화 시기와 순서

클래스변수 초기화 시점: 클래스가 처음 로딩될 때 단 한번

클래스변수의 초기화 순서: 기본값 → 명시적 초기화 → 클래스 초기화블럭

인스턴스변수 초기화 시점: 인스턴스가 생성될 때 마다

인스턴스변수 초기화 순서: 기본값 → 명시적 초기화 → 인스턴스 초기화블럭 → 생성자

0개의 댓글