Java/Java 수강일지

[수강일지_15] 상속성 ,다향성,오버라이드, 강제형변환(cats)

jamk-diary 2026. 5. 29. 17:50

지난 시간에 배웠던 것 

-> 캡슐화 != 은닉성 

-> 접근 지정자 private , public 

 

캡슐화, 상속성, 다형성 <_ 정석적 표현

은닉성 상속성 다형성 <_ 실용적 표현 

상속성 (inheritance)

 

부모 클래스와 자식 클래스를 생성하기 

부모 클래스에 있는 내용들을 자식 클래스로 가져온 후 자식 클래스에서 보강해서 사용하는 것 

 

클래스 생성시 부모 클래스 를 자식 클래스에 상속되게 하려면? 아래처럼 설정하기 SuperClass -> 브라우저 클릭 

sample39-MainClass

package Sample39;

 

import Child.ChildClass;

 

public class MainClass {

 

public static void main(String[] args) {

 

/*

상속성 (inheritance)

 

정의: 부모 클래스로부터 기능을 상속하는 것을 의미한다

 

기능: variabe(변수) , method(함수)-> 물려 받는 것

 

부모클래스의 인스턴스 : Super -> 부모 객체의 주소(reference)를 가리킨다

 

형식:

class 부모 클래스 {

(부모) 변수

(부모) 메소드

}

 

class 자식 클래스 extends 부모클래스 {

* 자식 로봇을 만들 때 뒤에 extends ParentClass라고만 적어주면 끝!

* 우리 눈에 보이지는 않지만 부모 클래스에서 지정한 변수와 메소드가 상속되어 저장되어 있다

 

(자식) 변수

(자식 ) 메소드

}

 

접근지정자:

아주 중요한 규칙이 있어. 바로 접근 지정자(자물쇠) 규칙

 

  • private: 비밀번호가 걸려 있어서 부모 클래스에만 쓸 수 있어. 자식 로봇도 못 열어봐! (그래서 number = 12; 가 접근 불가였던 거야.)
  • protected: 외부에선 못 열지만, 핏줄인 클래스에서는 열어주는 특별한 자물쇠야!
  • public: 누구나 다 쓸 수 있는 오픈된 공간이야.

 

*/

 

ChildClass cc = new ChildClass(); // 메인 클래스에서 new ChildClass();를 호출

 

cc.name = "홍길동";

// cc.height = 172.1; -> protected 로 부모 클래스에서 설정 되어 있음으로 자식클래스에서는 호출이 가능하나 외부 클래스에서는 접근이 불가하다

cc.parentMthod();

//cc.info();

Sample39 - ParentClass

package Sample39;

 

public class ParentClass {

 

private int number;

public String name;

protected double height;

 

public void parentMthod () {

System.out.println("parenClass parentMethod()");

}

 

protected void info() {

 

}

 

 

}

Sample39-Child

package Child;

 

import Sample39.ParentClass;

 

public class ChildClass extends ParentClass { // ChildClass 생성자

// super();  맨 첫 줄에 눈에 보이지 않는 super(); 문장을 자동으로 실행

public void func() {

// number = 12; -> 접근 불가한 이유 부모 클래스에서 private 으로 선언되어 있기 때문

name = "성춘향";

height= 152.1;

 

info();

1. [Sample 39] super() : "자식 클래스가 태어날 때의 대원칙"

이 샘플에서 가장 기억해야 하는 정석 용어는 super()야.
  • 개념: 자식 클래스의 인스턴스(객체)가 메모리에 생성될 때, 자바는 무조건 부모 클래스의 생성자를 먼저 호출하게 되어 있어. 부모 없는 자식은 없으니까!
  • 컴퓨터의 동작 순서:
    1. 메인 클래스에서 new ChildClass();를 호출해.
    2. 자바는 ChildClass 생성자로 달려가는데, 그 안의 맨 첫 줄에 눈에 보이지 않는 super(); 문장을 자동으로 실행해.
    3. 그래서 부모 클래스(ParentClass)의 생성자가 먼저 실행되면서 부모 방이 메모리에 먼저 만들어지고, 그 다음에 자식 방이 완성되는 거야.

Sample40 -MainClass

package sample40;

 

import java.security.PublicKey;

 

import Child.ChildClass;

 

public class MainClass {

 

public static void main(String[] args) {

 

 

ChildClass cc = new ChildClass();

}

 

}

 

Sample40 -ParentClass

package Parent;

 

public class ParentClass {

private String name;

 

public ParentClass() {

System.out.println("ParentClass ParentClass()");

}

public ParentClass(String name) {

System.out.println("ParentClass ParentClass(String name)");

 

}

/*

* * 기본 모양(ChildClass())으로만 생성자를 만들지 말고, 옵션(숫자)을 넣어서 생성자를 만들고 싶을 땐!

* 1번이 아니라 2번처럼 써야 된다 ! 1번 처럼 쓰면 오류 난다

 

1) private void child(int num ) {

System.out.println("childClass childClass()");

}

 

2) public ChildClass(int n ) { // 👈 void가 없고 public인 진짜 생성자!

System.out.println("ChildClass ChildClass(int n)" );

 

 

 

1번의 오류 이유

일반 메서드: 이름이 클래스명(ChildClass)과 다르고 앞에 void가 붙어 있기 때문에,

이는 생성자가 아니라 일반 메서드(함수)야.

게다가 접근 제어자가 private이라 외부 클래스에서 호출할 수 없어.

 

2번의 성공 이유

매개변수를 가진 생성자: 반환 타입(void 등)이 없고

이름이 클래스명과 완벽히 일치하므로 진짜 생성자가 맞아!

접근 제어자가 public이라 외부에서 이 생성자를 통해 인스턴스(객체)를 생성할 수 있게 되지.

*/

}

 

Sample40 -ChildClass

package Child;

 

import Parent.ParentClass;

 

public class ChildClass extends ParentClass {

 

public ChildClass() { // 기본 생성자

super("홍길동"); 👈 "부모님! '홍길동'이라는 이름 들고 먼저 태어나세요!" 하는 명령!

System.out.println("ChildClass ChildClass()");

}

public ChildClass(int n) {

// this();

System.out.println("ChildClass ChildClass(int n)");

}

}

출력결과

ParentClass ParentClass(String name)

ChildClass ChildClass()

핵심! super()와 생성자의 비밀 (출력 결과의 이유)

블로그 맨 밑에 출력 결과 적어둔 거 기억나?
"어? 나는 ChildClass만 만들었는데 왜 부모 클래스 글자가 먼저 찍히지?" 하고 놓쳤을 수 있어.
자바의 대원칙: "자식 로봇이 태어날 때는, 무조건 부모 로봇이 먼저 조립되어야 한다!" 그래서 ChildClass 내부를 보면 이렇게 적혀있지?

public ChildClass () {
super("홍길동" ); // 👈 "부모님! '홍길동'이라는 이름 들고 먼저 태어나세요!" 하는 명령!
System.out.println("ChildClass ChildClass()" );

super(...)는 부모의 생성자를 강제로 깨우는 마법 주문이야. 그래서 부모 로봇이 "나 홍길동이라는 이름으로 태어났다!" 하고 먼저 출력하고, 그 다음에 자식 로봇이 태어난 거야.

🧠 재미니의 요약 노트!

  1. private void child(int num)은 생성자 규칙에 맞지 않아서 주석으로 막아둔 버그성 예시 코드일 뿐이니 너무 심각하게 이해 안 해도 돼!
  2. 자식 로봇을 만들 땐 부모 로봇(super())이 먼저 태어난다는 것만 기억하자!

Sample41-MainClass

package Sample41;

 

import child.Pitcher;

 

public class MainClass {

 

public static void main(String[] args) {

// 자식 클래스를 생성하고 값을 저장하면

// 부모 클래스와 자식 클래스로 접근하여 멤버변수에 넣을수 있다

Pitcher pit = new Pitcher("홍길동", 24, 172.1, 10, 3, 1.23);

}

 

}

 

 

Sample41-Human

package parent;

//설명을 위한거라 주석처리

public class Human /*extends Object*/{

private String name;

private int age;

private double height;

 

public Human(String name, int age, double height) {

super();

this.name = name;

this.age = age;

this.height = height;

}

 

@Override // namespace (이름 공간 : 주석문에 해당한다)

public String toString() {

return "Human [name=" + name + ", age=" + age + ", height=" + height + "]";

}

 

 

 

}

Sample41

package child;

 

import parent.Human;

 

public class Pitcher extends Human {

private int win;

private int lose;

private double defence;

 

public Pitcher(String name, int age, double height, int win, int lose, double defence) {

super(name, age, height); //using 했더니 바로 super 로 접근 = 부모 클래스에 자식 클래스 데이터 들어가게 된다

this.win = win;

this.lose = lose;

this.defence = defence;

}

 

@Override

public String toString() {

return "Pitcher [win=" + win + ", lose=" + lose + ", defence=" + defence + "]";

}

 

}

Sample41-parent

package parent;

//설명을 위한거라 주석처리

public class Human /*extends Object*/{

private String name;

private int age;

private double height;

 

public Human(String name, int age, double height) {

super();

this.name = name;

this.age = age;

this.height = height;

}

 

@Override // namespace (이름 공간 : 주석문에 해당한다)

public String toString() {

return "Human [name=" + name + ", age=" + age + ", height=" + height + "]";

}

 

 

 

}

Sample41-child

package child;

 

import parent.Human;

 

public class Pitcher extends Human {

private int win;

private int lose;

private double defence;

 

public Pitcher(String name, int age, double height, int win, int lose, double defence) {

super(name, age, height); //using 했더니 바로 super 로 접근 = 부모 클래스에 자식 클래스 데이터 들어가게 된다

this.win = win;

this.lose = lose;

this.defence = defence;

}

 

@Override

public String toString() {

return "Pitcher [win=" + win + ", lose=" + lose + ", defence=" + defence + "]";

}

 

}

 

ChildClass method()


Sample 42-MainClass

package Sample42;

 

import child.ChildClass;

 

public class MainClass {

public static void main(String[] args) {

/*

Over Ride : 부모 클래스의 메서드를 자식 클래스가 엎어치기(재정의)했기 때문에, 재정의(Override)한 자식 클래스의 메서드가 호출된다!

*/

 

// ChildClass cc = new ChildClass();

// cc.method();

 

ChildClass pc = new ChildClass();//이렇게 되는 이유? ->

 

pc.method(); //-> 위에 있는 것이 아닌 재정의(Override)한 자식 클래스의 메서드가 호출된다 모 클래스의 메서드를 자식 클래스가 엎어치기(재정의)했기 때문에 자식의 기능이 실행되는 것이니까

// pc.func(); // 출력 안 되는 이유 -> overRide 된 메소드가 아니기 때문에 호출할 수 없다

 

}

}

Sample 42-parentClass

package parent;

 

public class ParentClass {

 

public void method() {

System.out.println("ParentClass method()");

}

 

}

Sample 42-childClass

package child;

 

import parent.ParentClass;

 

public class ChildClass extends ParentClass {

 

public void method() {

System.out.println("ChildClass method()");

}

public void func() {

 

}

 

 

 

}

Sample 42- 출력

ChildClass method()

 


다형성 (Polymorphism)과 강제 형변환 (Cast)의 핵심 원리

 

Sample43-MainClass 

package Sample43;

import child.Cat;
import child.Dog;
import parent.Animal;

public class MainClass {

public static void main(String[] args) {
 //다형성 (Ploymorphism ) 
//하나의 instance에 여러개의 객체를 저장하는 것 
// Animal ani1 = new Cat();
// Animal ani2 =new Dog();

Object ani1 = new Cat();
Object ani2 = new Dog();
//Animal ani1 = new Cat();
// Animal ani2 =new Dog();
//대신 Object를 활용해서 이렇게 쓸 수도 있다. 


String stt = new String("Hello");
Integer in =12;

Object obj = new String("Hello");
//String stt = new String("Hello"); ,Integer in =12;
//를 같이 담고 싶다면 이렇게 쓸 수도 있다. 

//고양이, 멍멍이 
Cat catArray [] = new Cat [10];
Dog dogArrat [] = new Dog[10];

Animal animal [] = new Animal [5];
animal [0] =new Dog () ;
animal [1] = new Cat ();
animal [2] =new Dog () ;
animal [3] =new Dog () ;
animal [4] = new Cat ();

//부모 클래스 타입의 배열(Animal[]) 하나로 자식 클래스인 Dog와 Cat 인스턴스들을 한 번에 관리(다형성)하기 위해서입니다.

for (int i = 0; i < animal.length; i++) {
animal[i].speech();
}
//animal[0].dog_method(); -> 에러
//- 에러 이유: 부모 타입(Animal) 상자 상태일 때는 자식 클래스만의 전용 메서드(dog_method)가 보이지 않음.
//- 해결 방법: instanceof로 진짜 Dog가 맞는지 확인한 후, (Dog) 키워드로 강제 형변환(Cast)을 해줘야 자식 전용 메서드를 깨워서 쓸 수 있음!

//부모 클래스 객체 (instance)를 자식 클래스의 객체로 변환하는 방법
//cast 변환으로 가능하다 
// Dog dog = (Dog)animal[0];
// dog.dog_method();
//
// ((Cat)animal[1]).cat_method();


//instandeof
//생성된 객체가 무엇인지 알 수 있는 키워드 


//

if(animal[0] instanceof Dog) {
 System.out.println("animal[0]는 Dog 클래스로 생성됨 ");
}

for (int i= 0; i< animal.length; i++) {
if(animal[i]instanceof  Dog) {
Dog d= (Dog)animal[i];
d.dog_method();
}

else if(animal[i]instanceof Cat) {
Cat c = (Cat)animal[i];
c.cat_method();
}

Sample43-parentClass

package parent;

 

public class Animal {

 

public void speech() {

System.out.println("Animal speech()");

}

 

 

}

Sample43-DogClass

package child;

 

import parent.Animal;

 

 

public class Dog extends Animal {

 

@Override

public void speech() {

System.out.println("멍멍");

}

 

public void dog_method() {

System.out.println("저는 멍멍이");

}

}

Sample 43-CatClass

package child;

 

import parent.Animal;

 

public class Cat extends Animal {

 

 

@Override

public void speech() {

System.out.println("야옹야옹");

}

 

public void cat_method() {

System.out.println("나는 고양이");

}

 

 

}

출력

멍멍

야옹야옹

멍멍

멍멍

야옹야옹

animal[0]는 Dog 클래스로 생성됨

저는 멍멍이

나는 고양이

저는 멍멍이

저는 멍멍이

나는 고양이


질문: 메소드와 생성자를 어떻게 구분해? 형식이 같아서 헷갈려!

💡 한 줄 요약

질문자님이 말씀하신 모양 중에서, 접근 제어자와 () {}가 붙는 것은 공통점이지만 그 사이에 void 같은 반환 타입이 들어가면 '메서드', 반환 타입이 완전히 생략되고 클래스 이름과 똑같으면 '생성자'라고 부릅니다.

 

🔍 재미니의 꼼꼼 피드백 & 보완 포인트

1. [Sample 41] "Pitcher에 있는 내용이 Human에도 넘어가는 거지?"에 대한 명확한 해답

블로그 맨 밑에 질문으로 남겨두신 이 부분! 아주 날카로운 의문입니다. 정답은 "반대"입니다!
  • 올바른 개념: Human(부모 클래스)에 있는 내용이 Pitcher(자식 클래스)에게 물려 내려가는 것입니다.
  • 코드에서 super(name, age, height);를 쓴 이유는, 자식 클래스인 Pitcher가 생성될 때 부모 클래스(Human)의 생성자에게 값을 전달해서 부모의 멤버 변수들을 먼저 초기화(세팅)하기 위함입니다.
  • 블로그 보완 추천 글:

질문:  pitcher 에 있는 내용이 Human 에도 넘어가는 거지? 



🔍 재미니의 꼼꼼 피드백 & 보완 포인트

1. [Sample 41] "Pitcher에 있는 내용이 Human에도 넘어가는 거지?"에 대한 명확한 해답

블로그 맨 밑에 질문으로 남겨두신 이 부분! 아주 날카로운 의문입니다. 정답은 "반대"입니다!
  • 올바른 개념: Human(부모 클래스)에 있는 내용이 Pitcher(자식 클래스)에게 물려 내려가는 것입니다.
  • 코드에서 super(name, age, height);를 쓴 이유는, 자식 클래스인 Pitcher가 생성될 때 부모 클래스(Human)의 생성자에게 값을 전달해서 부모의 멤버 변수들을 먼저 초기화(세팅)하기 위함입니다.
  • 블로그 보완 추천 글:

ChildClass.java
0.00MB
MainClass.java
0.00MB
ParentClass.java
0.00MB
ChildClass.java
0.00MB
ParentClass.java
0.00MB
MainClass.java
0.00MB
Pitcher.java
0.00MB
Human.java
0.00MB
MainClass.java
0.00MB
ChildClass.java
0.00MB
ParentClass.java
0.00MB
MainClass.java
0.00MB
Cat.java
0.00MB
Dog.java
0.00MB
Animal.java
0.00MB
MainClass.java
0.00MB