
복습시간!
클래스 외부에 올 수 있는 것들 : 패키지, 임포트, 아웃 클래스
클래스 내부에 올 수 있는 것들 : 필드, 메서드, 생성자, 이너클래스
: 부모클래스의 생성자를 제외한 멤버(필드,메서드,이너클래스)를 자식클래스가 내려받아(상속) 클래스 내부에 포함하는 것
: 시스템을을 모델로 표현해주는 모델링 언어
상속 다이어 그램을 표기할 때, 자식에서 부모클래스 쪽을 화살표를 표시한다

코드의 중복성 제거
대학생 - 이름, 나이, 학번(필드) / 밥먹기, 자기, 등교하기(메서드)
직장인 - 이름, 나이, 사번(필드) / 밥먹기, 자기, 출근하기(메서드)
공통부분 사람: 이름, 나이, 밥먹기, 자기 -> 부모클래스
차이점 : 학생: 학번, 등교하기 -> 자식클래스1
회사원 : 사번, 출근하기 -> 자식클래스2
⭐️⭐️ 상속으로 인해 다형적 표현 가능
사과는 과일이다 ( 과일 fruit = new 사과() )
포도는 과일이다 ( 과일 fruit = new 포도() )
키위는 과일이다 ( 과일 fruit = new 키위() )
extends(확장) 키워드 사용
class 자식클래스 extends 부모클래스 {...}
다중 상속 불가
class 자식클래스 extends 부모클래스 1, 부모클래스 2{...}
=> 불가능 부모가 둘일 수는 없지만 자식은 여러개 가능
class Human{
String name;
int age;
void eat(){...}
void sleep(){...}
}
class Student extends Human {
int studentID;
void goToSchool(){...}
}
class Worker extends Human {
int workerID;
void goTowork(){...}
}
생성자를 제외하고 상속된다고 했는데 상속할거면 다 하지 이게 무슨 일??
다음과 같은 이유로 상속되지 않는다
class A{
A() {
}
}
class B extends A {
A() {
//만약 생성자가 들어왔다면 클래스 이름과 동일해야하는데-> 클래스 B이므로 안됨
//그러면 메서드여야 하는데 메서드는 리턴타입이 존재
}
}
복습시간!
기본자료형에서는 값의 범위를 기준으로 했다
int -> double 업캐스팅 = 자동
double -> int 다운캐스팅 = 수동
기본자료형과 달리, 상속으로 기준으로 타입변환이 이루어진다
A a = new (A) b;-> 컴파일러가 자동 업캐스팅 B b = new (B) a;좀 더 자세히 알아보면,
class A {
int m=3;
void abc() {
System.out.println("A");
}
}
class B extends A {
int n=4;
void bcd() {
System.out.println("B");
}
}
1) B로 선언타입이 된 경우
B b = new B();
System.out.println(b.m);
//가능 b가 B객체를 가리키고 있고 B객체는 A를 상속받음
System.out.println(b.n);
//자기클래스의 필드이므로 가능
b.abc();// 같은 이유로 가능
b.bcd();// 같은 이유로 가능
2) A로 선언타입이 된 경우
A a = new A();
System.out.println(a.m);
//가능 A의 자기 클래스 내의 필드임
System.out.println(a.n);
//불가능 참조변수 a는 자신의 객체인 A를 가리키고 있기 때문에 B의 내용을 상속받지 않고 내용도 없음
a.abc();//가능 자기클래스의 메서드
a.bcd();//불가능 B클래스의 메서드라 위와 같은 내용으로 불가능
: 다운캐스팅 가능여부 확인하는 참조변수 Boolean 타입
// 다운 캐스팅이 가능한 여부를 확인해보자
A a = new B();
if( a instanceof B ) {
B b = new (B)a;//true
}
: 부모 클래스에게 상속받은 메서드를 재정의하여 사용
부모클래스의 메서드와 시그니처(메서드 이름,변수타입)및 리턴타입 동일
부모클래스의 메서드보다 접근지정자는 같거나 넓어야 함->그렇지 않으면 오버라이딩 의미가 없음
class A {
void print() {
System.out.println("A클래스");
}
}
class B extends A {
void print() {//A와 동일한 메서드
System.out.println("B클래스");//B 클래스로 나온다
}
public static void main(String[] ar) {
A aa = new A();//A 클래스만들고 스택에 aa가 가르키는 곳에 A객체 만들어라
aa.print();//A클래스
B bb = new B();//B 클래스만들고 스택에 bb가 가르키는 곳에 B객체 만들어라
bb.print()://B클래스
A ab = new B();//스택에 ab가 가르키는 곳에 A를 품고 있는 B를 만들어라-> 오버라이딩
ab.print();//B클래스
}
}
Animal ab = new Bird();
Animal ac = new Cat();
Animal ad = new Dog();
ab.cry(); //짹짹
ac.cry(); //야옹
ad.cry(); //멍멍
Animal[] animals = new Animal[] {new Bird(), new Cat(), new Dog()};
for(Animal animal : animals) {
animal.cry();
//for-each문을 이용해서 animals 집합에 해당하는 원소면 출력가능
//배열로 한번에 관리할 수 있다
}
오버라이딩 : 상속에서 중복 (다 똑같음)
오버로딩 : 메서드명과 리턴타입만 같고 매개변수 다름
instance 필드도 오버라이딩 될까?
-> 오버라이딩 XXX, 제일 먼저 만나는 값으로 출력된다
class A {
int m=3;
}
class B extends A {
int m=4;
}
A ab = new B();
//A클래스가 있고 참조변수는 ab, 객체는 클래스A이므로 A 객체를 가리킨다
ab.m; //3
static 필드도 오버라이딩 될까?
-> 오버라이딩 XXX, 인스턴스 필드와 마찬가지로 먼저 만나는 값으로 출력된다
static 메서드도 오버라이딩 될까?
-> 똑같다 이렇게 했는데도 모르면,,, 돌아가라
❗️어떤 클래스로 되어있는지가 중요하다
: this 키워드는 자기 클래스의 객체 호출이었다면
super는 부모클래스의 객체 가리키는 것
-> 부모의 필드와 메서드를 호출하기 위해서 사용(상속에서의 this키워드 개념과 유사)
class A {
void abc(){
System.out.println("A클래스 abc()");
}
}
class B extends A{
void abc() {
System.out.println("B클래스 abc()");
//인스턴스 메서드 오버라이딩
}
void bcd() {
super.abc(); //A클래스 abc()
//A클래스의 void abc()를 출력
}
}
: this()는 자신의 생성자를 호출했다면 super()는 부모클래스의 생성자를 호출하는 것
class A {
A(){
System.out.println("A클래스 생성자");
}
}
class B extends A{
B() {
super();
System.out.println("B클래스 생성자");
//A클래스 생성자와 B클래스 생성자 출력
}
}
: 모든 자바 클래스의 부모클래스 = 자바의 모든 클래스는 Object의 메서드를 가짐
❗️ 즉, Object클래스를 제외하고는 모든 클래스는 상속이 되어있을 수밖에 없다.
class A extends Object{
//상속하지 않아도 자동으로 extends Object를 추가
}
class B extends A {
}
System.out.pritnln("블라블라");
// 아무렇게나 적어도 오류가 안 난 이유는 이것도 Object클래스에 속해 있기 때문이다
: 객체의 정보를 알려줌(어디 패키지이고 뭐 어디 클래스 소속인지)패키지.클래스명@해쉬코드
-> 잘 안써서 오버라이딩해서 많이들 씀
class A { //toString()을 출력하면 Object의 객체정보 출력
int a=3;
int b=4;
}
class B { //object클래스와 상속 overriding이 됨
int a=3;
int b=4;
@Override
public String toString() {
return "필드값": a="+a + ", b="+b;
}
}
public static void main(String[] ar) {
A aa = new A();
System.out.prinf("%x\n",aa.hashCode());
System.out.prntln(aa); //aa.toString 자동실행
B bb = new B();
System.out.println(bb);//bb.toString 자동 실행 오버라이딩 했던 값이 나옮
}
: 객체의 stack 메모리 주소값을 비교(비교연산자와 동일한 결과)
class A {
String name;
A(String name) {
this.name=name;
}
}
class B {
String name;
B(String name) {
this.name=name;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof B) {//B가 obj로 다운캐스팅이 가능하다면
if (this.name == ((B)obj).name)
//B다운캐스팅된 obj의 name과 이 B클래스의 name이 같다면
return true
}
return false;
}
}
public static void main(String[] ar) {
A aa1 = new A("안녕");
A aa2 = new A("안녕");
System.out.println(aa1==aa2);//false 다른 객체
System.out.pritnln)(aa1.equals(aa2)); //false 다른 객체
B bb1 = new B("안녕");
B bb2 = new B("안녕");
System.out.println(bb1==bb2); //false
System.out.pritnln)(bb1.equals(bb2)); //true
: 객체의 hashCode값 리턴(해쉬의 자료구조들 중 그 비교값을 리턴해준다)
hashMap : 데이터를 쌍으로 구성함 (key,value)
key는 절대 중복 되지 않음 -> key값이 서로 같은지를 확인하는 프로세스
정리
| 반환타입 | 메서드명 | 기능 |
|---|---|---|
| String | toString() | object의 객체정보 : package.클래스명@해쉬코드-> 일반적으로 오버라이딩 한다 |
| boolean | equals(Object obj) | 매개변수 Obj 객체와 stack 메모리 주소를 비교 -> 비교연산자와 동일한 결과 |
| int | hashCode() | 위치값을 기반으로 생성된 고유값: 객체의 hashCode()값을 리턴 / hashTable,hashMap 동등비교에 사용 [1. hashCode()일치 2. equals() true -> 동등] |
| void | wait() / wait(long timeout) / wait(long timeout, int nanos) | 현재 쓰레드를 일시정지한 상태로 전환 : 동기화 블록에서만 사용 |
| void | notify() / notifyAll() | wait()을 통해서 하나또는 전체 쓰레드를 일시정지 해제 : 동기화 블록에서만 사용 |