🌞 Day 013 : class의 상속, Object클래스, toString, equals 



 🐬 상속 

  • 어제 마지막에 수업 했던 Extends04 class를 이어서 수업

  • 상속된 자식 클래스의 객체가 만들어질 때,
    자식 클래스의 생성자가 먼저 호출되고,
    자식클래스의 첫 번째 명령은 부모클래스의 생성자 호출이다.

  • super();는 일부러 밖에 꺼내 쓰지 않아도 이미 자식클래스의 생성자의 첫 번째 줄에 존재하는 명령이다.

  • 다만 super();는 부모클래스의 생성자 중 매개변수가 없는 디폴트 생성자를 호출하는 명령이므로, 혹시라도 부모클래스의 생성자가 매개변수 있는 생성자로 대체되었다면 이는 에러를 발생한다.

  • 이 에러를 해결할 수 있는 방법

    1. 부모클래스의 매개변수 형태 대로 호출
      -> super();에 전달인수를 넣어준다. super(10);

    2. 부모클래스의 생성자를 오버로딩해서 자식클래스 생성자에서 호출하는 형태로 부모클래스의 생성자 추가

      ∴ 부모클래스의 생성자 형태로 호출하거나,
         자식클래스 생성자에서 호출하는 형태로 부모클래스의 생성자를
         추가하거나

  • 자식 클래스의 오버로딩된 생성자의 첫 번째 실행코드는
    super();혹은this();가 올 수 있다
    BUT 한 번에 둘 다 올 수는 없다.

  • 아무것도 쓰지 않으면 super();를 호출한다.
    이 때, 공교롭게도 부모클래스의 디폴트 생성자가 없다면 ERROR!!

  • 여기서 선택할 사항은 부모클래스의 생성자에 맞게 호출하던가,
    이미 (부모클래스를 형태에 맞춰서) 호출하고 있는 형제 생성자를,
    this();를 이용해서 재호출 하던가

 💙 정리 

  • 오버로딩된 생성자 모두 첫 번째 명령이 this();일 수는 없다.

  • 여러 생성자 중 하나는 반드시 super();가 있어야 한다.

  • 자식클래스 생성자에서 super를 호출했으면,
    "그에 맞게 오버로딩된 부모 생성자가 있거나", 없으면
    "지금 존재하는 부모생성자에 맞춰서 호출하거나"...


 🎯 시험 문제 

  • 부모클래스도 여러개 오버로딩 && 자식클래스도 여러개 오버로딩

  • 시험에는 (출력)순서가 바뀔 수 있음



 🐬 메서드 오버라이딩(Overriding) 

 🔸 개념 - 메서드 오버라이딩 이란? 

  • 각각의 클래스에서 발견되는 공통변수, 메서드 등을 하나의 클래스로 만들어 다른 클래스에게 물려주는 것이 "상속"

  • 부모클래스에서 정의되는 변수, 메서드들은 (private 제외)
    모든 자식클래스에서도 정상적으로 동작해야 하므로 부모자식에 공통으로 적용할 수 있는 사항들이 정의되고는 한다.

  • 하지만 가끔 상속 받은 메서드들이 자식 클래스의 생성 목적이나 용도에 따라 어울리지 않는 메서드일 가능성이 있다.

  • 이 때, 자식클래스에서 물려받은 부모클래스의 메서드를 재정의 하여 사용하는데, 이를 메서드 오버라이딩(overriding) 이라고 한다.

  • 자식클래스는 부모클래스에서 물려받은 메서드를 자신의 용도에 맞게 재정의(overriding)할 수 있다.

  • 메서드 오버라이딩은 자식클래스에서 부모클래스의 메서드의 내용을 다시 정의하는 문법이다.

  • 메서드 오버라이닝으로 메서드를 재정의하면 자식클래스의 객체에서 물려받은 메서드는 무시되고 새로 재정의한 메서드가 실행된다.

 💙정리 - 메서드 오버라이딩 

  1. 메서드 이름이 동일해야 한다.

  2. 메서드의 매개변수 타입, 개수, 순서, 리턴값 등이 다를 경우 다른 메서드로 인식한다.

  3. 부모클래스의 메서드 원형(리턴 타입, 매개변수 타입 · 개수 · 순서 등)이 일치해야 한다.

  4. 상속관계에서만 사용이 가능

  5. 접근지정자는 축소될 수 없다. (public -> private X)

  6. 부모클래스 메서드가 "final"로 정의 되어있다면 오버라이딩 할 수 없다.

  7. super.crying()처럼 super키워드를 이용하여 오버라이딩 되기 전 부모메서드를 호출 실행할 수 있다.

  8. 클래스의 외부에서는 super라는 말을 쓸 수 없으므로, 생성된 객체에 super를 붙여서 사용할 수 없다.
    예 ) Cat 클래스의 객체 c를 이용하여 c.super.crying() -> ERROR!!


 🔸 상속 - 캐스팅연산 (형 변환) 

 💙 캐스팅 연산 - 기본 

  • 기본 자료형 같의 형변환(TypeCasting)은 자료형의 크기에 제약을 받는다.

    • 자동 형변환(스마트캐스팅) : 작은용량에서 큰 용량의 변수로
      short -> int

    • 강제 캐스팅 : 큰 용량에서 작은 용량의 변수로
      int -> short
      강제 캐스팅 연산자를 앞에 붙여서 사용
      short k = (short)j;

    • 강제캐스팅도 두 자료형 간의 호환성이 있어야 가능
      String str = i; (X)String.valueOf(i); (O)
      int p = "1234"; (X)Integer.parseInt(1234); (O)

  • 클래스의 레퍼런스 변수 간의 형변환은 각 레퍼런스의 접근 범위에 영향을 받는다.

  • 서로 다른 클래스 객체 간의 형변환은 허용되지 않는다.

 💙 캐스팅 연산 - 부모-자식 클래스 간 

  1. 부모클래스의 참조변수에 자식클래스의 인스턴스주소는 아무런 조치 없이 저장 가능하다

  2. 자식클래스의 참조변수에 부모클래스의 인스턴스주소는 아무런 조치 없이 저장할 수 없다.
    자식참조변수 ← 부모 인스턴스 주소 (X)

  3. 그래도 자식클래스의 참조변수에 부모클래스의 인스턴스 주소를 저장하고 싶다면, 강제캐스팅을 이용할 수는 있다.
    SuperE super4 = new SuperE();
    SubE sub4 = (SubE) super4; // RUNTIME ERROR!!
    ※ 런타임에러(실행할 때 생기는 에러)
    : 코드 작성상에는 문제가 없으나 프로그램을 실행하면 에러가 발생

  4. 이런 런타임 에러를 방지 하려면?

    • 자식참조변수(Sub5)에 저장하려는 부모참조변수(Sper5)가 저장하고 있는 인스턴스 주소가 자식 인스턴스 주소(new SubE())였다면,

    • 즉, "자식 참조변수 <- (부모참조변수 <- 자식 인스턴스주소)"

    • 그렇다면 SubE sub5 = (SubE)super5; 이코드는 정상 실행된다.
      최종적으로 자식인스턴스 주소를 자식 참조변수에 저장한 셈이 되므로

    • 자식인스턴스 주소가 부모참조변수에 저장될 때는 문제가 없지만
      다시 나와서 자식참조변수에 저장될 때는 강제캐스팅이 반드시 필요하다.

  5.  [중요!!] 자식 인스턴스 주소를 저장한 "부모참조 변수"는 부모클래스에서 물려준 멤버들에만 접근이 가능하다. 

  • 부모참조변수(<-자식인스턴스 주소)는 부모가 물려준 멤버변수 자유롭게 사용가능하다

  • 예시) super6.subNum = 200;
    ★★★★★ ERROR!! 자식 멤버변수에는 접근이 불가능

  • ★★★★★
    부모클래스 메서드보다 재정의 된 자식클래스의 메서드가 우선 실행

  • 부모참조변수로 접근이 불가능한 자식 멤버변수를 사용하려면?
    저장된 자식 인스턴스 주소를 자식 참조변수에 옮겨담고 접근하는 수 밖에 없다.


 💙 캐스팅 연산 - instanceof 연산자 

  • 그렇다면 캐스팅연산을 하려는 참조변수가 저장하고 있는 인스턴스 주소의 타입을 어떻게 알 수 있는가?
    (부모클래스 타입인지, 자식클래스 타입인지 알 수 없는 경우엔?)

  • instanceof 연산자를 사용하여 부모와 자식클래스의 타입을 비교한다.
    주의할 점은 반드시 부모클래스는 마지막에 비교한다.

  • 부모클래스로의 캐스팅 검사가 자식캐스팅 검사보다 뒤에 있다면 자식 캐스팅 검사들의 기회가 없어질 수도 있다.



 🐬 Object 클래스 

 🔸 Object 클래스란? 

  • 개발자가 클래스 하나를 새롭게 만들면 자동으로 상속(extends)되는 클래스

  • 자바 내부에 존재하는 그리고 새롭게 만들어지는 모든 클래스는 보이지 않는 곳에 extends Object 가 존재한다.

  • 자바 내부에 존재하는 그리고 새롭게 만들어지는 모든 클래스의 부모클래스

  • 자바의 클래스는 한 클래스 당 하나의 부모클래스만 가질 수 있다.

  • Object 아닌 다른 클래스를 상속하면 그 클래스는 extends Object가 지워진다.

  • extends Object가 없는 경우는 다른 클래스를 상속하는 경우이며,
    그 부모클래스가 이미 Object를 상속하고 있기 때문에 결국 Object의 자식(손자)클래스가 된다.

 💙 Object 클래스에서 물려받은 메서드 

  • .getClass() 메소드 : 해당 객체의 클래스 이름을 리턴해주는 메서드

  • .hashCode() 메소드 : 해당 객체의 해시코드값을 리턴
    ※ 해시코드 : JVM에 의해서 관리되고 있는 다른 객체와 구분해주는 값

  • .toString() 메소드 : 해당 객체의 정보를 문자열로 리턴해주는 메서드
    .toString()을 생략하고 객체이름만 출력해도 출력 내용이 같다.
    출력 내용은 → 패키지이름.클래스이름@해시코드

    • obj 참조변수가 "패키지이름.클래스이름@해시코드"을 저장하고 있다가 출력되는 것이 아니라 Object에 있는 toString메서드가 "패키지이름.클래스이름@해시코드"를 리턴하고 print가 그것을 출력.


 🔸 toString() 메서드 

  • 메서드 오버라이딩을 할 때, 메서드이름, 변수의 개수·타입·순서 등이 전부 일치해야 한다!!!


 🔸 Object 클래스의 equals 메서드 

  • Object 클래스의 equals 메서드 : 객체 간의 비교를 위해서 사용되는 메서드

  • Object가 상속한 메서드들 중 toString과 함께 가장 많이 오버라이딩 된다.

  • ★★★★★
    Object 클래스 안의 equals 메서드는 "참조변수값들끼리" 비교하도록 제작되어 있다.

  • String 클래스 안의 equals 메서드는 글자들끼리 비교하도록 오버라이딩 되어 있다.

  • s1==s2 연산의 결과가 true라는 것은 글자가 같아서 true가 아니라, 참조값이 같아서 true라는 뜻이다. (s1,s2 모두 참조변수)

  • 예를 들어 이런 코드가 있을 때, String s1 = "Hello";
    최초 String 데이터가 새로운 공간에 저장되고 그 주소가 s1에 저장된다.

  • 그러나 String s2 = "Hello";가 실행되면, 새 공간이 만들어지는 것이 아니라, HEAP에 저장된 "Hello"의 주소를 s2에 저장한다.
    즉, new 명령이 없어서 있는 자료를 재활용한 셈이다.

  • 지금껏 String을 기본자료형인 것처럼 그냥 사용했지만 String 또한 참조변수이며, new를 사용하여 객체를 만들 수 있는 클래스이다.

  • new를 사용해서 각각 새로운 메모리를 할당해서 s1과 s2를 만들었다면 (인스턴스 주소값이 다르므로) s1==s2는 false이다.


 🔸 메서드 오버라이딩 연습하기 

 1. toString() 

  • toString() 메서드 오버라이딩 하기
    출력 양식 ⇒ "이름:XXX 나이:@@"

  • 문제 (주어진 코드)

  • 내가 작성한 메서드

 🎯 시험 문제 : equals() 오버라이딩 

  • 오버라이딩 되는 메서드의 조건
    : 리턴값의 유형, 매개변수의 유형·개수·순서가 같아야 한다.

  • equals 메서드는 어떤 클래스 내부에서도 오버라이딩 될 준비를 해야하므로 매개변수가 모든 클래스가 전달 가능하도록 모든 클래스의 부모클래스인 Object 자료형으로 정해져 있다.

  • Object는 부모참조변수이므로 자식클래스의 멤버변수에 접근이 안된다.
    Object인 매개변수가 자식클래스의 멤버변수에 접근하려면 다시 자식 클래스 형으로 변환(강제캐스팅)을 해야 한다.

  • equals() 오버라이딩 만들기

    1. 접근지정자 리턴값 이름 (매개변수) {} 작성
      public boolean equals(Object obj) { }
    2. 여기서는 Human 클래스끼리 비교하는 메서드이므로,
      Human이 아닌 다른 클래스의 인스턴스 주소인지 먼저 확인하기
      다른 클래스의 인스턴스 주소라면 더 볼 것도 없이 false 리턴
    3. Human 클래스 인스턴스 주소를 가지고 있다면,
      Human형으로 강제 캐스팅 → 자식클래스인 멤버변수에 접근하기 위해서
      (이유는 바로 위에 설명임)
    4. 비교할 멤버 변수인 name, age를 비교하고 둘 다 같으면 true를 리턴하는 코드 작성하고 끝!


 💙 연습 문제 (혼자 해보기) 

  • 문제 : toString, equals 오버라이딩

  • 내가 작성한 메서드와 출력 결과


 🎯 시험 문제 : 쇼핑하기 

  • 오늘 배운 내용이 전부 나오는 예제, 시험 가능성 매우 높음!!!

  • 클래스로 만들어질 대상 : 판매상품(TV, Computer, Audio), 구매자

  • 구매자가 상품을 사고, 환불하는 행위가 가능하도록 class와 프로그램을 제작

  • Vector

    • 벡터란 배열의 확장형 리스트 구조
      : 객체들을 저장할 수 있는 배열이라고 해도 무방
    • import해서 사용한다.
    • 사용자가 만든 클래스의 객체(메모리를 할당 받은 레퍼런스값) 등이 저장되는 다형성 객체 저장 리스트
    • 추가된 순서로 번호(index)도 설정이 되어 나중에 번호로 검색할 수 있다.
    •  .add() 
      : Vector클래스의 멤버 메서드, 벡터에 객체를 추가
      itemList.add(c); (item:벡터이름, c:벡터에 넣을 객체 이름)
      public boolean add(Object obj){}
    •  .isEmpty() 
      : Vector가 비어있으면 true, 하나라도 채워져 있으면 false를 리턴
    •  .size()  : 저장된 요소의 개수 리턴
    •  .get(n) 
      : Vector에서 저장요소를 꺼내는 멤버메서드, 0부터 시작 (n에는 꺼낼 객체의 순서를 정수로...)
    •  .remove(p) 
      : 벡터에서 상품을 삭제, remove하려는 p(객체이름)가 존재하여 잘 지워졌다면 true 리턴 아니면 false
  1. 클래스 작성하기, toString(), buy(), summary() 만들기

  2. refund() 만들기 (환불 메서드)

    • 제일먼저 itemList가 비어있으면 '해당 상품 구매한 내역이 없습니다.' 출력하기
    • 환불하려는 상품이 없으면 '해당 상품이 없습니다.' 출력
    • 벡터.remove(상품) 사용하기 .remove가 true를 리턴하면,
    • 잔액이 상품 가격만큼 늘어나고 보너스 포인트 줄어듬
    • itemList에서 상품이 삭제됨



🐣 정리하면서...

  • 오늘은 부모-자식 클래스 간의 캐스팅연산, 오버라이딩 등 어려운 내용이 많았다.
  • 코드를 여러번 반복해서 읽어야 이해가 되는 내용들이 많았다.
  • 복잡해보이지만 실제로 많이 사용하는 문법들이라고 하고 시험에도 나올 예정인 것들이 많아서 복습에 시간이 가장 오래 걸렸다.
profile
제가 공부하고 공유하고 싶은 글을 올리고 있습니다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN