
스테레오 타입 : 인터페이스
concrete : 구현 클래스



## 1교시 인터페이스
>> 추상메서드
1. abstract 안붙여도 인터페이스는 디폴트가 추상메서드이다 (본문없이)
2. 다형성의 달성을 위해서 사용한다 (상속과 오버라이딩)
3. 필드는 public static final 이 기본값임
4. 생성자, main 메소드는 사용 불가, default 메서드는 this 가 있다고 가정, this로의 접근은 불가
## 2교시 인터페이스
> default, this
메소드 중에 상속된 클래스의 인스턴스의 기본 메서드를 default 키워드로 제공 가능
this로의 접근은 불가 (this.x 불가)
기본 메서드는 다양한 명칭으로 불림
default method == defender method == virtual extension method
> Static method
인터페이스에는 클래스의 정적 메서드와 유사한 static 메서드도 있을 수 있습니다.
defulat method & multiple inheritance
구현된 두 인터페이스 모두 동일한 메서드 시그니처를 가진 기본 메서드를 포함하는 경우
구현 클래스는 사용할 기본 메서드를 명시적으로 지정하거나 기본 메서드를 재정의(override) 해야 합니다.
> 예시 :
interface A {
public default void display() {
System.out.println("AAAA");
}
}
interface B {
public default void display() {
System.out.println("BBBB");
}
}
// 오버라이딩 되지 않은 경우
public class InterfaceExample implements A, B {
// 이럴때는 오버라이딩 해서 쓰면됨
// @Override
// public void display() {
// A의 display를 쓰겠다
// A.super.display();
// B의 display를 쓰겠다
// B.super.display();
// 혹은 아예 재정의
// System.out.println("CCCC");
// }
public static void main(String args[])
{
InterfaceExample obj = new InterfaceExample();
// A의 display를 실행해야 하는 지, B의 display를 실행해야 하는 지 알 수 없어 에러가 남
// 호환불가
obj.display();
}
}
private 메서드는 default 메소드에서 사용 가능
private static 메서드는 default 메소드와 static 메소드에서 사용 가능
default메서드와 static 메서드의 차이
부모타입으로 자식 인스턴스를 이용할 수 있다 LSP (Liskov substitution principle)
## 실무 case
다형성을 이용하고 싶다면 extends 대신 인터페이스로 implements 하여 interface 타입으로 사용하기를 권하며,
상위 클래스의 기능을 이용하거나 재사용을 하고 싶다면
상속(inheritnace) 보단 실체화(realization) 를 권장
>> 차에 타이어 인터페이스 타입으로 인스턴스화(new) 하는 방식 [Has-a 관계]
예시 :
class HankookTire implements Tire {
//추상 메소드 재정의
@Override
public void roll() {
System.out.println("한국 타이어가 굴러갑니다.");
}
}
class KumhoTire implements Tire {
//추상 메소드 재정의
@Override
public void roll() {
System.out.println("금호 타이어가 굴러갑니다.");
}
}
class Car {
//필드
Tire tire1 = new HankookTire();
Tire tire2 = new KumhoTire();
//메소드
void run() {
tire1.roll();
tire2.roll();
}
}
public class CarExample {
public static void main(String[] args) {
//자동차 객체 생성
Car myCar = new Car();
//run() 메소드 실행
myCar.run();
//타이어 객체 교체
myCar.tire1 = new HankookTire();
myCar.tire2 = new KumhoTire();
//run() 메소드 실행(다형성: 실행 결과가 다름)
myCar.run();
}
}
## 3교시 UML / SOLID
클래스 다이어그램 참고사이트] https://mermaid.js.org/syntax/classDiagram.html
Has-a (realization)
Is-a (Inheritance)
### 정적 메소드
메소드명 앞에 static 키워드 붙는다
인스턴스를 만들지 않아도 클래스에서 바로 메소드를 사용할 수 있게 해준다
메인 메소드는 정적 메소드인가요?
네
왜? 앞에 static키워드를 사용했고, 인스턴스 없이 실행가능하니까
### 추상 메소드
인터페이스를 정의할 때는 모두 추상 메소드이다
재정의(Overriding) 해서 써야 한다
오버라이딩 ⇒ 재정의
달리다를 오버라이딩을 했다고 하면?
사람이 달린다를 개가 달린다 라고 구체화 시킬 수 있음
실제로 상속받아서 (implemets 구현해서 사용) 사용한다
## 디폴트 메소드
실체화된 인스턴스가 구현된 인스턴스가 this일 것이다 하고 실현이 되는 것
추상 메소드는 본래 본문이 없음 누군가가 실제로 구현(implemnt, extend)해서 사용하는 것
즉, 기능이 없고 이름만 있다 (본문이 없는 모습)
* 상속을 받거나 구현을 했을 때 실제로 정의해서 사용해야 한다
디폴트 메소드는 본문을 작성 할 수 있음
인스턴스가 나를 상속(extend, implement) 받은 자식을 가르키게 된다
다만 자식이 어떤 것을 가지고 있는지 모른다. 접근이 불가능하다는 뜻 (this.xxx 은 디폴트 메소드 안에서 사용할 수 없음)
상속받은 애가 어느정도 부수적인 기능을 할 수 있도록 구현을 해놓았다
추상 클래스 → 추상 메소드 구현
본문: 자식 A에도 System.out.println 했고 자식 B에도 하는 출력문을 계속적으로 작성해야함
불편.... 디폴트 메소드에다가 1999줄 작성하고 나머지 한 줄만 너가 채워서 써!
이런 기능들을 미리 정의 할 수 있도록 하는 것이 디폴트 메소드
### private 메소드
상속을 받았거나 구현을 했을 때 이 메소드를 쓸 수 있나요?
못 쓴다
왜? sub 클래스가 부모 클래스로 접근 할 수 없도록 막아버림 (접근 제한)
실제로 자식을 만들었을 때 실체는 있지만 접근은 못 함
프라이빗 필드는 자동 완성으로 안 나옴 → 인텔리제이에서
접근 할 수 있는 메소드 하나를 정의해서 쓰고는 한다 (캡슐화 적용) getXxx() 로 만들어 씀
private 키워드를 사용하더라도 본인 클래스 안에서는 접근할 수 있다는 원리를 이용해서
자식을 실제로 인스턴스화 했을 때 x는 접근 못하지만 getX() 는 접근 가능하도록 함
⇒ getter와 setter의 역할
캡슐화로 인해서!
불필요한 속성은 숨기고, 원하는 기능만 보게 해 주는 것
getter만 있으면 수정 불가 (setter 메소드가 없으면 수정할 방법이 없음) readonly로 만든다는 의미
getter + setter도 있으면 수정 가능
정리 하자면...
## 정적 메소드 (Static Method)
사용법: 클래스명.메소드명()
특징: 인스턴스 생성 없이 사용, 클래스 레벨에서 공유
## 추상 메소드 (Abstract Method)
사용법: abstract 키워드 사용
특징: 선언만 하고 구현은 없음, 상속받은 클래스에서 반드시 구현
## 디폴트 메소드 (Default Method)
사용법: default 키워드 사용
특징: 인터페이스에서 기본 구현 제공, 필요시 오버라이드 가능
## 프라이빗 메소드 (Private Method)
사용법: private 키워드 사용
특징: 클래스 내부에서만 접근 가능, 캡슐화된 내부 동작
각 키워드는 객체 지향 프로그래밍의 다양한 원칙과 패턴을 구현하는 데 사용되며, 특정 상황에서 올바르게 사용하는 것이 중요합니다. 이를 통해 코드의 재사용성, 유지보수성, 가독성을 높일 수 있습니다.
public default private protect의 개념은 이해가 되지만..
각각 언제 활용해야되는 것인지에 대해 잘 모르겠어요
그냥 저희가 프로그램 코드를 작성할 때 속성들의 접근 범위를
지정하고 싶은데로 사용하면 되는 것인가요?
어떤건 private으로 선언해야되! 같은 규칙이 있는 건 아닌거죠?
> 규칙이 있긴 있어요 : 사용할 수 있는 접근 제한자가 정해져 있다
> 다만 용도는 접근제한
ex ) Class public / default(안씀)
>> Inner Class 는 private Class 가능
--------------------
저희가 실습에서 사용하는 private는 원래
사용하면안되는 private인건가요?
> 상속을 못하게 되는 경우에는 private를 제거해주어야 할거에요
--------------------
@Override 꼭 써야만 하나요?
>1. Override 어노테이션이 있으면 다른 개발자가 이 메소드가 인터페이스에서 오버라이딩 되었다는걸 쉽게 알 수 있어요
interface 파일을 열어보지 않아도 된다는 뜻이기도 합니다
>2. 컴퓨터가 Override 어노테이션을 썼는데 interface 에 이 메소드가 없을 경우에 알려줘요
너가 오버라이드 하려는 메소드가 인터페이스에는 없다. 라고
--------------------
new 연산자로 객체를 생성할 때 객체를 왜 초기화 하나요
1. 초기값이 정해지지 않은 경우를 방지할 수 있습니다
2. 반드시 초기화 하지는 않아도 됩니다 lazy하게 객체부터 만든 후 setter를 사용하기도 합니다
--------------------
자바에서의 this 키워드는 클래스로 만들어진 인스턴스입니다.
예시 :
public class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Animal a1 = new Animal("동물1");
Animal a2 = new Animal("동물2");
}
}
--------------------
컴퓨터 입장에서 NaN값과 Null 값을 같게 판단하는지 다르게 판단하는지 궁금합니다.
> 언어에 따라 다릅니다
java util에서 Objects 를 import하고 isNull() 메소드를 사용하는데
isNull에 NaN값이 들어가면 true를 반환하는지 false를 반환하는지 궁금합니다.
> false
--------------------
// 인터페이스 변수 선언
RemoteControl rc1;
RemoteControl rc2;
// Television 객체 생성하고 인터페이스 변수에 대입
rc1 = new Television();
rc1.turnOn();
rc1.setVolume(5);
rc1.turnOff();
// Audio 객체 생성하고 인터페이스 변수에 대입
rc2 = new Audio();
rc2.turnOn();
rc2.setVolume(11);
rc2.turnOff();
이런 식으로 하면 Television을 가진 rc1 인스턴스가 사라지지 않고 rc1과 rc2를 계속 쓸 수 있는 것 맞나요?
--------------------
### 추상
인터페이스: 메소드 디폴트가 public이라 안써도 됨
구현: public 메소드 써야됨
### 디폴트
인터페이스 : default 메소드에서 함수 선언 가능
구현 : public 메소드
### 정적
인터페이스 : static 메소드
구현 : 필요없음
### main : 바로 호출 가능
### 클래스 this는 클래스에서 만들어진 인스턴스를 가리킨다.