07 객체지향 프로그래밍
접근 제어자(Access Modifier)와 캡슐화(Encapsulation)
접근 제어자(Access Modifier)는 클래스, 필드, 메소드, 생성자 등에 대해 다른 클래스에서 접근할 수 있는 범위를 지정하는 키워드입니다. Java에서 접근 제어자를 사용하면 객체 지향 프로그래밍의 중요한 개념인 캡슐화(Encapsulation)를 실현할 수 있습니다. 접근 제어자는 데이터를 보호하고, 외부 클래스가 필드나 메소드를 잘못 사용하지 못하도록 제어하는 데 사용됩니다.
Java에는 네 가지 주요 접근 제어자가 있습니다:
public
protected
default
(아무 접근 제어자를 명시하지 않은 경우)private
1. public
(공개 접근 제어자)
public
(공개 접근 제어자)어디서나 접근 가능: 다른 클래스, 패키지에서 자유롭게 접근할 수 있습니다.
모든 클래스가 접근할 수 있으며, 제한이 없습니다. 클래스 내부뿐만 아니라, 다른 패키지의 클래스에서도 접근할 수 있습니다.
2. protected
(보호된 접근 제어자)
protected
(보호된 접근 제어자)같은 패키지 또는 **서브 클래스(자식 클래스)**에서 접근 가능합니다.
다른 패키지의 클래스에서는 접근할 수 없지만, 해당 클래스를 상속한 자식 클래스에서는 접근이 가능합니다.
3. default
(패키지 전용 접근 제어자)
default
(패키지 전용 접근 제어자)아무 접근 제어자도 명시하지 않았을 때 사용됩니다.
같은 패키지 내의 클래스에서만 접근 가능하며, 다른 패키지에서는 접근할 수 없습니다.
default
접근 제어자는 패키지 전용입니다.
4. private
(비공개 접근 제어자)
private
(비공개 접근 제어자)해당 클래스 내부에서만 접근 가능합니다.
외부 클래스에서는 물론, 같은 패키지나 상속받은 자식 클래스에서도 접근할 수 없습니다. 즉, 클래스 내부에서만 사용할 수 있는 가장 제한적인 접근 제어자입니다.
주로 캡슐화를 위해 필드에 사용되며, 외부에서 필드에 직접 접근하지 못하도록 하고, 메소드를 통해서만 간접적으로 접근할 수 있게 합니다.
접근 제어자 비교 예제
accessModifier 패키지에 작성
접근 제어자 요약
해당 클래스 안에서
✅
✅
✅
✅
동일 패키지 안에서
✅
✅
✅
동일 패키지 또는 자손 클래스 안에서
✅
✅
다른 패키지 포함 어느 곳에서든
✅
Getter 와 Setter
Getter와 Setter는 객체의 필드(변수)에 대한 접근을 제어하는 메소드입니다. 이들은 객체 지향 프로그래밍에서 캡슐화(Encapsulation)를 실현하는 중요한 도구로, 필드에 직접 접근하지 않고, 메소드를 통해 간접적으로 값을 읽거나 수정할 수 있도록 합니다. 이를 통해 데이터의 무결성을 유지하고, 외부에서 필드의 값을 잘못 변경하지 않도록 보호할 수 있습니다.
1. Getter
Getter 메소드는 객체의 필드 값을 반환하는 역할을 합니다.
보통 필드에 접근하는데 사용되며, 메소드 이름은
get
으로 시작하고 필드 이름을 이어 붙여 작성합니다.Getter 메소드는 주로 읽기 전용 필드에 사용되며, 필드 값을 외부에서 조회할 수 있게 합니다.
Getter 메소드 예시
getterSetterExample 패키지
위 코드에서 getName()
메소드를 사용하면 name
필드의 값을 반환할 수 있습니다. 필드가 private
로 선언되어 외부에서 직접 접근할 수 없지만, Getter 메소드를 통해 간접적으로 값을 읽을 수 있습니다.
2. Setter
Setter 메소드는 객체의 필드 값을 수정하는 역할을 합니다.
보통
set
으로 시작하고 필드 이름을 이어 붙여 작성합니다.Setter 메소드를 통해 필드 값을 변경할 때, 검증 로직을 추가하여 필드에 적절한 값만 저장되도록 제어할 수 있습니다.
Setter 메소드
getterSetterExample 패키지 Person에 코드추가
위 코드에서 setName()
메소드를 사용하면 name
필드의 값을 변경할 수 있습니다. 필드가 private
로 선언되어 외부에서 직접 수정할 수 없지만, Setter 메소드를 통해 간접적으로 값을 설정할 수 있습니다.
getterSetterExample 패키지 Main에 코드추가
인텔리제이 단축키로 기본적인 getter 와 setter 작성
메뉴 - 코드 - 생성
윈도우:
alt
+insert
맥:
command
+N
getter 및 setter
선택
Getter와 Setter의 역할
Getter
객체의 필드 값을 조회할 때 사용합니다.
필드가
private
로 선언되었기 때문에, 외부에서 직접 접근할 수 없고, Getter를 통해 값에 접근할 수 있습니다.
Setter
객체의 필드 값을 설정할 때 사용합니다.
필드에 직접 접근하지 못하도록 하고, Setter 메소드를 통해 값을 변경할 수 있습니다. 또한 Setter 내부에서 검증 로직을 추가하여 유효하지 않은 값이 설정되지 않도록 할 수 있습니다.
예시: Getter와 Setter를 활용한 캡슐화
useGetterSetterEncapsulation 패키지에 작성
사용 예시
위 예시에서 name
과 age
필드는 private
으로 선언되어 외부에서 직접 접근할 수 없지만, getName()
, setName()
, getAge()
, setAge()
메소드를 통해 간접적으로 접근할 수 있습니다. 또한, setAge()
메소드에서 나이를 설정할 때, 검증 로직을 추가하여 유효하지 않은 나이를 입력하면 오류 메시지를 출력하게 했습니다.
상속(Inheritance)
상속(Inheritance)은 객체 지향 프로그래밍(OOP)에서 중요한 개념 중 하나로, 기존 클래스(부모 클래스, 슈퍼 클래스, 상위 클래스)의 속성과 메소드를 새로운 클래스(자식 클래스, 서브 클래스, 하위 클래스)가 물려받는 기능을 말합니다. 이를 통해 코드의 재사용성을 높이고, 새로운 기능을 추가하거나 기존 기능을 확장할 수 있습니다.
Java에서는 상속을 사용하여 클래스 간의 계층 구조를 만들 수 있으며, 자식 클래스는 부모 클래스의 모든 필드와 메소드를 상속받아 사용할 수 있습니다. 또한, 필요에 따라 상속받은 메소드를 재정의(오버라이딩(Overriding))하여 자식 클래스에서 다른 동작을 구현할 수도 있습니다.
1. 상속의 기본 구조
Java에서 상속은 extends
키워드를 사용하여 구현합니다.
예시: 상속 기본 예제
inheritanceAnimal 패키지에 Animal과 Dog, Main 작성
출력 결과
Dog
클래스는Animal
클래스를 상속받아name
필드와eat()
메소드를 물려받았으며,bark()
라는 고유한 메소드를 추가로 정의했습니다.자식 클래스인
Dog
객체는 부모 클래스의 필드와 메소드를 그대로 사용할 수 있으며, 자신만의 추가 기능도 구현할 수 있습니다.
2. 상속의 장점
코드 재사용: 부모 클래스의 코드(필드와 메소드)를 재사용하여 코드 중복을 줄이고, 유지보수가 용이해집니다.
확장성: 자식 클래스는 부모 클래스의 기능을 그대로 물려받고, 필요에 따라 새로운 기능을 추가할 수 있습니다.
유지보수성: 부모 클래스의 코드를 수정하면, 상속받은 자식 클래스들에도 자동으로 반영됩니다.
3. 메소드 오버라이딩(Overriding)
오버라이딩(Overriding)은 자식 클래스에서 부모 클래스의 메소드를 재정의하는 것을 말합니다. 자식 클래스는 상속받은 부모 클래스의 메소드를 그대로 사용할 수도 있지만, 자식 클래스의 요구에 맞게 해당 메소드를 다른 방식으로 구현할 수 있습니다. 오버라이딩할 때는 부모 클래스의 메소드와 이름, 매개변수, 리턴 타입이 동일해야 합니다.
오버라이딩 예시
overridingAnimal 패키지에 Animal과 Dog, Main 작성
출력 결과
Dog
클래스는 부모 클래스인Animal
의sound()
메소드를 오버라이딩하여,Dog
객체에서 호출할 때는 "멍멍"이라는 소리를 출력하도록 변경했습니다.@Override
어노테이션은 오버라이딩한 메소드임을 명시하는 데 사용되며, 컴파일러가 올바르게 오버라이딩했는지 확인할 수 있게 합니다.부모의 특정 메소드를 오버라이드함을 명시
없어도 오류가 나지는 않음
붙였는데 메소드명이 다를 시 오류 (실수 방지)
인텔리제이 단축키로 오버라이드 메소드 생성 가능
메뉴 - 코드 - 생성
윈도우:
alt
+insert
맥:
command
+N
Override Methods
선택
오버로딩과 오버라이딩
오버로딩은 같은 이름의 메소드의 매개변수를 다르게 설정하는 것
오버라이딩은 부모의 메소드를 자식이 재정의
헷갈릴 수 있으나 매우 중요한 개념이므로 정확하게 알아둘 것
4. super
키워드
super
키워드super
키워드는 부모 클래스의 필드나 메소드에 접근할 때 사용됩니다. 이를 통해 자식 클래스에서 부모 클래스의 메소드를 호출하거나 필드에 접근할 수 있습니다. 오버라이딩한 메소드 내부에서 부모 클래스의 메소드를 호출하고 싶을 때도 super
를 사용할 수 있습니다.
super
키워드 예시
super
키워드 예시superKeywordAnimal 패키지에 Animal과 Dog, Main 작성
출력 결과
자식 클래스에서
super.sound()
를 호출하여 부모 클래스의sound()
메소드를 실행한 후, 자식 클래스의 추가 로직을 실행합니다.
5. 상속에서의 생성자
자식 클래스의 생성자는 자동으로 부모 클래스의 생성자를 호출합니다. 이때, 부모 클래스의 기본 생성자가 먼저 호출되고, 그다음에 자식 클래스의 생성자가 실행됩니다.
만약 부모 클래스에 매개변수가 있는 생성자가 있다면, 자식 클래스에서
super(매개변수)
를 사용해 명시적으로 부모 생성자를 호출해야 합니다.
상속에서의 생성자 예시
inheritanceAnimal 패키지에 Animal과 Dog, Main 작성
자식 클래스
Dog
의 생성자에서super(name)
을 사용하여 부모 클래스Animal
의 생성자를 호출합니다.부모 클래스의 생성자를 호출하면, 부모 클래스의 필드
name
이 초기화됩니다.
6. 상속의 제한
단일 상속: Java에서는 다중 상속을 지원하지 않으며, 하나의 클래스는 오직 한 개의 부모 클래스만 상속받을 수 있습니다. 다중 상속으로 인한 모호성을 방지하기 위함입니다.
다형성
다형성(Polymorphism)과 instanceof
연산자는 객체 지향 프로그래밍에서 중요한 역할을 합니다. 다형성은 하나의 객체가 여러 가지 형태를 가질 수 있는 능력을 의미하며, 부모 클래스의 참조 변수로 자식 클래스를 참조할 수 있게 합니다. instanceof
연산자는 객체가 특정 클래스나 인터페이스의 인스턴스인지를 확인하는 데 사용됩니다. 이를 통해 다형성의 환경에서 어떤 객체가 실제로 어떤 클래스의 인스턴스인지 확인하여 올바른 동작을 할 수 있게 합니다.
1. 다형성과 instanceof
의 기본 개념
instanceof
의 기본 개념다형성: 부모 클래스 타입의 변수로 여러 자식 클래스의 객체를 참조할 수 있습니다. 하지만 자식 클래스의 고유한 기능을 사용해야 할 때, 해당 객체가 실제로 어떤 클래스의 인스턴스인지 알아야 하는 경우가 있습니다. 이때
instanceof
연산자를 사용합니다.instanceof
연산자: 객체가 특정 클래스의 인스턴스인지를 확인할 때 사용되며, 결과는true
또는false
로 반환됩니다.
2. instanceof
연산자의 사용
instanceof
연산자의 사용instanceof
는 객체가 특정 클래스나 인터페이스의 인스턴스인지 확인하는 연산자로, 형식은 다음과 같습니다.
객체가 해당 클래스의 인스턴스면
true
를 반환하고, 아니면false
를 반환합니다.
3. 예시: 다형성과 instanceof
instanceof
polymorphismAndAnimal 패키지에 Animal과 Dog, Main 작성
출력 결과
설명
다형성:
myDog
과myCat
변수는Animal
타입이지만, 각각Dog
와Cat
객체를 참조하고 있습니다. 따라서 다형성을 통해 부모 클래스 타입으로 여러 자식 객체를 참조할 수 있습니다.메소드 오버라이딩:
sound()
메소드는Dog
와Cat
클래스에서 각각 오버라이딩되었기 때문에,myDog.sound()
와myCat.sound()
는 각각Dog
와Cat
클래스에서 구현된 메소드가 호출됩니다.instanceof
연산자:myDog instanceof Dog
는myDog
객체가Dog
클래스의 인스턴스인지 확인합니다.true
가 반환되면Dog
로 다운캐스팅하여bark()
메소드를 호출할 수 있습니다.myCat instanceof Cat
도 마찬가지로Cat
객체인지 확인하고, 다운캐스팅하여purr()
메소드를 호출합니다.
보충 - 정적 바인딩과 동적 바인딩
정적 바인딩
컴파일 시점(Compile-time)에 메서드 호출이 결정됩니다.
private, static, final 메서드와 같이 컴파일 타임에 호출이 확정되는 경우 정적 바인딩이 사용됩니다.
예: 컴파일 시점에 메서드가 확정된 main() 함수 호출.
동적 바인딩
실행 시점에 객체의 실제 타입을 기준으로 호출할 메서드가 결정됩니다.
일반적으로 오버라이딩(Overriding) 된 메서드에서 사용됩니다.
예: 부모 클래스 타입으로 참조된 자식 객체에서 메서드를 호출할 때, 실제 객체의 메서드가 실행됨.
4. instanceof
의 사용 이유
instanceof
의 사용 이유instanceof
연산자는 다음과 같은 상황에서 유용합니다.
다운캐스팅(Downcasting): 부모 클래스 타입의 참조 변수를 자식 클래스 타입으로 변환할 때,
instanceof
를 사용하여 안전하게 다운캐스팅할 수 있습니다. 이를 통해 해당 객체가 실제로 그 클래스의 인스턴스인지 확인한 후 다운캐스팅을 수행할 수 있습니다.다양한 객체 처리: 다형성을 사용하면서, 동일한 부모 클래스를 상속한 여러 자식 객체를 처리할 때
instanceof
를 사용하여 객체의 실제 타입을 확인하고, 해당 객체에 맞는 동작을 할 수 있습니다.
5. 다운캐스팅과 instanceof
의 관계
instanceof
의 관계다운캐스팅은 부모 클래스 타입을 자식 클래스 타입으로 변환하는 작업입니다. 하지만 잘못된 타입으로 캐스팅을 시도할 경우 ClassCastException
이 발생할 수 있습니다. 이를 방지하기 위해 instanceof
를 사용하여 안전하게 다운캐스팅할 수 있습니다.
다운캐스팅 예시
instanceof
를 사용하여myAnimal
이 실제로Dog
클래스의 인스턴스인지 확인한 후에 다운캐스팅을 수행하므로 안전합니다.
다운캐스팅을 통한 자식 클래스의 기능 사용 예제
downcastingAniaml 패키지에 ****Animal과 Dog 및 Cat, Main 작성
출력 결과
설명
업캐스팅(Upcasting):
Animal myAnimal = new Dog();
에서myAnimal
은 부모 클래스인Animal
타입으로 업캐스팅되어 있습니다. 이때,myAnimal
참조 변수는Dog
객체를 가리키고 있지만, 부모 클래스인Animal
의 기능만 사용할 수 있습니다.myAnimal.bark()
를 호출하려 하면 컴파일 에러가 발생합니다. 이는Animal
클래스에는bark()
메소드가 존재하지 않기 때문입니다.
다운캐스팅(Downcasting):
if (myAnimal instanceof Dog)
을 통해 객체가 실제로Dog
타입인지 확인한 후, 명시적 타입 변환을 사용하여Dog
타입으로 다운캐스팅합니다.이렇게 변환된 객체(
myDog
)는 이제 자식 클래스Dog
의 고유 메소드인bark()
를 호출할 수 있습니다.
다른 예시:
마찬가지로
Cat
클래스도 업캐스팅되었다가 다운캐스팅을 통해purr()
메소드를 호출할 수 있습니다.
final 클래스
final
클래스는 상속할 수 없는 클래스를 의미합니다. 즉, final
키워드가 붙은 클래스는 다른 클래스에서 상속받아 확장할 수 없습니다. final
클래스는 보통 상속의 필요성을 없애기 위해 사용되며, 클래스의 동작을 변경하거나 확장할 수 없게 만듭니다.
1. final
클래스의 특징
final
클래스의 특징상속 불가:
final
로 선언된 클래스는 상속할 수 없습니다. 이는 클래스가 완전한 형태로 사용되기를 원할 때 유용합니다.안정성 제공: 클래스의 동작을 더 이상 변경하지 못하게 하므로, 클래스의 안정성을 보장합니다.
보안성 강화: 클래스의 중요한 동작을 자식 클래스가 재정의(오버라이딩)하거나 수정할 수 없도록 막습니다.
2. final
클래스 선언
final
클래스 선언위 코드에서 FinalClass
는 final
로 선언되었으므로, 다른 클래스가 이 클래스를 상속할 수 없습니다.
3. final
클래스의 상속 불가
final
클래스의 상속 불가위의 코드처럼 FinalClass
를 상속하려고 하면, 컴파일 오류가 발생합니다. final
클래스는 상속이 불가능하기 때문에, 자식 클래스에서 이를 상속받으려 하면 오류가 발생합니다.
4. final
클래스의 사용 예
final
클래스의 사용 예불변 객체 생성:
final
클래스는 객체의 상태나 동작을 변경할 필요가 없을 때, 즉 불변 객체(immutable object)를 만들기 위해 자주 사용됩니다. 예를 들어,String
클래스는 자바에서 대표적인final
클래스입니다.
보안: 중요한 클래스의 동작을 자식 클래스에서 변경할 수 없도록 막기 위해 사용됩니다.
5. final
메소드와의 차이
final
메소드와의 차이final 클래스
: 해당 클래스는 상속이 불가능합니다. 즉, 다른 클래스가 이 클래스를 확장하여 사용할 수 없습니다.final 메소드
:final
메소드가 선언된 메소드는 오버라이딩(Overriding)할 수 없습니다. 즉, 자식 클래스에서 메소드를 재정의할 수 없습니다. 그러나 클래스 자체는 상속이 가능합니다.
예시: final
메소드
final
메소드fianlMethod 패키지에 작성
위 예시에서 Parent
클래스의 show()
메소드는 final
로 선언되었기 때문에 자식 클래스에서 오버라이딩할 수 없습니다.
추상 클래스(Abstract Class)
추상 클래스는 객체를 직접 생성할 수 없는 클래스로, 주로 공통된 속성이나 동작을 정의하고 이를 상속받은 자식 클래스에서 구체적인 구현을 강제하는 역할을 합니다.
객체 생성 불가: 추상 클래스는 객체를 직접 생성할 수 없습니다. 이는 추상 클래스가 미완성된 클래스이기 때문입니다.
공통된 속성과 메소드 정의: 추상 클래스는 공통된 필드와 메소드를 정의할 수 있습니다. 자식 클래스는 이들을 상속받아 사용할 수 있습니다.
추상 메소드를 포함할 수 있음: 추상 클래스는 추상 메소드를 포함할 수 있으며, 추상 메소드는 자식 클래스에서 반드시 구현해야 합니다.
일반 메소드도 포함 가능: 추상 클래스는 구현된 일반 메소드도 포함할 수 있어, 일부 동작은 부모 클래스에서 정의하고, 나머지는 자식 클래스에서 구현하게 할 수 있습니다.
추상 클래스 선언 예시
추상 메소드(Abstract Method)
추상 메소드는 구현되지 않은 메소드로, 추상 클래스에서 선언만 하고 자식 클래스에서 반드시 구현해야 합니다.
구현 없음: 추상 메소드는 메소드의 선언만 있고 구현이 없습니다. 즉, 메소드의 동작을 정의하지 않고 선언만 합니다.
자식 클래스에서 구현 강제: 추상 메소드는 자식 클래스에서 반드시 오버라이딩(Overriding)되어 구체적인 구현을 제공해야 합니다.
abstract
키워드로 선언: 추상 메소드는abstract
키워드를 사용하여 선언되며, 메소드 본문{}
이 없습니다.
추상 메소드 선언 예시
인텔리제이 단축키로 추상 메소드 생성 가능
메뉴 - 코드 - 생성
윈도우:
alt
+insert
맥:
command
+N
Implement Methods
선택
3. 추상 클래스와 추상 메소드의 사용 예
abstractAnimal 패키지에 작성
출력 결과
4. 추상 클래스와 추상 메소드의 역할
상속 구조의 설계: 추상 클래스는 상속의 기본 틀을 제공하며, 상위 클래스에서 공통된 속성과 동작을 정의합니다. 하위 클래스는 구체적인 동작을 구현해야 합니다.
코드의 재사용성: 공통적인 동작은 상위 추상 클래스에 정의하고, 자식 클래스는 이를 재사용할 수 있습니다.
구현 강제: 추상 메소드를 통해 자식 클래스가 반드시 특정 메소드를 구현하도록 강제할 수 있습니다. 이를 통해 일관성 있는 구현을 보장할 수 있습니다.
인터페이스
인터페이스(Interface)는 자바에서 추상적인 메소드의 집합을 정의하는 일종의 설계도입니다. 추상 클래스와 비슷한 개념이지만, 더 추상적이고 유연한 형태를 제공합니다. 인터페이스는 구체적인 구현을 포함하지 않으며, 오직 메소드의 시그니처(선언부)만 정의하고, 해당 인터페이스를 구현한 클래스가 구체적인 구현을 제공해야 합니다.
1. 인터페이스의 주요 특징
메소드 선언만 존재: 인터페이스에는 메소드의 선언만 있고, 구현부가 없습니다. 구현은 해당 인터페이스를 구현한 클래스에서 제공해야 합니다.(Java 8부터는 디폴트 메소드(default method)와 정적 메소드(static method)의 구현이 가능해졌습니다.)
다중 구현 가능: 자바에서는 하나의 클래스가 여러 인터페이스를 구현할 수 있습니다. 이는 자바에서 다중 상속이 불가능한 제약을 보완하는 역할을 합니다.
상수만 포함 가능: 인터페이스에 선언된 변수는 자동으로
public static final
로 선언됩니다. 즉, 인터페이스의 변수는 상수입니다.접근 제어자: 인터페이스의 메소드와 상수는 자동으로
public
으로 선언됩니다. 메소드에 별도로public
을 명시하지 않아도public abstract
로 간주됩니다.
2. 인터페이스 선언
위의 Animal
인터페이스는 sound()
라는 메소드를 정의하고 있으며, 구현부가 없습니다. 인터페이스를 구현하는 클래스에서 반드시 이 메소드를 구현해야 합니다. 또한 디폴트 메소드인 sleep()
은 기본 동작을 제공할 수 있습니다.
3. 인터페이스 구현
인터페이스는 implements
키워드를 사용하여 클래스에서 구현할 수 있습니다. 인터페이스를 구현하는 클래스는 해당 인터페이스의 모든 메소드를 구현해야 합니다.
인터페이스 구현 예시
interfaceExample 패키지에 작성
출력 결과
4. 인터페이스의 장점
다중 구현: 자바에서는 클래스는 하나만 상속받을 수 있지만, 여러 인터페이스를 동시에 구현할 수 있습니다. 이를 통해 자바의 다중 상속 제약을 해결할 수 있습니다.
다형성(Polymorphism): 인터페이스를 사용하면 다형성을 쉽게 구현할 수 있습니다. 여러 클래스가 같은 인터페이스를 구현하면, 인터페이스 타입으로 각기 다른 클래스의 객체를 참조할 수 있으며, 해당 인터페이스의 메소드를 호출할 수 있습니다.
유연성: 인터페이스는 객체들 간의 느슨한 결합(Loose Coupling)을 가능하게 하여, 유연한 코드 구조를 만들 수 있습니다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.
5. 인터페이스와 추상 클래스의 차이점
항목
인터페이스(Interface)
추상 클래스(Abstract Class)
객체 생성 여부
객체 생성 불가
객체 생성 불가
메소드
추상 메소드와 디폴트 메소드 가능 (Java 8 이후)
추상 메소드와 일반 메소드 모두 가질 수 있음
변수
상수만 가질 수 있음 (public static final
)
필드를 가질 수 있음
다중 상속
다중 구현 가능
다중 상속 불가
상속 키워드
implements
extends
추상 클래스와 인터페이스 비교 예시
compareAbstractWithInterface 패키지에 각각 작성
추상 클래스는 하나만 상속할 수 있지만, 인터페이스는 여러 개를 다중 구현할 수 있습니다.
6. 인터페이스와 다형성
인터페이스를 사용하면, 부모 인터페이스 타입의 참조 변수를 통해 여러 자식 클래스의 객체를 참조할 수 있습니다. 이를 통해 다형성(Polymorphism)을 구현할 수 있습니다.
다형성 예시
useInterfaceForPolymorphism 패키지에 각각 작성
Animal
인터페이스 타입의 참조 변수myAnimal
은Dog
와Cat
객체를 모두 참조할 수 있습니다.이는 다형성을 통해 동일한 메소드 호출이지만 다른 동작을 수행하게 만듭니다.
7. 디폴트 메소드와 정적 메소드
디폴트 메소드: Java 8 이후, 인터페이스에서 메소드의 기본 구현을 제공할 수 있는 디폴트 메소드를 사용할 수 있습니다. 이를 통해 기존 인터페이스를 수정하지 않고도 새로운 메소드를 추가할 수 있습니다.
정적 메소드: 인터페이스에서도 정적 메소드를 정의할 수 있으며, 이는 클래스처럼 인터페이스 이름을 통해 호출할 수 있습니다.
디폴트 메소드와 정적 메소드 예시
defaultMethodAndStaticMethod 패키지에 작성
싱글턴 패턴(Singleton Pattern)
싱글턴 패턴(Singleton Pattern)은 클래스의 인스턴스를 오직 하나만 생성하도록 보장하는 디자인 패턴입니다. 즉, 하나의 애플리케이션 내에서 특정 클래스에 대한 단일 객체만 존재하도록 하고, 해당 객체에 대한 글로벌 접근을 제공하는 방식입니다.
1. 싱글턴 패턴의 주요 특징
인스턴스가 하나만 존재: 클래스의 인스턴스가 오직 하나만 생성되도록 제한합니다.
글로벌 접근점 제공: 애플리케이션 어디서든 이 단일 인스턴스에 접근할 수 있습니다.
클래스 자체가 인스턴스 생성을 관리: 클래스 내부에서 객체를 생성하고, 외부에서 객체를 새로 생성하지 못하게 합니다.
2. 싱글턴 패턴 구현 방법
싱글턴 패턴을 구현하려면 생성자를 private
으로 선언하여 외부에서 객체를 생성하지 못하게 하고, 클래스 내부에서 정적 메소드를 사용하여 단일 인스턴스를 반환하도록 만듭니다.
싱글턴 패턴 구현 예시
singletonPatternExample 패키지에 각각 작성
설명
instance
변수:private static
으로 선언하여 클래스 로딩 시 단 한 번만 객체를 생성합니다.getInstance()
메소드: 외부에서 싱글턴 객체에 접근할 수 있도록 공용 정적 메소드로 제공됩니다. 이 메소드는 항상 유일한 인스턴스를 반환합니다.private
생성자: 외부에서 생성자를 호출하지 못하도록 하여, 외부에서 객체를 생성할 수 없습니다.
정리
싱글턴 패턴(Singleton Pattern)은 하나의 인스턴스만 생성하여 이를 전역적으로 접근할 수 있도록 하는 디자인 패턴입니다.
객체의 생성 비용을 줄이고, 공유 자원을 관리할 때 유용합니다.
Last updated