[Java] 객체지향 프로그래밍Ⅰ

📁 객체지향언어

기존의 프로그래밍 언어에 규칙을 추가해 발전시킨 것
코드 사이에 유기적인 관계를 맺어주어 서로 상호작용하도록 프로그램을 구성할 수 있다.

객체지향언어의 특징

  • 코드의 재사용성이 높다.
  • 코드 관리, 유지보수에 용이하다.
  • 중복 코드를 제거해 신뢰성이 높은 프로그래밍이 가능하다.

📁 클래스와 객체

클래스

객체를 정의해놓은 틀. 객체를 생성하는 데에 사용되는 설계도

class 클래스명 {}

객체

클래스에 정의된 내용대로 메모리에 생성된 것
클래스가 의도한 속성과 기능을 갖춘 상품
속성(멤버변수)과 기능(메서드)으로 구성

인스턴스화

클래스로부터 객체를 만들어내는 과정
new 연산자를 사용

new 클래스명();

인스턴스 Instance

인스턴스화의 결과물로 만들어진 객체
같은 타입의 참조변수로 인스턴스가 저장된 위치의 주소값을 참조한다
인스턴스를 다루는 유일한 방법은 참조변수를 사용하는 것

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

📁 변수

변수의 종류는 선언 위치와 생성 시점, 생성 위치에 따라 클래스변수, 인스턴스변수, 지역변수 세가지로 분류된다.

선언 위치에 따른 변수의 구분

  • 전역변수 : 클래스영역에 생성된 변수
  • 지역변수 : 메서드영역에 생성된 변수

cviv는 전역변수, lv는 지역변수

class Variable {
	static int cv;
    int iv; 
    
    void method() {
    	int lv;
    }
}

📂 클래스 변수

전역변수의 한 종류로 모든 인스턴스가 공유하는 멤버변수

static 타입 변수명;
클래스명.변수명;

처음 클래스가 메모리에 로드될 때 단 한번 클래스영역에 생성되어 프로그램이 종료될 때까지 유지된다.
따라서 객체 생성 없이도 사용 가능하며, 클래스명.변수명의 형식으로 사용한다.
모든 인스턴스가 공통된 값을 공유해야 하는 변수의 경우 static을 붙여 클래스 변수로 선언한다.

📂 인스턴스 변수

전역변수의 일종으로 인스턴스마다 서로 다른 값을 가지고 있는 멤버변수

타입 변수명;
인스턴스명.변수명;

클래스 변수와 달리 객체가 생성되어야 사용할 수 있으며 객체가 생성될 때마다 메모리에 로드된다.
인스턴스마다 서로 다른 값을 가질 수 있기 때문에 인스턴스명.변수명 형식으로 사용한다.
메모리를 절약하기 위해서는 인스턴스 별로 고유한 값을 유지해야 하는 경우에만 인스턴스 변수로 선언하는 것이 좋다.

3) 지역변수

메서드영역에 생성된 변수로 메서드 내에서만 사용 가능

타입 변수명;

메서드 블럭을 벗어나면 소멸되어 사용할 수 없기 때문에 전역변수나 다른 메서드의 지역변수와 이름이 겹쳐도 크게 문제가 되지 않는다.

📁 메서드

특정 작업을 수행하는 일련의 코드들을 하나로 묶은 것

반환타입 메서드명(매개변수) { 작업내용 }

클래스영역에 선언되며 메서드명, 반환타입, 매개변수가 적힌 부분을 선언부, 작업내용이 적힌 블럭을 구현부라고 한다.

클래스 메서드와 인스턴스 메서드

전역변수와 마찬가지로 메서드 역시 클래스 메서드(static 메서드)와 인스턴스 메서드로 구분된다.
클래스 메서드는 맨 앞에 static이 붙어 객체 생성 없이 사용 가능한 반면 인스턴스 메서드는 인스턴스를 생성해야 사용 가능하다.

static int cv;
int iv;
void instanceMethod() {}

static void classMethod(int lv) {
	cv = lv;
    iv = lv;	// 에러
    instanceMethod();	// 에러
}

 

⚠️ 메서드 사용시 주의사항
인스턴스 메서드는 클래스 멤버를 자유롭게 사용할 수 있지만 클래스 메서드에서는 인스턴스 멤버를 사용할 수 없다.
인스턴스 멤버는 반드시 객체가 생성되어야만 사용 가능한데, 클래스 메서드를 사용하는 시점에 해당 클래스의 인스턴스가 존재하지 않을 가능성이 있기 때문이다.
인스턴스 멤버를 사용하지 않는 메서드는 static을 붙여 클래스 메서드로 만들어주는 것이 성능 측면에서 좋다.

📁 JVM의 메모리구조

응용프로그램이 실행되면 JVM은 시스템으로부터 프로그램 수행에 필요한 메모리를 할당받는다.
JVM은 이 메모리를 용도에 따라 메서드영역, , 호출스택 등으로 나누어 관리한다.

📂 메서드영역 Method Area

프로그램 실행 중 클래스가 사용되면 JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 클래스에 대한 정보를 저장한다.
클래스 변수, 메서드는 이곳에 단 한번 생성되어 프로그램이 종료될 때까지 유지된다.

📂 호출스택 Call Stack

메서드를 스택에 적재하고 작업을 수행하는 데에 필요한 메모리 공간을 제공한다.
할당된 메모리는 메서드의 매개변수, 인스턴스의 참조변수 등 작업을 수행하는 동안 생성된 지역변수를 저장하는 데에 활용된다.
메서드가 작업을 마치면 스택에서 비워지면 메모리 공간이 반환되며, 스택이 전부 비워지면 프로그램이 종료된다.

📂 힙 Heap

인스턴스가 생성되는 공간으로 프로그램 실행 중 생성되는 인스턴스를 수시로 저장한다.
참조변수가 없어 사용할 수 없게 된 인스턴스는 가비지 컬렉터에 의해 제거된다.

📁 오버로딩 Overloading

한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것

public class PrintStream {
	public void println(boolean x)
	public void println(char x)
	public void println(char[] x)
}

PrintStream 클래스의 println()은 오버로딩의 대표적인 예시이다.

성립 조건

  • 메서드 이름이 동일해야 한다.
  • 매개변수의 개수나 타입이 달라야 한다.
  • 리턴타입이 다른 것은 관계없다.

📁 생성자

인스턴스 생성시 호출되는 인스턴스 초기화 메서드

클래스명(매개변수) {}

모든 클래스는 하나 이상의 생성자를 가져야 한다.
이름은 생성자이지만 그 자체로 인스턴스를 생성하는 것은 아니다. 실제로 인스턴스를 생성하는 것은 new 연산자의 역할이다.
생성자는 매개변수로 넘겨받은 값을 사용해 인스턴스 멤버를 초기화하거나 인스턴스를 생성할 때 실행되는 작업에 사용된다.

기본 생성자

매개변수도 내용도 없는 간단한 메서드

public Constructor() {}

컴파일 타임에 클래스에 생성자가 하나도 없는 경우 JVM이 자동으로 기본 생성자를 추가해준다.
생성자가 하나라도 있으면 컴파일러는 기본 생성자를 만들지 않는다.
기본 생성자는 인스턴스 생성이나 클래스 상속에서 필수적으로 사용되기 때문에 명시적으로 선언해주는 것이 좋다.

매개변수가 있는 생성자

생성자는 매개변수로 값을 넘겨받아 인스턴스의 생성과 동시에 멤버변수를 초기화할 수 있다.

public Constructor(int value1, int value2) {
	this.value1 = value1;
	this.value2 = value2;
}

메서드와 마찬가지로 오버로딩이 적용 가능하기 때문에 필요한 멤버만 초기화하는 생성자들을 여러개 선언할 수 있다.

this

객체 자신을 가리키는 참조변수의 예약어로 인스턴스 메서드 내에 숨겨진 지역변수로 항상 존재

this.instanceValue = instanceValue;
this.instanceMethod();

클래스 내에서 인스턴스 멤버를 사용할 때에는 this.를 붙여 해당 객체의 멤버임을 명시할 수 있으며, 동일한 이름을 가진 지역변수와도 구분이 가능해진다.

this()

메서드에서 다른 메서드를 호출할 수 있듯이, 생성자에서도 다른 생성자를 호출할 수 있다.
자기 클래스의 생성자를 호출할 때에는 클래스명() 대신 this()를 사용한다.

public Constructor(int value1, int value2, int value3) {
	this(value1, value2);
    this.value3 = value3;
}

이처럼 클래스 내에 이미 존재하는 생성자를 재사용하면 코드의 중복을 줄일 수 있다.
주의할 점은 오직 생성자의 첫번째 줄에서만 다른 생성자를 호출할 수 있다는 것이다.
첫번째 줄 이하에서 다른 생성자를 호출하면 이전에 기존 생성자에서 수행한 초기화 작업이 무의미해질 수 있기 때문이다.

📁 변수의 초기화

변수를 처음 선언하고 값을 지정하는 것

📂 묵시적 초기화

값을 직접 지정하지 않아도 자동적으로 해당 자료형의 기본값으로 초기화되는 것

static int cv;
int iv;

void method() {
	int lv;
    cv++;
    iv++;
    lv++;	// 에러
}

전역변수는 직접 초기화해주지 않아도 자동 초기화가 되지만 지역변수는 사용 전 반드시 초기화를 해주어야 에러가 발생하지 않는다.

📂 명시적 초기화

변수를 선언과 동시에 초기화하는 가장 기본적인 초기화 방법

int i = 10;
String str = new String("abc");

📂 초기화 블럭

멤버변수의 복잡한 초기화에 사용되는 방법이다
블럭 내에서는 조건문, 반복문, 메서드 등을 자유롭게 사용할 수 있어 명시적 초기화만으로는 부족한 경우 사용된다.

  • 클래스 초기화 블럭

클래스 변수의 복잡한 초기화에 사용되는 블럭
클래스가 처음 메모리에 로드될 때 단 한번 수행되며, 내부에서 인스턴스 멤버를 사용할 수 없다.

static { ... }
  • 인스턴스 초기화 블럭

인스턴스 변수의 복잡한 초기화에 사용되는 블럭
인스턴스가 생성될 때마다 수행된다.

{ ... }

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

클래스 변수

클래스가 메모리에 로드될 때 단 한번 초기화된다.
기본값 → 명시적 초기화 → 클래스 초기화 블럭

인스턴스 변수

인스턴스가 생성될 때마다 초기화된다.
기본값 → 명시적 초기화 → 인스턴스 초기화 블럭 → 생성자