프로그래밍자바 개발자

자바에서 사용되는 객체 지향 프로그래밍(OOP)의 주요 원칙과 그것이 실제로 구현되는 방법에 대해 이야기해 주세요?

Hintsage AI 어시스턴트로 면접 통과

답변.

자바는 객체 지향 프로그래밍(OOP)의 네 가지 주요 원칙인 캡슐화, 상속, 다형성, 추상화를 모두 구현하고 있습니다.

  • 캡슐화는 클래스의 내부 구현을 숨기고 데이터에 대한 접근을 메소드를 통해서만 허용합니다. 자바는 접근 수정자(private, protected, public)와 게터/세터를 사용하여 캡슐화를 달성합니다.
public class Account { private double balance; public double getBalance() { return balance; } public void deposit(double amount) { this.balance += amount; } }
  • 상속은 기존 클래스를 기반으로 새로운 클래스를 생성할 수 있게 해 줍니다. 이는 extends 키워드를 사용하여 이루어집니다. 코드 재사용을 촉진합니다.
public class Animal {} public class Dog extends Animal {}
  • 다형성은 하나의 인터페이스가 여러 유형의 객체에 대해 작동할 수 있게 합니다. 자바에서는 메소드 오버라이딩과 인터페이스를 통해 이를 달성합니다.
Animal animal = new Dog(); animal.makeSound(); // Dog의 구현을 호출합니다.
  • 추상화는 추상 클래스와 인터페이스를 선언하여 복잡한 시스템을 간소화하는 것에 의해 이루어집니다.
public interface Drawable { void draw(); }

함정 질문.

자바에서 클래스가 인터페이스와 추상 클래스를 상속받고, 두 클래스 모두 동일한 시그니처를 가진 메소드를 가지고 있다면 어떻게 될까요? 상속된 클래스는 어떤 동작을 보여줄까요?

답변: 추상 클래스와 인터페이스가 동일한 메소드 시그니처를 정의하는 경우, 파생 클래스에서 이 메소드를 한 번만 구현하면 충분합니다. 그러나 추상 클래스가 이 메소드를 구현했다면 자바는 그 구현을 사용합니다. 인터페이스의 디폴트 메소드는 필요할 때만 오버라이드 됩니다.

interface A { default void foo() { System.out.println("A"); }} abstract class B { void foo() { System.out.println("B"); }} class C extends B implements A {} // new C().foo()는 "B"를 출력합니다.

주제에 대한 세부 사항을 모른 채 발생하는 실제 오류의 예.


이야기

은행 프로젝트에서는 개발자가 모든 필드를 public으로 설정하고 직접 접근하였습니다. 이로 인해 객체 상태의 통제되지 않는 변경과 오류 추적이 복잡해졌습니다. 결국 모든 코드를 private 필드 및 접근 메소드를 사용하는 것으로 다시 작성해야 했습니다.


이야기

한 신입 직원이 다형성이 지원된다고 생각하며 기본 클래스의 private 메소드를 오버라이드 하려 했습니다. 하지만 사실상 자식 클래스에서 새로운 메소드가 생성되었고, 기본 클래스에서의 호출은 원래 버전을 호출하여 예상치 못한 동작을 일으키게 되었습니다.


이야기

여러 소스에서 디폴트 메소드를 가진 인터페이스를 사용하는 것은 "class X inherits unrelated defaults for Y() from types A and B" 오류를 발생시켰습니다. 직원은 이러한 충돌을 자식 클래스에서 수동으로 해결해야 한다는 사실을 몰랐습니다.