[Java] override, overload

2023. 2. 5. 16:57Java/Basic

반응형

1. method override

상속하는 클래스에서 상위 클래스(또는 인터페이스)의 메서드를 재정의하는 것

메서드를 재정의 하는 것이기 때문에 final, static 메서드는 오버라이드 할 수 습니다.

protected 이상의 접근 제한자에서 지원됩니다.

private 접근제한자는 오버라이드 할 수 없습니다.

서브 클래스의 오버라이드 메서드에서 슈퍼 클래스의 메서드를 호출하고 싶다면 super키워드를 사용하면 됩니다.

오버라이딩은 런타임 시 실질적으로 작동될 메서드가 결정되는 동적 바인딩 방식입니다.


1.1. 예제 1

Java에서 서브 클래스 타입은 슈퍼 클래스 타입으로 받을 수 있습니다.
아래 예제에서는 Animal 타입으로 Cat, Dog 클래스를 받을 수 있습니다.

interface Animal {
    void bark();
}

class Cat implements Animal {
    @Override
    public void bark() {
        System.out.println("야옹");
    }
}

class Dog implements Animal {
    @Override
    public void bark() {
        System.out.println("멍멍");
    }
}
public class OverrideTest {

    public static void main(String[] args) {
        List<Animal> animals = List.of(new Dog(), new Cat());
        for (Animal animal : animals) {
            animal.bark();
        }
    }
}
멍멍
야옹

Animal을 구현한 Cat, Dog 클래스는 bark() 메서드를 오버라이드 했어서
위와 같이 같은 이름의 메서드를 호출할 수 있습니다.

animal.bark() 구문은 런타임시 실제 메서드를 결정합니다.

1.2. 예제 2. override시 공변 리턴 타입 허용

오버라이드 시 covariant(공변) 리턴 타입을 허용한다는 것은
오버라이드 시 반환 값을 Sub Class로 설정할 수 있는 성질을 뜻합니다.

즉, 오버라이드 할 때 반환 값을 하위 클래스로 변경할 수 있는 성질입니다.

Shape 인터페이스에서 area 메서드의 반환타입은 Number 입니다.

Shape를 구현하는 클래스인 Square, Circle에서는 area메서드의 리턴타입은 Integer, Double로 변경이 가능합니다.

interface Shape {
    Number area();
}
class Square implements Shape {
    private int width;

    public Square(int width) {
        this.width = width;
    }

    @Override
    public Integer area() {
        return width * width;
    }
}

class Circle implements Shape {
    private int radius;

    public Circle(int radius) {
        this.radius = radius;
    }

    @Override
    public Double area() {
        return Math.PI * Math.pow(radius, 2.0);
    }
}

2. method overload

같은 이름의 메서드이지만 서로 다른 입력값을 갖는 메서드를 작성하는 것을 의미합니다.

서로 다른 입력값에는 인수의 갯수, 인수 타입, 인수 위치가 해당됩니다.

특정 메서드에 throws문이 있다고 할 때, 오버로드 메서드에 throws문이 있지 않아도 되고 다른 Exception을 throw 해도 됩니다.

인수 값에 따라 실행될 메서드가 실행되는, 컴파일 시 실행될 메서드가 결정되는 정적 바인딩 방식입니다.

메서드는 static 또는 static이 아닌 메서드로 작성하고
리턴값은 각각 달라도 됩니다.

static int plus(int a, int b) {
    return a + b;
}

static int plus(int a, int b, int c) {
    return a + b + c;
}

static double plus(double a, double b) {
    return a + b;
}

3. interface 내의 default, static 메서드

interface 함수 내의 메서드는 기본적으로 public abstract 이고 해당 키워드는 생략하여 표기합니다.

Java 8 부터는 interface에서 static 메서드, default 메서드를 이용할 수 있습니다.

default 키워드는 인터페이스 메서드에 기본 구현을 작성할 수 있도록 합니다. (default 메서드는 override가 필수가 아닙니다.)

static 메서드는 하위 클래스로 상속되지는 않지만, 인터페이스 내의 static method나 default 메서드에서 접근은 가능합니다.

interface Vehicle {
    String getName();

    static String code() {
        return "200";
    }

    default void introduce() {
        System.out.printf("이름: %s, 코드: %s%n", getName(), code());
    }
}
class Car implements Vehicle {
    private String name;

    public Car(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}

default 메서드가 있는 interface는 abstract class와 기능상으로는 동일해 보입니다.

interface에 default 메서드를 이용하는 것은
기존의 비즈니스 로직에는 영향을 주지 않으면서 추가 기능을 추가하고자할 때 활용할 수 있습니다.

기본적으로 abstract class와 interface의 차이점은
abstract class에서는 abstract가 아닌 메서드도 가질 수 있고, 필드값을 가질 수 있다는 점입니다.


이 특성을 이용하여 Java에서는 기존의 인터페이스에 새로은 기능을 추가하고자 할때, 그 인터페이스의 구현체에 영향을 주지않으면서 기능을 추가하는 것이 가능해졌습니다.


4. static method 숨기기

만일, Super Class와 Sub Class에서 동일한 이름의 static method를 갖고 있다면,
클래스 작성된 static 메서드를 호출하고 나머지는 숨겨집니다.

class Fruit {
    public static void introduce() {
        System.out.println("나는 과일 입니다");
    }
}

class Apple extends Fruit {
    public static void introduce() {
        System.out.println("나는 사과 입니다");
    }
}
public class MethodHidingTest {
    public static void main(String[] args) {
        Fruit.introduce();
        Apple.introduce();
    }
}
나는 과일 입니다
나는 사과 입니다

728x90
반응형