클래스의 상속과 다형성
클래스의 상속은 부모 클래스의 멤버(필드, 메서드, 이너클래스)를 내려받아 자식 클래스 내부에 포함시키는 것
Do it 자바 자료 참고

공통적인 부분이 부모클래스
상속의 장점은 ? 코드의 중복성 제거 (공통부분은 여러번 적을필요 X)
다형적 표현 가능O (부모(사람) ← 자식(직장인or대학생) O) 직장인은 사람이다. O
(부모)사람→ (자식)직장인 X 사람은 직장인이다. X

상속 문법
상속 문법 O | 자바의 클래스는 다중 상속 불가 |
class 자식클래스 extends 부모클래스 { } |
부모클래스가 하나인데 자식클래스 여러개는 가능!
클래스의 상속과 사용할 수 있는 멤버변수
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() {};
}
public class Inheritance {
public static void main(String[] args) {
// Human 객체 생성
Human h = new Human();
h.name = "김현지";
h.age = 11;
h.eat();
h.sleep();
// Student 객체 생성
Student s = new Student();
s.name = "이민성"; // Human이 가지고 있는 속성
s.age = 18;
s.eat();
s.sleep();
s.studentID = 20230427; // 추가로 정의한 멤버
s.goToSchool(); // 추가로 정의 한 멤버
// Worker 객체 생성
Worker w = new Worker();
w.name = "박영훈";
w.age = 33;
w.eat();
w.sleep();
w.workerID = 19901211; // 추가로 정의한 멤버
w.goToWork(); // 추가로 정의한 멤버
}
}
상속을 이용한 객체의 다형적 표현
책의 예제
// 상속관계 만들기
class A {}
class B extends A {}
class C extends B {}
class D extends B {}
public class Polymorphism {
public static void main(String[] args) {
// A 타입의 다형적 표현
A a1 = new A(); // A는 A이다 O
A a2 = new B(); // B는 A이다 O
A a3 = new C(); // C는 A이다 O
A a4 = new D(); // D는 A이다 O
// B 타입의 다형적 표현
// B b1 = new A(); // A는 B이다 X
B b2 = new B(); // B는 B이다 O
B b3 = new C(); // C는 B이다 O
B b4 = new D(); // D는 B이다 O
// C 타입의 다형적 표현
// C c1 = new A(); // A는 C이다 X
// C c2 = new B(); // B는 C이다 X
C c3 = new C(); // C는 C이다 O
// C c4 = new D(); // C는 D이다 X
// D 타입의 다형적 표현
// D d1 = new A(); // A는 D이다 X
// D d2 = new B(); // B는 D이다 X
// D d3 = new C(); // C는 D이다 X
D d4 = new D(); // D는 D이다 O
}
}
다형적 표현이라는 것을 개념적으로 이해 하기 위해서 한 번 바꿔서 해 봄
// 상속관계 만들기Animal
class Animal {}
class Bird extends Animal {}
class Charly extends Bird {}
class Demian extends Bird {}
public class Polymorphism {
public static void main(String[] args) {
// Animal 타입의 다형적 표현
Animal a1 = new Animal(); // Animal는 Animal이다 O
Animal a2 = new Bird(); // Bird는 Animal이다 O
Animal a3 = new Charly(); // Charly는 Animal이다 O
Animal a4 = new Demian(); // Demian는 Animal이다 O
// Bird 타입의 다형적 표현
// Bird b1 = new Animal(); // Animal는 Bird이다 X
Bird b2 = new Bird(); // Bird는 Bird이다 O
Bird b3 = new Charly(); // Charly는 Bird이다 O
Bird b4 = new Demian(); // Demian는 Bird이다 O
// Charly 타입의 다형적 표현
// Charly c1 = new Animal(); // Animal는 Charly이다 X
// Charly c2 = new Bird(); // Bird는 Charly이다 X
Charly c3 = new Charly(); // Charly는 Charly이다 O
// Charly c4 = new Demian(); // Charly는 Demian이다 X
// Demian 타입의 다형적 표현
// Demian d1 = new Animal(); // Animal는 Demian이다 X
// Demian d2 = new Bird(); // Bird는 Demian이다 X
// Demian d3 = new Charly(); // Charly는 Demian이다 X
Demian d4 = new Demian(); // Demian는 Demian이다 O
}
}
객체의 타입 변환
객체 타입 변환 - 업캐스팅과 다운캐스팅
사람 | 업캐스팅 | 학생은 사람이다 | 항상 O |
▲ | |||
학생 | 다운캐스팅 | 사람은 학생이다. | 학생인 사람이라면 O 학생이 아닌 사람이라면 X |
* 객체는 항상 업캐스팅을 할 수 있으므로 명시적으로 적어주지 않아도 컴파일러가 알아서 넣어준다.
* 다운캐스팅은 개발자가 직접 명시적으로 넣어줘야한다.
* 잘못된 다운캐스팅을 수행하게 된다면 ClassCastException이라는 예외가 발생하고, 프로그램이 종료된다.

선언 타입에 따른 사용할 수 있는 멤버
class A {
int m = 3;
void abc() {
System.out.println("A 클래스");
}
}
class B extends A {
int n =4;
void def() {
System.out.println("B 클래스");
}
}
public class Typecastion_2 {
public static void main(String[] args) {
// A 타입 / A 생성자
A aa = new A();
System.out.println(aa.m); // 3
aa.abc(); // A 클래스
// B 타입 / B 생성자
B bb = new B();
System.out.println(bb.m); // 3
System.out.println(bb.n); // 4
bb.abc(); // A 클래스
bb.def(); // B 클래스
// A 타입 / B 생성자 : 다형적 표현
A ab = new B();
System.out.println(ab.m); // 3
ab.abc(); // A 클래스
}
}
캐스팅 가능 여부를 확인하는 instanceof 키워드
규모가 커지거나 소스코드가 길어지면 생성 객체 타입 확인이 어려우므로, 캐스팅 가능여부를 확인 할 수 있는 키워드
참조변수 instanceof 타입 | true 캐스팅가능 | false 캐스팅불가 |
캐스팅 가능 여부를 확인할 수 있는 instanceof
/* 캐스팅 가능 여부를 확인 할 수 있는 instanceof */
class AA {}
class BB extends AA{}
public class Typecasting_3 {
public static void main(String[] args) {
// instanceof
AA aa = new AA();
BB aabb = new BB();
System.out.println(aa instanceof AA); // true
System.out.println(aabb instanceof AA); // true
System.out.println(aa instanceof BB); // false
System.out.println(aabb instanceof BB); // true
if(aa instanceof BB) {
BB bb = (BB)aa;
System.out.println("aa 를 BB 로 캐스팅 했습니다.");
} else {
System.out.println("aa는 BB 타입으로 캐스팅 불가능 !!"); // 출력
}
if(aabb instanceof BB) {
BB bb = (BB)aabb;
System.out.println("aabb 는 BB 캐스팅 했습니다."); // 출력
} else {
System.out.println("aabb는 BB 타입으로 캐스팅 불가능 !!");
}
if("안녕" instanceof String){
System.out.println("\"안녕\"은 String 클래스입니다. "); // 출력
}
}
}
메서드 오버라이딩
메서드 오버라이딩의 개념과 동작
메서드 오버라이딩은 부모 클래스에게 상속받은 메서드와 동일한 이름의 메서드를 재정의 하는 것
ex. 우리가 동일한 위치에 동일한 파일을 저장할때 덮어쓰기가 수행되는 것과 같은 원리(똑같지는 않음)
* 부모 클래스의 메서드와 시그니처(매서드명, 입력매개변수의 타입과 개수) 및 리턴 타입이 동일해야 한다.
* 부모 클래스의 메서드보다 접근 지정자의 범위가 같거나 넓어야 한다.
메서드 오버라이딩의 대표적인 예
class Animal {
void cry() {}
}
class Bird extends Animal {
@Override
void cry() {
System.out.println("짹짹");
}
}
class Cat extends Animal{
@Override
void cry() {
System.out.println("야옹");
}
}
class Dog extends Animal {
@Override
void cry() {
System.out.println("멍멍");
}
}
public class MethodOverriding_2 {
public static void main(String[] args) {
// 각 타입으로 선언 + 각 타입으로 생성
Animal aa = new Animal();
Bird bb = new Bird();
Cat cc = new Cat();
Dog dd = new Dog();
aa.cry();
bb.cry(); // 짹짹
cc.cry(); // 야옹
dd.cry(); // 멍멍
System.out.println();
// Animal 타입으로 선언 + 자식 클래스 타입으로 생성
Animal ab = new Bird();
Animal ac = new Cat();
Animal ad = new Dog();
ab.cry(); // 짹짹
ac.cry(); // 야옹
ad.cry(); // 멍멍
System.out.println();
// 배열로 관리
Animal[] animals = {ab, ac, ad};
for(Animal animal : animals) {
animal.cry(); // 짹짹 야옹 멍멍
}
}
}
* 메서드 오버라이딩과 메서드 오버로딩

메서드 오버라이딩과 메서드 오버로딩 예
class AAA {
void print1() {
System.out.println("A 클래스 print1");
}
void print2() {
System.out.println("A 클래스 print2");
}
}
class BBB extends AAA {
@Override
void print1() {
System.out.println("B 클래스 print1");
}
void print2(int a) {
System.out.println("B 클래스 print2");
}
}
public class MethodOverriding_3 {
public static void main(String[] args) {
// A 타입 선언 / A 생성자 사용
AAA aaa = new AAA();
aaa.print1(); // A클래스 print1
aaa.print2(); // A클래스 print2
System.out.println();
// B 타입 선언 / B 생성자 사용
BBB bbb = new BBB();
bbb.print1(); // A클래스 print1
bbb.print2(); // A클래스 print2
bbb.print2(3); // B클래스 print2
System.out.println();
// A 타입 선언 / B 생성자 사용
AAA aba = new BBB();
aba.print1(); // B클래스 print1
aba.print2(); // A클래스 print2
}
}
메서드 오버라이딩과 접근 지정자
부모 클래스 메서드의 접근 지정자 | 메서드 오버라이딩 할 때 사용할 수 있는 접근 지정자 |
public | public |
protected | public, protected |
default | public, protected, default |
private | public, protectec, default, private |
메서드 오버라이딩 할 때 사용할 수 있는 접근 지정자 |
* 사실 이건 잘 모르게..따리
인스턴스 필드와 정적 멤버의 중복
인스턴스 필드의 중복
class Apple {
int m = 3;
}
class Banana extends Apple {
int m = 4;
}
public class OverlapInstanceField {
public static void main(String[] args) {
// 객체 생성
Apple aa = new Apple();
Banana bb = new Banana();
Apple ab = new Banana();
// 인스턴스 필드
System.out.println(aa.m); // 3
System.out.println(bb.m); // 4
System.out.println(ab.m); // 3
}
}
정적필드의 중복
class E {
static int m = 3;
}
class F extends E {
static int m = 4;
}
public class OverlapStaticField {
public static void main(String[] args) {
// 클래스명으로 바로 접근
System.out.println(E.m); // 3
System.out.println(F.m); // 4
System.out.println();
// 객체 생성
E ee = new E();
F ff = new F();
E ef = new F();
// 생성한 객채로 정적 필드 호출
System.out.println(ee.m); // 3
System.out.println(ff.m); // 4
System.out.println(ef.m); // 3
}
}
정적 메서드의 중복
class W {
static void print() {
System.out.println("W 클래스");
}
}
class Q extends W {
static void print() {
System.out.println("Q 클래스");
}
}
public class OverlapStaticMethod {
public static void main(String[] args) {
// 클래스명으로 바로 접근
W.print(); // W 클래스
Q.print(); // Q 클래스
System.out.println();
// 객체 생성
W ww = new W();
Q qq = new Q();
W wq = new Q();
// 객체를 통한 메서드 호출
ww.print(); // W 클래스
qq.print(); // Q 클래스
wq.print(); // W 클래스
}
}
* 인스턴스 멤버와 정적 멤버의 중복 정리
인스턴스 멤버 / static 멤버 오버라이딩Overriding 여부
인스턴스 필드 | 인스턴스 메서드 | 정적 static 필드 | 정적 static 메서드 |
오버라이딩 X | 오버라이딩 O | 오버라이딩 X | 오버라이딩 X |
메서드 오버라이딩 | |||
A a = new B(); | |||
A 인스턴스(instance) 필드 정적(static)필드 정적(static)메서드 |
B() 인스턴스(instance) 메서드 |
super 키워드와 super() 메서드
부모의 객체를 가리키는 super 키워드
멤버 앞에 있는 참조변수를생략(this.) 했을 때의 메서드 호출
class A {
void abc() {
System.out.println("A클래스의 abc()");
}
}
class B extends A {
void abc() {
System.out.println("B클래스의 abc()");
}
void bcd() {
abc(); // this.abc();
}
}
public class SuperKeyword_1 {
public static void main(String[] args) {
// 객체 생성
B bb = new B();
// 메서드 호출
bb.bcd(); // B클래스의 abc()
}
}
멤버 앞에 있는 super 키워드를 사용했을 때으 메서드 호출
class C {
void abc() {
System.out.println("C클래스의 abc()");
}
}
class D extends C {
void abc() {
System.out.println("D클래스의 abc()");
}
void bcd() {
super.abc(); // 부모 클래스 객체의 abc() 메서드 호출
}
}
public class SuperKeyword_2 {
public static void main(String[] args) {
// 객체 생성
D dd = new D();
// 메서드 호출
dd.bcd(); // C클래스의 abc()
}
}
super()메서드의 기능 및 컴파일러에 따라 super() 자동 추가
package superMethod;
class A {
A() {
System.out.println("A 생성자");
}
}
class B extends A {
B() {
super(); // 생략했을 때 컴파일러가 자동 추가(부모클래스의 생성자 호출)
System.out.println("B 생성자");
}
}
class C {
C(int a) {
System.out.println("C 생성자");
}
}
class D extends C {
D() {
super(3);
}
}
public class SuperMethod_1 {
public static void main(String[] args) {
// A 객체 생성
A aa = new A(); // A 생성자
System.out.println();
// B 객체 생성
B bb = new B(); // B 생성자
}
}
this() 메서드와 super() 메서드의 혼용
package superMethod;
class AA {
AA() {
this(3);
System.out.println("AA 생성자 1");
}
AA(int a) {
System.out.println("AA 생성자 2");
}
}
class BB extends AA{
BB() {
this(3);
System.out.println("BB 생성자 1");
}
BB(int a) {
System.out.println("BB의 생성자 2");
}
}
public class SuperMethod_2 {
public static void main(String[] args) {
// AA 객체 생성
AA aa1 = new AA();
System.out.println();
AA aa2 = new AA(3);
System.out.println();
// BB 객체 생성
BB bb1 = new BB();
System.out.println();
BB bb2 = new BB(3);
}
}
출력 결과
AA 생성자 2
AA 생성자 1 // aa1
AA 생성자 2 // aa2
AA 생성자 2
AA 생성자 1
BB의 생성자 2
BB 생성자 1 // bb1
AA 생성자 2
AA 생성자 1
BB의 생성자 2 // bb2
왜 2가 먼저 나올까?? this. 로가서 해당하는 int a 가 있는 거 먼저 받고 다음으로 실행되는거 같긴함..
으아아ㅏ..
최상위 클래스 Object
자바의 모든 클래스는 Object를 상속받는다.
Object 클래스
자바의 모든 클래스는 Object의 자식 클래스 = 자바의 모든 클래스는 Object의 메서드를 가짐

ObjectMethod_toString
class A {
int a = 3;
int b = 4;
}
class B {
int a =3;
int b =4;
public String toString() {
return "필드값(a, b) = " + a +" "+ b;
}
}
public class ObjectMethod_toString {
public static void main(String[] args) {
// 객체 생성
A a = new A();
B b = new B();
// 메서드 호출
System.out.printf("%x\n", a.hashCode()); // hashcode를 16진수로 표현
System.out.println(a.toString()); // toString()을 생략했을때는 자동으로 추가
System.out.println(b);
}
}
ObjectMethod_equals
class AA {
String name;
AA(String name) {
this.name = name;
}
}
class BB {
String name;
BB(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(this.name == ((BB)obj).name) {
return true;
} else return false;
}
}
public class ObjectMethod_equals {
public static void main(String[] args) {
AA a1 = new AA("안녕");
AA a2 = new AA("안녕");
System.out.println(a1 == a2); //false
System.out.println(a1.equals(a2)); // false
BB b1 = new BB("안녕");
BB b2 = new BB("안녕");
System.out.println(b1 == b2); // false
System.out.println(b1.equals(b2)); // true
}
}
ObjectMethod_hashcode
import java.util.HashMap;
class AAA {
String name;
AAA(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(this.name == ((AAA)obj).name) {
return true;
} else return false;
}
@Override
public String toString() {
return name;
}
}
class BBB {
String name;
BBB(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(this.name == ((BBB)obj).name) {
return true;
} else return false;
}
@Override
public String toString() {
return name;
}
}
public class ObjectMethod_hashcode {
public static void main(String[] args) {
HashMap<Integer, String> hm1 = new HashMap<>();
hm1.put(1, "데이터1");
hm1.put(1, "데이터2");
hm1.put(2, "데이터3");
System.out.println(hm1);
// {1=데이터2, 2=데이터3}
HashMap<AAA, String> hm2 = new HashMap<>();
hm2.put(new AAA("첫 번째"), "데이터1");
hm2.put(new AAA("첫 번째"), "데이터2");
hm2.put(new AAA("두 번째"), "데이터3");
System.out.println(hm2);
// {첫 번째=데이터2, 첫 번째=데이터1, 두 번째=데이터3}
HashMap<BBB, String> hm3 = new HashMap<>();
hm3.put(new BBB("첫 번째"), "데이터1");
hm3.put(new BBB("첫 번째"), "데이터2");
hm3.put(new BBB("두 번째"), "데이터3");
System.out.println(hm3);
// 첫 번째=데이터2, 두 번째=데이터3, 첫 번째=데이터1}
}
}
'JAVA SPRING > java' 카테고리의 다른 글
JAVA_010) 참조자료형( 배열, 문자열 저장 ) (1) | 2023.04.26 |
---|---|
JAVA_009) 클래스외부(패키지,임포트), 자바제어자(public,protected,default,private), Static (0) | 2023.04.26 |
JAVA_008) 클래스와 객체, 클래스의 내부 구성요소(생성자, this키워드, this()메서드) (0) | 2023.04.25 |
JAVA_007) 컬렉션 프레임워크 - List, Map, Set (0) | 2023.04.03 |
JAVA_006) 객체지향개념_3 개념적인 메소드 설계&실행2 (0) | 2023.03.16 |