어제 마지막에 수업 했던 Extends04 class를 이어서 수업
상속된 자식 클래스의 객체가 만들어질 때,
자식 클래스의 생성자가 먼저 호출되고,
자식클래스의 첫 번째 명령은 부모클래스의 생성자 호출이다.
super();는 일부러 밖에 꺼내 쓰지 않아도 이미 자식클래스의 생성자의 첫 번째 줄에 존재하는 명령이다.
다만 super();는 부모클래스의 생성자 중 매개변수가 없는 디폴트 생성자를 호출하는 명령이므로, 혹시라도 부모클래스의 생성자가 매개변수 있는 생성자로 대체되었다면 이는 에러를 발생한다.
이 에러를 해결할 수 있는 방법
부모클래스의 매개변수 형태 대로 호출
-> super();에 전달인수를 넣어준다. super(10);
부모클래스의 생성자를 오버로딩해서 자식클래스 생성자에서 호출하는 형태로 부모클래스의 생성자 추가
∴ 부모클래스의 생성자 형태로 호출하거나,
자식클래스 생성자에서 호출하는 형태로 부모클래스의 생성자를
추가하거나
자식 클래스의 오버로딩된 생성자의 첫 번째 실행코드는
super();혹은this();가 올 수 있다
BUT 한 번에 둘 다 올 수는 없다.
아무것도 쓰지 않으면 super();를 호출한다.
이 때, 공교롭게도 부모클래스의 디폴트 생성자가 없다면 ERROR!!
여기서 선택할 사항은 부모클래스의 생성자에 맞게 호출하던가,
이미 (부모클래스를 형태에 맞춰서) 호출하고 있는 형제 생성자를,
this();를 이용해서 재호출 하던가
오버로딩된 생성자 모두 첫 번째 명령이 this();일 수는 없다.
여러 생성자 중 하나는 반드시 super();가 있어야 한다.
자식클래스 생성자에서 super를 호출했으면,
"그에 맞게 오버로딩된 부모 생성자가 있거나", 없으면
"지금 존재하는 부모생성자에 맞춰서 호출하거나"...
부모클래스도 여러개 오버로딩 && 자식클래스도 여러개 오버로딩
시험에는 (출력)순서가 바뀔 수 있음
각각의 클래스에서 발견되는 공통변수, 메서드 등을 하나의 클래스로 만들어 다른 클래스에게 물려주는 것이 "상속"
부모클래스에서 정의되는 변수, 메서드들은 (private 제외)
모든 자식클래스에서도 정상적으로 동작해야 하므로 부모자식에 공통으로 적용할 수 있는 사항들이 정의되고는 한다.
하지만 가끔 상속 받은 메서드들이 자식 클래스의 생성 목적이나 용도에 따라 어울리지 않는 메서드일 가능성이 있다.
이 때, 자식클래스에서 물려받은 부모클래스의 메서드를 재정의 하여 사용하는데, 이를 메서드 오버라이딩(overriding) 이라고 한다.
자식클래스는 부모클래스에서 물려받은 메서드를 자신의 용도에 맞게 재정의(overriding)할 수 있다.
메서드 오버라이딩은 자식클래스에서 부모클래스의 메서드의 내용을 다시 정의하는 문법이다.
메서드 오버라이닝으로 메서드를 재정의하면 자식클래스의 객체에서 물려받은 메서드는 무시되고 새로 재정의한 메서드가 실행된다.
메서드 이름이 동일해야 한다.
메서드의 매개변수 타입, 개수, 순서, 리턴값 등이 다를 경우 다른 메서드로 인식한다.
부모클래스의 메서드 원형(리턴 타입, 매개변수 타입 · 개수 · 순서 등)이 일치해야 한다.
상속관계에서만 사용이 가능
접근지정자는 축소될 수 없다. (public -> private X)
부모클래스 메서드가 "final"로 정의 되어있다면 오버라이딩 할 수 없다.
super.crying()처럼 super키워드를 이용하여 오버라이딩 되기 전 부모메서드를 호출 실행할 수 있다.
클래스의 외부에서는 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)
클래스의 레퍼런스 변수 간의 형변환은 각 레퍼런스의 접근 범위에 영향을 받는다.
서로 다른 클래스 객체 간의 형변환은 허용되지 않는다.
부모클래스의 참조변수에 자식클래스의 인스턴스주소는 아무런 조치 없이 저장 가능하다
자식클래스의 참조변수에 부모클래스의 인스턴스주소는 아무런 조치 없이 저장할 수 없다.
자식참조변수 ← 부모 인스턴스 주소 (X)
그래도 자식클래스의 참조변수에 부모클래스의 인스턴스 주소를 저장하고 싶다면, 강제캐스팅을 이용할 수는 있다.
SuperE super4 = new SuperE();
SubE sub4 = (SubE) super4;
// RUNTIME ERROR!!
※ 런타임에러(실행할 때 생기는 에러)
: 코드 작성상에는 문제가 없으나 프로그램을 실행하면 에러가 발생
이런 런타임 에러를 방지 하려면?
자식참조변수(Sub5)에 저장하려는 부모참조변수(Sper5)가 저장하고 있는 인스턴스 주소가 자식 인스턴스 주소(new SubE())였다면,
즉, "자식 참조변수 <- (부모참조변수 <- 자식 인스턴스주소)"
그렇다면 SubE sub5 = (SubE)super5; 이코드는 정상 실행된다.
최종적으로 자식인스턴스 주소를 자식 참조변수에 저장한 셈이 되므로
자식인스턴스 주소가 부모참조변수에 저장될 때는 문제가 없지만
다시 나와서 자식참조변수에 저장될 때는 강제캐스팅이 반드시 필요하다.
[중요!!] 자식 인스턴스 주소를 저장한 "부모참조 변수"는 부모클래스에서 물려준 멤버들에만 접근이 가능하다.
부모참조변수(<-자식인스턴스 주소)는 부모가 물려준 멤버변수 자유롭게 사용가능하다
예시) super6.subNum = 200;
★★★★★ ERROR!! 자식 멤버변수에는 접근이 불가능
★★★★★
부모클래스 메서드보다 재정의 된 자식클래스의 메서드가 우선 실행
부모참조변수로 접근이 불가능한 자식 멤버변수를 사용하려면?
저장된 자식 인스턴스 주소를 자식 참조변수에 옮겨담고 접근하는 수 밖에 없다.
그렇다면 캐스팅연산을 하려는 참조변수가 저장하고 있는 인스턴스 주소의 타입을 어떻게 알 수 있는가?
(부모클래스 타입인지, 자식클래스 타입인지 알 수 없는 경우엔?)
instanceof 연산자를 사용하여 부모와 자식클래스의 타입을 비교한다.
주의할 점은 반드시 부모클래스는 마지막에 비교한다.
부모클래스로의 캐스팅 검사가 자식캐스팅 검사보다 뒤에 있다면 자식 캐스팅 검사들의 기회가 없어질 수도 있다.
개발자가 클래스 하나를 새롭게 만들면 자동으로 상속(extends)되는 클래스
자바 내부에 존재하는 그리고 새롭게 만들어지는 모든 클래스는 보이지 않는 곳에 extends Object 가 존재한다.
자바 내부에 존재하는 그리고 새롭게 만들어지는 모든 클래스의 부모클래스
자바의 클래스는 한 클래스 당 하나의 부모클래스만 가질 수 있다.
Object 아닌 다른 클래스를 상속하면 그 클래스는 extends Object가 지워진다.
extends Object가 없는 경우는 다른 클래스를 상속하는 경우이며,
그 부모클래스가 이미 Object를 상속하고 있기 때문에 결국 Object의 자식(손자)클래스가 된다.
.getClass() 메소드 : 해당 객체의 클래스 이름을 리턴해주는 메서드
.hashCode() 메소드 : 해당 객체의 해시코드값을 리턴
※ 해시코드 : JVM에 의해서 관리되고 있는 다른 객체와 구분해주는 값
.toString() 메소드 : 해당 객체의 정보를 문자열로 리턴해주는 메서드
.toString()을 생략하고 객체이름만 출력해도 출력 내용이 같다.
출력 내용은 → 패키지이름.클래스이름@해시코드
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이다.
toString() 메서드 오버라이딩 하기
출력 양식 ⇒ "이름:XXX 나이:@@"
문제 (주어진 코드)
내가 작성한 메서드
오버라이딩 되는 메서드의 조건
: 리턴값의 유형, 매개변수의 유형·개수·순서가 같아야 한다.
equals 메서드는 어떤 클래스 내부에서도 오버라이딩 될 준비를 해야하므로 매개변수가 모든 클래스가 전달 가능하도록 모든 클래스의 부모클래스인 Object 자료형으로 정해져 있다.
Object는 부모참조변수이므로 자식클래스의 멤버변수에 접근이 안된다.
Object인 매개변수가 자식클래스의 멤버변수에 접근하려면 다시 자식 클래스 형으로 변환(강제캐스팅)을 해야 한다.
equals() 오버라이딩 만들기
public boolean equals(Object obj) { }
문제 : toString, equals 오버라이딩
내가 작성한 메서드와 출력 결과
오늘 배운 내용이 전부 나오는 예제, 시험 가능성 매우 높음!!!
클래스로 만들어질 대상 : 판매상품(TV, Computer, Audio), 구매자
구매자가 상품을 사고, 환불하는 행위가 가능하도록 class와 프로그램을 제작
Vector
itemList.add(c);
(item:벡터이름, c:벡터에 넣을 객체 이름)public boolean add(Object obj){}
클래스 작성하기, toString(), buy(), summary() 만들기
refund() 만들기 (환불 메서드)