본문 바로가기

배운내용 정리

객체지향(3)

1. 추상 클래스

클래스가 설계도라면 추상 클래스는 미완성된 설계도이다.

  • abstract 키워드를 사용하여 추상 클래스를 선언할 수 있다. 
public abstract class 추상클래스명 {

}
  • 추상 클래스는 추상 메서드를 포함할 수 있습니다.
    • 추상 메서드가 없어도 추상 클래스로 선언할 수 있다.
  • 추상 클래스는 자식 클래스에 상속되어 자식 클래스에 의해서만 완성될 수 있다.
  • 추상 클래스는 여러개의 자식 클래스들에서 공통적인 필드나 메서드를 추출해서 만들 수 있다.

추상 메서드

추상 메서드는 아직 구현되지 않은 미완성된 메서드이다.

  • abstract 키워드를 사용하여 추상 메서드를 선언할 수 있다. 
public abstract class 추상클래스명 {
		abstract 리턴타입 메서드이름(매개변수, ...);
}
  • 추상 메서드는 일반적인 메서드와는 다르게 블록{ }이 없다.
    • 즉, 정의만 할 뿐, 실행 내용은 가지고 있지 않다.

추상 클래스 상속

public class 클래스명 extends 추상클래스명 {
		@Override
    public 리턴타입 메서드이름(매개변수, ...) {
		       // 실행문
    }
}
  • 상속받은 클래스에서 추상 클래스의 추상 메서드는 반드시 오버라이딩 되어야 한다.

예시

public abstract class Car {
    // 추상 클래스
    String company; // 자동차 회사
    String color; // 자동차 색상
    double speed;  // 자동차 속도 , km/h

    public double gasPedal(double kmh) {
        speed = kmh;
        return speed;
    }

    public double brakePedal() {
        speed = 0;
        return speed;
    }

    public abstract void horn();
}
public class BenzCar extends Car {

    @Override
    public void horn() {
        System.out.println("Benz 빵빵");
    }
}
public class AudiCar extends Car {
    @Override
    public void horn() {
        System.out.println("Audi 빵빵");
    }
}
public class ZenesisCar extends Car {

    @Override
    public void horn() {
        System.out.println("Zenesis 빵빵");
    }
}
public class Main {
    public static void main(String[] args) {
        Car car1 = new BenzCar();
        car1.horn();
        System.out.println();

        Car car2 = new AudiCar();
        car2.horn();
        System.out.println();

        Car car3 = new ZenesisCar();
        car3.horn();
    }
}
  • BenzCar, AudiCar, ZenesisCar 는 horn() 메서드의 내용에 차이가 존재하다.
  • 따라서 horn() 메서드를 추상 메서드로 선언하여 자식 클래스에서 재정의 될 수 있도록 한다.

2. 인터페이스

인터페이스의 역할

  • 인터페이스는 두 객체를 연결해주는 다리 역할
    • 사람과 삼성티비, 엘지티비 객체가 존재한다고 생각해 보겠습니다.
    • 사람 객체는 멀티 리모컨 인터페이스를 통해서 삼성티비 객체의 채널을 변경할 수 있다.
    • 이때 삼성티비가 아니라 엘지티비로 객체가 교체된다고 해도 채널을 변경할 수 있다.
  • 상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있다.
    • 인터페이스는 스팩이 정의된 메서드들의 집합이다.
    • 인터페이스의 구현 클래스들은 반드시 정의된 메서드들을 구현해야한다.
    • 따라서 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있다.
    • 이러한 특징은 인터페이스에 다형성을 적용할 수 있게 만들어 준다 
    • 인터페이스도 다형성이 가능

interface 키워드를 사용하여 인터페이스를 선언할 수 있다.

public interface 인터페이스명 { 

}
  • 인터페이스는 클래스와 마찬가지로 public, default 접근 제어자를 지정할 수 있다.

인터페이스의 멤버

  • 모든 멤버변수는 public static final 이어야한다.
    • 생략 가능하다.
  • 모든 메서드는 public abstract 이어야한다.
    • 생략 가능하다. (static 메서드와 default 메서드 예외)
  • 생략되는 제어자는 컴파일러가 자동으로 추가 해준다. 
public interface 인터페이스명 { 
		public static final char A = 'A';
    static char B = 'B';
    final char C = 'C';
    char D = 'D';

    void turnOn(); // public abstract void turnOn();
}

인터페이스 구현

인터페이스는 추상 클래스와 마찬가지로 직접 인스턴스를 생성할 수 없기 때문에 클래스에 구현되어 생성된다.

  • implements 키워드를 사용하여 인터페이스를 구현할 수 있다. 
public class 클래스명 implements 인터페이스명 { 
			// 추상 메서드 오버라이딩
			@Override
	    public 리턴타입 메서드이름(매개변수, ...) {
			       // 실행문
	    }
}
  • 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 한다.
  • 만약 인터페이스의 추상 메서드를 일부만 구현해야 한다면 해당 클래스를 추상 클래스로 변경해주면 된다.

인터페이스간의 상속이 가능하다.

  • 인터페이스간의 상속은 implements 가 아니라 extends 키워드를 사용한다.
  • 인터페이스는 클래스와는 다르게 다중 상속이 가능하다. 
public class Main implements C {
    @Override
    public void a() {
    	System.out.println("A");
    }
    @Override
    public void b() {
        System.out.println("B");
    }
}
interface A {
    void a();
}
interface B {
    void b();
}
interface C extends A, B { }
  • 인터페이스 C는 아무것도 선언 되어있지 않지만 인터페이스 A, B를 다중 상속받았기 때문에 추상 메서드 a, b를 갖고 있는 상태이다.
  • 따라서 Main 클래스에서 인터페이스 C가 구현될 때 a, b 추상 메서드가 오버라이딩된다.
  • 또한 인터페이스의 구현은 상속과 함께 사용될 수 있다.
public class Main extends D implements C {
    @Override
    public void a() {
        System.out.println("A");
    }

    @Override
    public void b() {
        System.out.println("B");
    }

    @Override
    void d() {
        super.d();
    }
    public static void main(String[] args) {
        Main main = new Main();
        main.a();
        main.b();
        main.d();
    }
}
interface A {
    void a();
}
interface B {
    void b();
}
interface C extends A, B {
}
class D {
    void d() {
        System.out.println("D");
    }
}

 

3. 디폴트 메서드와 static 메서드

디폴트 메서드

디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드이다.

  • 메서드 앞에 default 키워드를 붙이며 블럭{ }이 존재해야한다.
  • default 메서드 역시 접근 제어자가 public 이며 생략이 가능하다.
  • 추상 메서드가 아니기 때문에 인터페이스의 구현체들에서 필수로 재정의 할 필요는 없다.
public class Main implements A {

    @Override
    public void a() {
        System.out.println("A");
    }


    public static void main(String[] args) {
        Main main = new Main();
        main.a();

        // 디폴트 메서드 재정의 없이 바로 사용가능하다.
        main.aa();
    }
}

interface A {
    void a();
    default void aa() {
        System.out.println("AA");
    }
}

static 메서드

인터페이스에서 static 메서드 선언이 가능하다.

  • static의 특성 그대로 인터페이스의 static 메서드 또한 객체 없이 호출이 가능하다.
  • 선언하는 방법과 호출하는 방법은 클래스의 static 메서드와 동일하다.
    • 접근 제어자를 생략하면 컴파일러가 public을 추가해 준다. 
public class Main implements A {

    @Override
    public void a() {
        System.out.println("A");
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.a();
        main.aa();
        System.out.println();

        // static 메서드 aaa() 호출
        A.aaa();
    }
}

interface A {
    void a();
    default void aa() {
        System.out.println("AA");
    }
    static void aaa() {
        System.out.println("static method");
    }
}

 

'배운내용 정리' 카테고리의 다른 글

Java 예외처리  (1) 2023.10.23
자바의 구조체  (0) 2023.10.18
객체지향(2)  (0) 2023.10.17
객체지향(1)  (1) 2023.10.16
Java 문법 Array, collection  (0) 2023.10.13