사용관계, 포함관계, 상속관계의 정확한 설명
사용관계 | 상속관계 | 포함관계 | |
---|---|---|---|
정의 | 객체간의 상호작용을 의미하며, 객체는 다른 객체의 메소드를 호출하여 원하는 결과를 얻음 | 기존 클래스에, 이미 만들어진 클래스를 재 사용하여 새로운 클래스를 작성하는 것 | 상속처럼 클래스를 재사용할 수 있는 방법인데, 다른 클래스의 객체를 자신의 멤버로 사용하는 것 |
extends와 함께 써준다.
자손 클래스는 조상 클래스의 모든 멤버를 상속받으며, 자손 클래스의 개수는 조상 클래스보다 항상 같거나 많다.
단일 상속만 가능하다
- 다중상속을 허용하면 클래스간의 관계가 복잡해지는 문제가 생김
- 만약, 자식 클래스에서 상속받는 서로 다른 부모 클래스들이 같은 이름의 멤버를 가지고 있다면 자식 클래스에서는 이 멤버를 구별할 수 있는 방법이 없음
포함관계(~은 ~을 가지고 있다.)
한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것이다.
(클래스의 속성 값에 다른 클래스를 선언하여 사용하는 것이다.)
질문 (김은양)
상속관계와 포함관계의 차이가 모호한 것 같다. 둘을 구분할 수 있는 추가 설명이 있으면 좋을 것 같다.
김은서
포함관계와 상속관계를 그림으로 나타내면 다음과 같다. (왼쪽이 포함관계, 오른쪽이 상속관계)
포함관계는 하위 객체가 모여 상위 객체를 이루는 식이다.
반면 상속관계는 상속이라는 개념이 중요한데, 여기서 상속이란 재산 상속의 개념이 아니라 유전 상속의 개념과 비슷하다. 상위 객체가 가지고 있는 특성이 있다면 그걸 따라 하위 객체 또한 같은 특성을 가지게 되며 비유하자면 하위 객체끼리 비슷한 분위기가 연출된다.
(왼쪽 그림) 하위객체인 문과 핸들, 타이어가 결합되어 상위 객체인 자동차를 이룬다.
(오른쪽 그림) 상위 객체인 대중교통은 사람이 많이 이용할 수 있고 정해진 루트가 있다는 특성이 있다. 이에 따라 하위 객체인 버스와 지하철 또한 상속을 통해 같은 특성을 지니게 된다.
은양님께서 하신 질문처럼 상속관계와 포함관계를 한 눈에 구별하기 위해서는 해석이 필요하다고 생각한다.
예진님께서 하신 설명에도 있는 내용인데, 포함관계의 경우 하위 객체가 상위 객체에 포함된다. 라고 해석이 되고 상속관계의 경우 하위 객체는 상위 객체이다. 라고 해석이 된다.
문과 핸들, 타이어는 자동차에 포함이 되고, 버스와 지하철은 대중교통이다. 라고 해석할 수 있는 것이다.
이렇게 해석을 해 보면 둘을 더 명확히 구분 지을 수 있다.
김근보
(1)사용관계 : 한 객체가 다른 객체를 사용하는 것을 의미.
객체간의 상호작용을 통해 기능을 수행.
-직접적인 사용관계 : 한 객체가 다른 객체를 필드나 메소드의 인자로 전달하여 사용하는 경우
-간접적인 사용관계 : 객체가 직접 다른 객체를 사용하지 않고 중간에 또 다른객체를 거쳐서 기능을 수행(다른 객체 내부에 포함되지 않고, 서로 간접적인 사용관계를 가지는 것)
(2)포함관계는 객체를 다른 객체의 멤버 변수로 포함시키는 관계를 의미합니다.
즉, 객체 A가 객체 B를 포함하고 있다는 것은 객체 A가 객체 B를 사용하고 있으며, 객체 B가 없으면 객체 A도 정상적으로 동작할 수 없다는 것을 의미(3)상속관계는 부모 클래스와 자식 클래스 간의 관계를 의미합니다.
자식 클래스는 부모 클래스의 특성을 그대로 물려받아 사용할 수 있으며, 부모 클래스에서 정의된 메서드와 변수를 자식 클래스에서 사용할 수 있다. (자식 클래스는 부모클래스보다 같거나 크다)
클래스랑 인스턴스의 차이
public class Car {
}
2.객체가 가지고 있어야할 필드(속성) 정의public class Car {
boolean lights;
String Color;
double speed;
}
3.클래스의 생성자를 정의 (객체를 생성하는 ‘방식’ 정의) *생성자는 반환 타입이 없고, 이름은 클래스의 이름과 동일해야 한다. *중괄호 안에 아무것도 없는 것을 기본 생성자라고 한다. public class Car {
boolean lights;
String Color;
double speed;
public Car() {
}
}
4.메서드 정의(객체가 가지고 있어야할 ‘행위’ 정의)public class Car {
boolean lights;
String Color;
double speed;
public Car() {
}
double brakePedal() {
speed = 0;
return speed;
}
char changeGear(char type) {
gear = type;
return gear;
}
}
// Car 클래스를 사용할 수 있는 이유? : class 를 public 으로 선언 했기 때문에
public class Main {
public static void main(String[] args) {
// 연습 3 메서드(행위 - 객체간의 협력을 위해서 사용되기도 한다)
Car car1 = new Car(); // 객체 생성(인스턴스화) car1 은 인스턴스
System.out.println("페달 밟기 전, car1.gear = " + car1.gear);
// 메소드 호출 및 반환값을 저장
double speed = car1.gasPedal(100, 'D');
// 엑셀을 밟아 속력이 늘어나고, type 은 드라이모드로 바뀐다.
System.out.println("speed = " + speed);
boolean lights =car1.onOffLight();
System.out.println("lights = " + lights);
System.out.println();
System.out.println("페달 밟고 난 후, car1.gear = " + car1.gear);
System.out.println();
car1.carSpeed(100, 80);
System.out.println();
car1.carSpeed(110, 120, 150);
}
}
클래스(Class) 란 -객체를 만들어 내기 위한 설계도 혹은 틀 -연관되어 있는 변수와 메서드의 집합
인스턴스(Instance)란?
클래스의 타입으로 선언되었을 때 객체라고 부르고, 그 객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 부릅니다.
객체는 현실 세계에 가깝고, 인스턴스는 소프트웨어 세계에 가깝습니다.
객체를 ‘클래스의 인스턴스’라고도 부릅니다.
참고클래스(Class) VS 객체(Object) 클래스는 ‘설계도’, 객체는 ‘설계도로 구현한 모든 대상’을 의미한다. 객체(Object) VS 인스턴스(Instance) 클래스의 타입으로 선언되었을 때 객체라고 부르고, 그 객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 부른다.
따지자면 객체는 현실 세계에 가깝고, 인스턴스는 소프트웨어 세계에 가깝다.
객체는 ‘실체’, 인스턴스는 ‘관계’에 초점을 맞춘다.
객체를 ‘클래스의 인스턴스’라고도 부른다. ‘방금 인스턴스화하여 레퍼런스를 할당한’ 객체를 인스턴스라고 말하지만, 이는 원본(추상적인 개념)으로부터 생성되었다는 것에 의미를 부여하는 것일 뿐 엄격하게 객체와 인스턴스를 나누긴 어렵다.
참고
추상화 기법 분류(Classification) 객체 -> 클래스 실재하는 객체들을 공통적인 속성을 공유하는 범부 또는 추상적인 개념으로 묶는 것 인스턴스화(Instantiation) 클래스 -> 인스턴스 분류의 반대 개념. 범주나 개념으로부터 실재하는 객체를 만드는 과정 구체적으로 클래스 내의 객체에 대해 특정한 변형을 정의하고, 이름을 붙인 다음, 그것을 물리적인 어떤 장소에 위치시키는 등의 작업을 통해 인스턴스를 만드는 것을 말한다. ‘예시(Exemplification)’라고도 부른다.
필드, 생성자, 메서드의 설명
Time () { // 생성자 선언
//인스턴스 초기화 작업
}
Time t = new Tine(); // 다른 클래스에서 생성자 호출
생성자 특징 생성자는 반환값(리턴값)이 없고 이름은 클래스의 이름과 동일합니다. 괄호( ) 안에 아무것도 없는 생성자를 기본 생성자라 합니다.(매개변수가 없다) // 모든 클래스에는 기본 생성자가 존재해야 한다,(생성자가 클래스안에 하나도 없을 때만, 컴파일러가 자동 추가) 생성자도 메서드 처럼 오버로딩이 가능하다. 가비지 컬렉터에 지워지지 않기 위해 생성자로 인스턴스를 초기화 해줘야 한다. 참조변수 주소는 스택영역에 쌓이고 변수 원본값을 저장하는데 원본값은 힙영역에 쌓인다. 메서드 코드의 중복을 줄이기 위해 문장들을 묶어 놓은 것 // 두개의 배열을 반복문으로 돌려야하는 상황일때 코드를 메서드로 묶어줄수 있다.반환타입 이름 (매개변수) { //선언부
// 구현부
}
메서드는 구현부와 선언부로 나뉜다.public class Person {
//필드 두 개
int age;
double height;
String name;
//생성자 하나
public Person (int age, double height, String name){
this.age = age;
this.height = height;
this.name = name;
}
//메서드
void eat(){
System.out.println(name + " 밥 먹음");
}
public static void main(String[] args) {
//해당 클래스를 인스턴스화 하고 메서드 호출
Person eunseo = new Person(25, 180, "eunseo");
eunseo.eat();
}
}
클래스 내 클래스 변수는 인스턴스가 여러개 생성되어도 인스턴스끼리 클래스 변수의 값을 공유한다고 합니다.
만약 인스턴스1에서 클래스 변수 값을 지정해주고 인스턴스2에서 클래스 변수 값을 재지정 해주면 어떻게 되나요?
// 만약 재지정이 된다면 기존 값은 참조불가능으로 분류되어 GC가 처리해주나요?
래퍼런스(Reference)
객체를 생성하면 JVM(Java Virtual Machine)은 Heap 메모리 영역에 객체를 저장하고, 그 객체를 참조하기 위한 래퍼런스를 스택(Stack) 메모리 영역에 생성합니다. 이 래퍼런스는 객체의 주소를 저장하고, 이를 통해 래퍼런스를 통해 객체를 참조하거나 객체에 접근할 수 있습니다. 따라서 래퍼런스는 객체의 실제 값이 아니라, 객체의 위치를 가리키는 주소값을 저장함.
(강의 3-9 참조) 아래 두 개의 클래스가 있습니다. Main 클래스 실행 시 출력 값은 무엇인가요? 에러가 발생한다면 어떤 에러가 발생하고 그 이유는 무엇인가요?
ColaCan.class
public class ColaCan{
private static int numCreated;
private int ml; //밀리리터
public ColaCan(int ml){
++numCreated;
this.ml = ml;
}
public static void printStatus(){
System.out.println("# Cola Produced: " + numCreated);
}
public int getMl(){
return ml;
}
}
Main.class
public class Main{
public static void main(String[] args) throws Exception{
ColaCan 콜라1 = new ColaCan(500);
ColaCan 콜라2 = new ColaCan(300);
콜라1.printStatus();
ColaCan.printStatus();
}
}
ColaCan.class에 코드 추가
public static void printStatus(){
System.out.println("# Cola Produced: " + numCreated);
System.out.println("# Cola Ml is: " + getMl()); //추가된 코드
}
public class Main{
public static void main(String[] args) throws Exception {
ColaCan 콜라1 = new ColaCan(500);
콜라1.printStatus();
}
}