클래스(Class)와 객체(Object)
클래스
클래스와 객체
-
객체
-
클래스(Class)
- 객체를 정의한 설계도(blueprint) 또는 틀(frame)
- 클래스는 객체를 생성하는데 사용되며, 객체는 클래스에 정의되고 설계된 내용 그대로 생성됨
- 클래스는 객체 자체는 될 수 없음
- 즉, 클래스는 객체를 생성하는 데에 사용되는 틀
-
인스턴스(instance)
- 클래스를 통해 생성된 객체
- 인스턴스화(instantiate)
-
객체 vs 인스턴스
- 객체
- 인스턴스
- 객체가 어떤 클래스로부터 생성된 것인지를 강조
-
클래스로 객체를 생성하는 이유
- 한 번 클래스를 잘 정의해놓는다면, 매번 객체를 생성할 때마다 객체를 어떻게 생성해야할지 고민하지 않고 클래스로부터 객체를 생성하여 사용만 하면 됨
클래스의 구성요소
class 클래스명 {
}
- 클래스의 구성요소
- 필드(field)
- 메서드(method)
- 생성자(constructor)
- 이너 클래스(inner class)
public class Singer {
String name;
Date birth;
Singer() {
name = null;
birth = null;
}
void printTitle() {
System.out.println(title);
}
class Song {
String title;
String genre;
public Song() {
title = null;
genre = null;
}
}
}
- 필드
- 메서드
- 생성자
- 이너 클래스
- 멤버(member)
- 위 4개의 구성요소 중 생성자를 제외한 나머지 3개의 요소
- 즉, 필드, 메서드, 이너 클래스
객체(Object)
- 속성, 기능이라는 두 가지의 구성요소로 이루어져 있음
- 속성은 필드, 기능은 메서드로 정의됨
- 하나의 객체는 다양한 속성 및 기능의 집합으로 이루어져 있음
객체 생성
- new 키워드를 통해 실제 객체를 생성
- 포인트 연산자( . ) 를 통해 객체의 멤버에 접근
클래스명 참조변수명;
참조변수명 = new 생성자();
클래스명 참조변수명 = new 생성자();
- 특정 클래스 타입의 참조 변수를 선언
- 참조 변수가 선언되면, new 키워드와 생성자를 통해 인스턴스를 생성
- 참조 변수는 실제 데이터가 저장되어 있는 힙 메모리의 주소값을 가리킴
- new 키워드
class Test {
public static void main(String[] args) {
Singer singer1 = new Singer();
Singer singer2 = new Singer();
}
}
- Singer와 참조 변수 singer는 각각 클래스 영역과 스택 영역에 위치
- 인스턴스는 힙 메모리 영역에 위치
- 객체 내부에는 클래스의 멤버들이 위치
- 참조 변수는 힙에 저장되어 있는 인스턴스의 주소값을 가리킴
- 메서드 구현 코드는 클래스 영역에 저장되어 있음
- 같은 클래스의 모든 객체는 동일한 메서드 값을 공유
- 즉, 메서드를 여러 번 선언하는 것이 아닌 한 번만 저장해두고 필요한 경우 클래스 영역에 저장된 메서드를 찾아 사용
- 생성된 객체에서 필드값은 실제 저장공간이 객체 내부에 있음
- 메서드는 클래스 영역에 하나만 저장해놓고 공유!
객체의 활용
- 객체에 접근하고 이를 사용할 때는 포인트 연산자( . ) 를 이용
- 포인트 연산자( . )를 이용하여 특정 인스턴스 객체의 멤버들에 접근할 수 있음
참조변수명.필드명;
참조변수명.메서드명();
필드와 메서드
필드
- 클래스에 포함된 변수
- 객체의 속성을 정의할 때 사용
- Java에서의 변수
- 클래스 변수(class variable)
- 인스턴스 변수(instance variable)
- 지역 변수(local variable)
- 필드라 부르는 것은 클래스 변수, 인스턴스 변수
- 클래스 변수 vs 인스턴스 변수
- static 키워드의 유무
- 클래스 변수
- 인스턴스 변수
- 지역 변수
- 위 두 변수 유형(클래스 변수, 인스턴스 변수)에 포함되지 않고 메서드 내에 포함된 모든 변수
class Singer {
static String platform;
String name;
Date birth;
public void printBirth() {
DateFormat dateFormat = new SimpleDataFormat("dd/MM/yyyy HH:mm:ss");
String birthStr = dateFormat.format(birth);
System.out.println(birthStr);
}
}
-
인스턴스 변수
- 인스턴스가 가지는 각각의 고유한 속성을 저장하기 위한 변수
- new 생성자() 를 통해 인스턴스가 생성될 때 만들어짐
-
클래스 변수
- static 키워드를 통해 선언
- 독립적인 저장 공간을 가지는 인스턴스 변수와 다르게 공통된 저장 공간을 공유
- 한 클래스로부터 생성되는 모든 인스턴스들이 특정한 값을 공유해야 하는 경우 클래스 변수를 선언
- 클래스 영역에 저장되어 그 값을 공유하기 때문
- 클래스명.클래스변수명 을 통해 사용 가능
-
지역 변수
- 메서드 내에 선언됨
- 메서드 내에서만({ } 블록) 사용 가능
- 스택 메모리에 저장되어 메서드가 종료되는 것과 동시에 함께 소멸되어 더이상 사용할 수 없음
- 스택 메모리에 저장되는 지역 변수는 한동안 사용되지 않으면 가상 머신에 의해 자동으로 삭제됨 -> Garbage Collection
-
필드 변수 vs 지역 변수
- 지역 변수
- 직접 초기화하지 않으면 값을 출력할 때 오류 발생
- 필드 변수
- 직접적으로 초기화를 실행하지 않아도 강제로 초기화가 이루어짐
- 이는 메모리의 저장 위치와 관련이 있음
- 힙 메모리에는 빈 공간이 저장될 수 없음 -> 필드는 강제로 초기화가 됨
- 스택 메모리는 강제 초기화가 되지 않음 -> 초기화를 실행해주지 않으면 에러 발생
static 키워드
- 클래스의 멤버에 사용되는 키워드
- 정적 멤버(static member) -> static 키워드가 붙어있는 멤버
- 인스턴스 멤버
- 객체를 생성한 이후에 변수와 메서드에 접근하여 해당 멤버를 사용 가능
- 클래스 멤버
- static 키워드로 정의되어 있고 인스턴스 생성 없이 클래스명.멤버명으로 사용 가능
- 정적 멤버도 객체를 생성한 이후 참조변수를 통해 사용 가능하지만, 정적 멤버임을 표시하기 위해 클래스명.멤버명 형태로 사용을 권장
- 정적 멤버
- 메모리 저장 위치와 관련이 있음
- new 키워드를 통해 생성된 인스턴스는 힙 메모리에 생성되고 독립적인 저장공간을 가짐
- static 키워드로 선언된 정적 멤버는 클래스 영역에 저장 공간을 가지므로 객체 생성 없이 바로 사용 가능
- 정적 멤버는 다음과 같은 특징이 있음
- 정적 필드는 객체 간 공유 변수의 성질이 있음
- 정적 메서드의 경우 인스턴스 변수 또는 인스턴스 메서드를 사용할 수 없음
- 메서드를 사용해 객체를 생성할 수도 있지만 이 경우도 역시 내부적으로는 new 키워드를 통해 객체를 생성하므로 결국 동일한 방식이라고 볼 수 있음
- 참조 변수
- 실제 데이터가 위치해있는 힙 메모리의 주소를 저장하는 변수
- new 키워드와 생성자를 통해 클래스의 객체를 생성
- 해당 객체를 힙 메모리에 넣고 그 주소값을 참조 변수에 저장하는 것
class Singer {
static String platform;
String name;
Date birth;
}
public static void main(String[] args) {
Singer singer1 = new Singer();
Singer singer2 = new Singer();
singer1.platform = "멜론";
singer2.platform = "애플 뮤직";
System.out.println(singer1.platform);
System.out.println(singer2.platform);
애플 뮤직
애플 뮤직
}
- static 키워드를 사용하면 위 예시와 같이 모든 인스턴스에 공통적으로 적용되는 값을 공유할 수 있음
메서드
- 특정 작업을 수행하는 일련의 명령문들의 집합
- 클래스의 기능에 해당하는 내용들을 담당
- 메서드는 크게 메서드 시그니처(method signature) 와 메서드 바디(method body) 로 구분
자바제어자 반환타입 메서드명(매개 변수) {
메서드 내용
}
- 메서드 시그니처
- 반환 타입 : 해당 메서드가 어떤 타입을 반환하는가
- 메서드명 : 메서드의 이름이 무엇인가
- 매개 변수 : 수행하기 위해 어떤 것이 필요한가
- 메서드 바디
- 괄호({ }) 안에 해당 메서드가 호출되었을 때 수행되어야하는 실행문들을 표시
- 메서드 반환타입이 void가 아니라면 메서드 바디 안에는 반드시 return 문이 존재해야 한다!
- return문
- 작업을 수행한 결과값을 호출한 메서드로 반환
- 결과값은 반드시 반환타입과 일치하거나 자동 형변환이 이루어질 수 있어야 함
메서드 호출
- 외부에서 메서드를 사용하기 위해서는 인스턴스를 우선 생성해야 함
- 인스턴스 생성 후에 포인트 연산자( . )를 통해 메서드를 호출
- 클래스 내부에 있는 메서드들끼리는 객체 생성 없이 호출 가능
public class Singer {
static String platform;
String name;
Date birth;
public void printBirth() {
DateFormat dateFormat = new SimpleDataFormat("dd/MM/yyyy HH:mm:ss");
String birthStr = dateFormat.format(birth);
System.out.println(birthStr);
}
public static void main(String[] args) {
printBirth();
}
}
- 인자(argument)
- 메서드 호출 시 괄호( ( ) ) 안에 넣어주는 입력값
- 인자의 개수와 순서는 메서드를 정의할 때 선언한 매개변수와 일치해야 한다!
- 매개변수와 인자의 타입이 같거나 자동 형변환이 가능해야 한다!
메서드 오버로딩(Method Overloading)
- 하나의 클래스 내에 같은 이름의 메서드 여러 개를 정의하는 것
- 같은 이름의 메서드로 여러 기능을 구현할 때 오버로딩을 이용
- 메서드 시그니처(Method Signature)
- 메서드명 및 매개변수 타입을 의미
- 각 메서드를 구분하는 용도
- JVM은 매개변수의 타입, 메서드의 이름이 다르면 다른 메서드로 인식함
class Song {
String title;
String singer;
int curTime;
public void play() {
System.out.println("음악 재생 시작");
}
public void play(int curTime) {
this.curTime = curTime;
System.out.println("음악 재생 시작");
}
}
- play라는 메서드명을 가진 메서드가 Song 클래스 내에 2개가 존재
- 오버로딩의 조건
- 같은 이름의 메서드명을 사용
- 매개변수의 타입이나 개수가 달라야 함
- 만약 위 조건 2개 중 하나라도 충족되지 않는다면 컴파일 에러 발생
- 반환 타입은 오버로딩 성립에 영향을 주지 않는다!