Java 객체지향 Study 2회차

Geun Bo Kim·2023년 4월 10일
0

스터디

목록 보기
3/6

질문1

사용관계, 포함관계, 상속관계의 정확한 설명

  • 고예진 (답변자)
    사용관계상속관계포함관계
    정의객체간의 상호작용을 의미하며, 객체는 다른 객체의 메소드를 호출하여 원하는 결과를 얻음기존 클래스에, 이미 만들어진 클래스를 재 사용하여 새로운 클래스를 작성하는 것상속처럼 클래스를 재사용할 수 있는 방법인데, 다른 클래스의 객체를 자신의 멤버로 사용하는 것
    상속관계(~은 ~이다)
    • extends와 함께 써준다.

    • 자손 클래스는 조상 클래스의 모든 멤버를 상속받으며, 자손 클래스의 개수는 조상 클래스보다 항상 같거나 많다.

    • 단일 상속만 가능하다
      - 다중상속을 허용하면 클래스간의 관계가 복잡해지는 문제가 생김
      - 만약, 자식 클래스에서 상속받는 서로 다른 부모 클래스들이 같은 이름의 멤버를 가지고 있다면 자식 클래스에서는 이 멤버를 구별할 수 있는 방법이 없음

      포함관계(~은 ~을 가지고 있다.)

    • 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것이다.
      (클래스의 속성 값에 다른 클래스를 선언하여 사용하는 것이다.)

  • 질문 (김은양)

    상속관계와 포함관계의 차이가 모호한 것 같다. 둘을 구분할 수 있는 추가 설명이 있으면 좋을 것 같다.

  • 김은서

    포함관계와 상속관계를 그림으로 나타내면 다음과 같다. (왼쪽이 포함관계, 오른쪽이 상속관계)

    포함관계는 하위 객체가 모여 상위 객체를 이루는 식이다.

    반면 상속관계는 상속이라는 개념이 중요한데, 여기서 상속이란 재산 상속의 개념이 아니라 유전 상속의 개념과 비슷하다. 상위 객체가 가지고 있는 특성이 있다면 그걸 따라 하위 객체 또한 같은 특성을 가지게 되며 비유하자면 하위 객체끼리 비슷한 분위기가 연출된다.

    (왼쪽 그림) 하위객체인 문과 핸들, 타이어가 결합되어 상위 객체인 자동차를 이룬다.

    (오른쪽 그림) 상위 객체인 대중교통은 사람이 많이 이용할 수 있고 정해진 루트가 있다는 특성이 있다. 이에 따라 하위 객체인 버스와 지하철 또한 상속을 통해 같은 특성을 지니게 된다.

    은양님께서 하신 질문처럼 상속관계와 포함관계를 한 눈에 구별하기 위해서는 해석이 필요하다고 생각한다.

    예진님께서 하신 설명에도 있는 내용인데, 포함관계의 경우 하위 객체가 상위 객체에 포함된다. 라고 해석이 되고 상속관계의 경우 하위 객체는 상위 객체이다. 라고 해석이 된다.

    문과 핸들, 타이어는 자동차에 포함이 되고, 버스와 지하철은 대중교통이다. 라고 해석할 수 있는 것이다.

    이렇게 해석을 해 보면 둘을 더 명확히 구분 지을 수 있다.

  • 김근보

    (1)사용관계 : 한 객체가 다른 객체를 사용하는 것을 의미.

    객체간의 상호작용을 통해 기능을 수행.

    -직접적인 사용관계 : 한 객체가 다른 객체를 필드나 메소드의 인자로 전달하여 사용하는 경우

    -간접적인 사용관계 : 객체가 직접 다른 객체를 사용하지 않고 중간에 또 다른객체를 거쳐서 기능을 수행(다른 객체 내부에 포함되지 않고, 서로 간접적인 사용관계를 가지는 것)

    (2)포함관계는 객체를 다른 객체의 멤버 변수로 포함시키는 관계를 의미합니다.

    즉, 객체 A가 객체 B를 포함하고 있다는 것은 객체 A가 객체 B를 사용하고 있으며, 객체 B가 없으면 객체 A도 정상적으로 동작할 수 없다는 것을 의미(3)상속관계는 부모 클래스와 자식 클래스 간의 관계를 의미합니다.

    자식 클래스는 부모 클래스의 특성을 그대로 물려받아 사용할 수 있으며, 부모 클래스에서 정의된 메서드와 변수를 자식 클래스에서 사용할 수 있다. (자식 클래스는 부모클래스보다 같거나 크다)

질문2

클래스랑 인스턴스의 차이

  • 김은양 (답변자)
    • 클래스 설계도 인스턴스를 만들기 위해서 클래스가 필요하다. 클래스 구성 멤버 = 필드(속성, 변수) + 생성자 + 메서드
      • 클래스를 만들기 위한 4단계 1.클래스 선언 (public 과 같은 접근제어자는 본인의 선택)
        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)’라고도 부른다.

질문3

필드, 생성자, 메서드의 설명

  • 장기웅 (답변자) 필드 필드는 객체의 속성으로써 데이터를 저장하는 역할을 합니다. (변수들을 저장하는 영역) 자동차를 객체로 만들기위해 클래스를 설계할때(예시) String 타입의 company 변수 선언 : 자동차 회사명을 저장합니다. double 타입의 price 변수 선언 : 자동차의 가격을 저장합니다. char 타입의 gear 변수 선언 : 자동차의 기어 상태를 저장합니다. boolean 타입의 lights 변수 선언 : 자동차의 조명 상태를 저장합니다. 생성자 인스턴스가 생성될 때마다 호출되는 "인스턴스 초기화 메서드"
    Time () {       // 생성자 선언 
    //인스턴스 초기화 작업
    }
    Time t = new Tine();   // 다른 클래스에서 생성자 호출
    생성자 특징 생성자는 반환값(리턴값)이 없고 이름은 클래스의 이름과 동일합니다. 괄호( ) 안에 아무것도 없는 생성자를 기본 생성자라 합니다.(매개변수가 없다) // 모든 클래스에는 기본 생성자가 존재해야 한다,(생성자가 클래스안에 하나도 없을 때만, 컴파일러가 자동 추가) 생성자도 메서드 처럼 오버로딩이 가능하다. 가비지 컬렉터에 지워지지 않기 위해 생성자로 인스턴스를 초기화 해줘야 한다. 참조변수 주소는 스택영역에 쌓이고 변수 원본값을 저장하는데 원본값은 힙영역에 쌓인다. 메서드 코드의 중복을 줄이기 위해 문장들을 묶어 놓은 것 // 두개의 배열을 반복문으로 돌려야하는 상황일때 코드를 메서드로 묶어줄수 있다.
    반환타입 이름 (매개변수) {   //선언부  
    // 구현부
    }
    메서드는 구현부와 선언부로 나뉜다.
    만약 배열을 다른 방식으로 사용하고 싶다면 메서드만 고쳐주면 된다.
  • 김은서 필드와 생성자, 메서드는 앞으로도 계속 사용되는 중요한 개념이라 지금 같이 코딩을 하며 개념을 완벽하게 이해하고 가는 게 중요한 것 같다. 다같이 코딩하며 개념을 이해하자. 우선 Person이라는 클래스를 만들었다. 해당 클래스는 필드 두 개와 해당 필드를 초기화 하는 생성자 하나, 메서드 하나가 필요하다. 또한 main 클래스에서 Person 클래스를 인스턴스화 하여 메서드를 호출하고 싶다. 코딩 해 보자 !
    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();
    
        }
    
    }
  • 김근보 필드, 생성자, 메서드의 설명
    • 필드(Field): 클래스 내부에서 데이터를 저장하는 변수를 의미합니다. 인스턴스 변수와 클래스 변수로 나뉘며, 인스턴스 변수는 객체마다 다른 값을 가지고 클래스 변수는 모든 객체가 공유하는 값을 가집니다.
    • 생성자(Constructor): 객체가 생성될 때 호출되는 메서드로 객체의 초기화를 담당합니다. 일반적으로 인스턴스 변수를 초기화하거나 객체 생성 시 필요한 작업을 수행합니다. 생성자는 클래스 이름과 동일하며, 리턴 타입이 없습니다.
    • 메서드(Method): 클래스 내부에서 특정한 기능을 수행하는 코드 블록을 의미합니다. 객체의 상태를 변경하거나, 특정한 값을 반환할 수 있습니다. 메서드는 인스턴스 메서드와 클래스 메서드로 나뉘며, 인스턴스 메서드는 객체가 생성된 후 호출되는 메서드이고, 클래스 메서드는 클래스 이름으로 직접 호출되는 메서드입니다.

질문4

클래스 내 클래스 변수는 인스턴스가 여러개 생성되어도 인스턴스끼리 클래스 변수의 값을 공유한다고 합니다.
만약 인스턴스1에서 클래스 변수 값을 지정해주고 인스턴스2에서 클래스 변수 값을 재지정 해주면 어떻게 되나요?
// 만약 재지정이 된다면 기존 값은 참조불가능으로 분류되어 GC가 처리해주나요?

  • 김근보 (답변자) 인스턴스 1에서 지정한 값이 2 값으로 재지정됨 왜 why? 클래스 변수가 인스턴스와는 독립적으로 존재하기 때문 클래스 변수는 클래스 영역에 저장되기 때문에 인스턴스 간에 공유되는 것. 요약: 클래스 변수 → 클래스에 속함 / 클래스 변수는 해당 클래스의 모든 인스턴스에서 동일한 값을 가지고 있음 ⇒ 만약 재지정이 된다면 기존 값은 참조불가능으로 분류되어 GC가 처리해주나요? 참조 불가능으로 분류되어 GC가 처리되는 개념은 변수가 아닌 객체를 가리키는 레퍼런스가 적용되는 것
    • 래퍼런스(Reference)

      객체를 생성하면 JVM(Java Virtual Machine)은 Heap 메모리 영역에 객체를 저장하고, 그 객체를 참조하기 위한 래퍼런스를 스택(Stack) 메모리 영역에 생성합니다. 이 래퍼런스는 객체의 주소를 저장하고, 이를 통해 래퍼런스를 통해 객체를 참조하거나 객체에 접근할 수 있습니다. 따라서 래퍼런스는 객체의 실제 값이 아니라, 객체의 위치를 가리키는 주소값을 저장함.

질문5

(강의 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();
    }
}
  • 위의 코드를 약간 수정 해 보았습니다. Main 클래스 실행 시 출력 값은 무엇인가요? 에러가 발생한다면 어떤 에러가 발생할 것 같고 그 이유는 무엇인가요?

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();
    }
}
  • 신동현 (답변자) 첫 문제에서는 두개의 ColaCan 객체가 생성되고, 이들이 생성될 때마다 정적 변수인 numCreated가 증가 됩니다.  따라서 콜라1.printStatus()를 호출한 결과로 2가 출력됩니다. 그리고, ColaCan.printStatus()를 호출하면 마찬가지로 numCreated값이 2로 출력됩니다. ColaCan클래스의 정적 메서드인 printStatus()가 호출되었기 때문입니다. printStatus()메서드는 클래스의 모든 객체가 공유하는 정적변수 numCreated값을 출력합니다. 두번째 질문에서는 Main클래스 실행시 getMl()메서드를 사용하여 콜라 객체의 용량을 출력하려고 하지만, 이 메서드는 인스턴스 메서드이므로 정적인 printStatus()메서드 내에서는 사용할  수 없습니다. 따라서 getMl()메서드도 정적인 메서드로 변경해야 하지만, 이 경우 콜라의 용량이 객체마다 다르기 때문에 정적인 메서드로는 적합하지 않습니다.   그렇기 때문에 콜라1과 콜라2의 용량을 따로 출력하려면 printStatus()메서드를 인스턴스 메서드로 변경해야 합니다. 인스턴스 메서드로 변경하면 객체 인스턴를 참조할 수 있으므로, ml값을 출력할 수 있습니다. 또는 printStatus()메서드에 매개변수로 ColaCan 객체를 전달하는 방법도 있습니다. 이 경우 printStatus()메서드가 호출될 때 인자로 전달된 ColaCan객체의 ml값을 출력할 수 있습니다.
  • 김건 → (질문 의도) 정적인 객체(static)에서 비정적인 객체(non static)를 바라볼 수 없음 → 여러분이 System.out.println()을 사용할 때 System 인스턴스를 생성했나요? 댓츠 노노 out 이 친구는 static이라 어디에서든 사용을 할 수 있답니다. 그렇듯 ColaCan을 따로 인스턴스로 만들어 printStatus()를 호출할 필요 없다! 그냥 (클래스 이름).(static 메서드) 로 호출 가능!
profile
미래는 개발이다

0개의 댓글