본문 바로가기

WINK-(Web & App)/JAVA 스터디

[2024-2 Java 스터디] 김지나 #4주차 "5.5~5.9"

반응형

05-05. 상속

 

✅ 상속

- 자식 클래스가 부모 클래스의 기능을 그대로 물려받는 것

- extends 키워드 사용

class Dog extends Animal 
// Animal 클래스를 상속받는 Dog 클래스

- Dog 클래스는 Animal 클래스의 객체 변수와 메서드 사용 가능

 

 

✅ 자식 클래스의 기능 확장

class Animal {
	String name;
    
    void setName(String name) {
    	this.name = name;
    }
}

class Dog extends Animal {
	void eat() {
    	System.out.println(this.name+"yamyam");
    }
} // 자식 클래스에 메서드 추가

public class Sample {
	public static void main(String[] args) {
    	Dog dog = new Dog();
        dog.setName("ddoddo");
        System.out.println(dog.name);
        dog.eat(); // 메서드 호출
    }
}
/* 출력: ddoddo
ddoddo yamyam */

 

 

✅ IS-A 관계

- Dog 클래스는 Animal 클래스를 상속했기 때문에 Dog는 Animal이다 <- 표현 가능!

- 👆 이런 것을 IS-A 관계라고 함

- IS-A 관계에서 자식 클래스의 객체는 부모 클래스의 자료형처럼 사용 가능 (※ 자식 클래스에만 존재하는 메서드는 사용 불가!!)

Animal dog = new Dog(); // Dog 클래스의 dog 객체를 Animal 클래스의 자료형으로 사용

- 부모 클래스의 객체를 자식 클래스의 자료형으로는 사용 불가. ( 집합적으로 Dog < Animal이므로 안됨 xxxx )

 

✅ Object 클래스

- 자바에서 만드는 모든 클래스는 Object 클래스를 상속받음.

-> 자바에서 만드는 모든 객체는 Object 자료형으로 사용 가능

Object animal = new Animal();
Object dog = new Dog();

 

 

✅ 메서드 오버라이딩

- 부모 클래스의 메서드를 자식 클래스가 동일하게 다시 구현하는 것

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + " zzz");
    }
}

class HouseDog extends Dog {
    void sleep() {
        System.out.println(this.name + " zzz in house");
    }
}

public class Sample {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("happy");
        houseDog.sleep();  // happy zzz in house 출력
    }
}

- 자식 클래스에 부모 클래스와 동일한 형태(동일한 입출력)의 메서드가 구현되면, 자식 클래스의 메서드가 우선순위를 가짐. 

 

 

✅ 메서드 오버로딩

- 입력 항목이 다를 때 동일한 이름의 메서드를 만드는 것

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + " zzz");
    }
}

class HouseDog extends Dog {
    void sleep() {
        System.out.println(this.name + " zzz in house");
    }

    void sleep(int hour) {
        System.out.println(this.name + " zzz in house for " + hour + " hours");
    }
}

public class Sample {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("happy");
        houseDog.sleep();  // happy zzz in house 출력
        houseDog.sleep(3);  // happy zzz in house for 3 hours 출력
    }
}

 

 

✅ 다중 상속

- 클래스가 동시에 하나 이상의 클래스를 상속받는 것(인데 자바에선 안 된다네요... 뭔지 이해만 하고 넘어가겠습니다)

 

 

05-06. 생성자

✅ 생성자

- 객체가 생성될 때 자동으로 호출되는 객체 초기화 메서드

- 생성자 규칙: 클래스명 = 메서드명, 리턴 타입 정의 X (void도 x)

- 생성자는 new 키워드가 사용될 때 호출. 

class HouseDog extends Dog {
    HouseDog(String name) { // 입력값으로 문자열을 필요로 하는 생성자
        this.setName(name);
    }
}

HouseDog dog = new HouseDog("happy"); // 생성자 호출 시 문자열 전달

 

 

✅ 디폴트 생성자

- 입력 항목과 내부 내용이 없는 생성자

class Dog extends Animal {
	Dog() { // 입력 항목과 내용이 없는 디폴트 생성자
    }
}

- 클래스에 생성자가 없으면 컴파일러가 자동으로 디폴트 생성자 추가

 

 

✅ 생성자 오버로딩

- 입력 항목이 다른 생성자 여러 개를 만들 수 있는 것

(... 생략 ...)
class HouseDog extends Dog {
    HouseDog(String name) {
        this.setName(name); // String 입력 생성자 1
    }

    HouseDog(int type) {
        if (type == 1) {
            this.setName("yorkshire");
        } else if (type == 2) {
            this.setName("bulldog"); // int 입력 생성자 2
        }
    }
    
(... 생략 ...)
public class Sample {
    public static void main(String[] args) {
        HouseDog happy = new HouseDog("happy"); // 생성자 1
        HouseDog yorkshire = new HouseDog(1); // 생성자 2
        System.out.println(happy.name);  // happy 출력
        System.out.println(yorkshire.name);  // yorkshire 출력
    }
}

 

05-07. 인터페이스

 

✅ 인터페이스

- 동일한 목적 하에 동일한 기능을 수행하게끔 강제하는 것

- 의존적인 클래스를 독립적인 클래스로 만들 수 있다는 점에서 필요함

- interface 키워드로 선언

- implements 키워드로 일반 클래스에서 구현 

interface Predator {
}

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

(... 생략 ...)

class Tiger extends Animal implements Predator {
}

class Lion extends Animal implements Predator {    
}

(... 생략 ...)

class ZooKeeper {
    void feed(Predator predator) {
        System.out.println("feed apple");
    }
}

(... 생략 ...)

 

 

✅ 인터페이스의 메서드

- 인터페이스 내부에 메서드를 작성할 때는 메서드의 이름과 입출력 정의만 O, 내용은 X

- 인터페이스를 implements한 클래스들이 구현함(항상 public으로!!)

interface Predator {
    String getFood();
}
(...생략...)

class Tiger extends Animal implements Predator {
    public String getFood() {
        return "apple";
    }
}

 

- 디폴트 메서드는 인터페이스에서 구현 가능

- 오버라이딩 가능 (클래스에서 다르게 구현하여 사용 가능)

interface Predator {
    String getFood();

    default void printFood() { // 앞에 default 표기
        System.out.printf("my food is %s\n", getFood());
    }
}

 

 

05-08. 다형성

✅ 다형성

- 하나의 객체가 여러 개의 자료형 타입을 가질 수 있는 것

- 복잡한 분기문을 간단하게 처리

- 자식 인터페이스로 생성한 객체의 자료형은 부모 인터페이스로 사용 가능

 

05-09. 추상 클래스

✅ 추상 클래스

- 인터페이스의 역할과 클래스의 기능을 가지고 있는 클래스

- 단독으로 객체 생성 불가, 추상 클래스를 상속한 클래스를 통해서만 객체 생성 가능

abstract class Predator extends Animal { // 클래스 앞에 abstract 표기
    abstract String getFood(); // 메서드 앞에 abstract 표기, 구현체 X

    void printFood() {  // default 제거
        System.out.printf("my food is %s\n", getFood()); 
    }
}

(... 생략 ...)

 


객관식 문제

Q1. 자바에서 한 클래스가 다른 클래스를 상속받을 때 사용하는 키워드는 무엇인가요?

A1. b) extends

 

Q2. 상속을 통해 자식 클래스가 부모 클래스에서 얻을 수 있는 이점은 무엇인가요?

A2. a) 코드 재사용성

 

Q3. 다중 상속이 허용되지 않는 이유 중 하나는 무엇인가요?

A3. c) 다이아몬드 문제로 인한 모호성

 

Q4. 상속된 메서드를 자식 클래스에서 재정의하려면 어떤 키워드를 사용하나요?

A4. d) 없음, 자동으로 재정의된다.

 

Q5. 자바에서 모든 클래스의 상위 클래스는 무엇인가요?

A5. a) Object

 

Q6. 생성자의 기본 역할은 무엇인가요?

A6. b) 클래스의 객체를 초기화한다.

 

Q7. 생성자는 언제 호출되나요?

A7. b) 객체가 생성될 때

 

Q8. 생성자를 오버로딩할 때 중요한 조건은 무엇인가요?

A8. b) 서로 다른 매개변수를 가져야 한다

 

Q9. 인터페이스의 특징으로 옳은 것은 무엇인가요?

A9. b) 메서드의 구현을 포함할 수 없다

 

Q10. 인터페이스의 메서드 구현을 클래스에서 강제하기 위한 키워드는 무엇인가요?

A10. a) implements

 

Q11. 다형성의 주요 특징은 무엇인가요?

A11. c) 동일한 인터페이스로 다양한 구현을 사용할 수 있다

 

Q12. 오버라이딩과 오버로딩의 차이점으로 올바른 것은 무엇인가요?

A12. c) 오버라이딩은 상속 관계에서 이루어진다

 

Q13. 추상 클래스의 주요 특징으로 옳은 것은 무엇인가요?

A13. c) 인스턴스를 만들 수 없다

 

Q14. 추상 클래스와 인터페이스의 공통점은 무엇인가요?

A14. a) 둘 다 객체를 생성할 수 없다

 

Q15. 추상 메서드는 어떤 키워드를 사용하여 선언하나요?

A15. c) abstract

 

서술형 문제

Q1. 추상 클래스와 일반 클래스의 차이점을 설명하세요.

A1. 추상 클래스는 객체를 생성할 수 없고 구체적인 메서드 구현은 자식 클래스에서 이루어져야 한다. 일반 클래스는 객체를 생성할 수 있으며 모든 메서드가 구현되어야 한다. 

 

Q2. 추상 클래스와 인터페이스를 함께 사용하는 이유와 예를 설명하세요.

A2. 추상 클래스는 공통 기능을 정의할 수 있고, 인터페이스는 동일한 기능을 하도록 강제시킬 수 있으니 함께 사용한다면 코드를 유연하고 보기 쉽게 짤 수 있다. 

interface Animal {
	void bark(); // bark 메서드 정의
}

abstract class Dog implements Animal { // Dog 추상 클래스 feed 메서드 구현
	void feed() {
    	System.out.println("yamyam");
    }
}

class Poodle extends Dog {
	@Override
    public void bark() {
    	System.out.println("wang");
    }
}

public class Sample {
	public static void main(String[] args) {
    	Poodle poodle = new Poodle();
        poodle.bark(); // wang
        poodle.feed(); // yamyam
    }
}

 

Q3. 추상 클래스를 상속받은 자식 클래스에서 추상 메서드를 구현해야 하는 이유를 설명하세요.

A3. 추상 클래스에서 정의한 메서드는 구현되어 있지 않기 때문에 상속받은 자식 클래스가 구현을 해야 한다.

 

Q4. 추상 클래스에서 선언된 일반 메서드와 추상 메서드의 차이점을 설명하세요.

A4. 일반 메서드는 구현이 완료된 메서드이고 추상 메서드는 구현이 없는 메서드이다.

 

Q5. 상속과 구성(Composition)의 차이점과 각각의 장단점을 비교하세요.

A5. 상속은 자식 클래스가 부모 클래스의 속성을 상속받은 것이고 구성은 클래스가 다른 클래스 내부에 포함되어 있는 것이다. 상속은 코드를 재사용할 수 있고, 설계가 직관적이지만 자식 클래스가 부모 클래스 변경에 영향을 받을 수 있다는 단점이 있다. 구성은 다중 구성을 할 수 있고, 부모 클래스의 변경이 자식 클래스와 무관하기 때문에 유연성이 좋지만 코드 중복이 많을 수 있다는 단점이 있다.

 

Q6. 생성자에서 this와 super 키워드의 차이점에 대해 설명하세요.

A6. this는 현재 객체를 참조하는 키워드이고 super는 부모 클래스의 생성자를 호출하거나 접근하는 데에 사용된다.

 

Q7. 자바에서 인터페이스와 추상 클래스의 차이점을 설명하세요.

A7. 인터페이스는 메서드의 이름과 입출력 정의만 한다. 추상 클래스는 추상 메서드와 일반 메서드를 같이 가질 수 있다.

 

Q8. 다형성의 개념과 객체지향 프로그래밍에서의 중요성을 설명하세요.

A8. 다형성은 하나의 객체가 여러 개의 자료형 타입을 가질 수 있는 것이다. 동일한 메서드가 서로 다른 방식으로 동작할 수 있다. 이는 프로그램의 유연성을 높이고 복잡한 분기문을 간단하게 처리할 수 있어서 중요하다.

 

Q9. 메서드 오버로딩과 오버라이딩의 차이점을 비교하세요.

A9. 오버로딩은 입력 항목이 다를 때 같은 이름의 메서드를 만드는 것이고 오버라이딩은 부모 클래스의 메서드를 자식 클래스가 재정의해서 사용하는 것인데, 메서드의 이름과 매개변수, 반환 타입 등이 부모 클래스와 동일해야 한다. 

 

Q10. 동적 바인딩의 개념을 설명하고 다형성과의 관계를 설명하세요.

A10. 동적 바인딩이란 실행 이후에 값이 확정되는 것이다. 예를 들어, 부모와 자식 클래스에 동일한 메서드가 존재하면 실행 시점에 타입이 결정되어 해당 타입에 맞는 메서드가 실행되기 때문에 동적 바인딩이다. 다형성은 동적 바인딩 기반으로 작동하는데, 오버라이딩된 메서드는 실행 시점에 객체의 실제 타입에 맞춰 호출되기 때문이다. 

 

코딩 테스트 문제

Q1.

class Animal {
    String sound = "generic sound";
}

class Dog extends Animal {
    String sound = "bark";
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        System.out.println(a.sound);
    }
}

A1. generic sound

 

Q2.

class Parent {
    void show() {
        System.out.println("Parent");
    }
}

class Child extends Parent {
    void show() {
        System.out.println("Child");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent p = new Child();
        p.show();
    }
}

A2. Child

 

Q3.

class Parent {
    int x = 10;
}

class Child extends Parent {
    int x = 20;
}

public class Main {
    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.x);
    }
}

A3. 10

 

Q4.

class A {
    A() {
        System.out.println("A's constructor");
    }
}

class B extends A {
    B() {
        System.out.println("B's constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        B obj = new B();
    }
}

A4. A's constructor

B's constructor

 

Q5.

class A {
    A() {
        System.out.println("A's no-arg constructor");
    }
}

class B extends A {
    B() {
        System.out.println("B's no-arg constructor");
    }
}

public class Main {
    public static void main(String[] args) {
        A a = new B();
    }
}

A5. A's no-arg constructor
B's no-arg constructor

 

Q6.

interface A {
    void display();
}

interface B extends A {
    void display();
}

class C implements B {
    public void display() {
        System.out.println("C's display");
    }
}

public class Main {
    public static void main(String[] args) {
        A obj = new C();
        obj.display();
    }
}

A6. C's display

 

Q7.

interface A {
    default void show() {
        System.out.println("A");
    }
}

class B implements A {
    public void show() {
        System.out.println("B");
    }
}

public class Main {
    public static void main(String[] args) {
        A obj = new B();
        obj.show();
    }
}

A7. B

반응형