[JAVA]기본개념 Remind(객체지향 개념)

ggamang·2022년 9월 12일
0

JAVA&Spring

목록 보기
3/27

📌 자바의 정석 유튜브 인강으로 후루룩 정리 (50/171)

객체지향

객체지향 언어 = 프로그래밍 언어 + 객체지향개념

  • 코드 재사용성이 높다
  • 유지보수가 용이하다
  • 중복코드 제거

❗️특징

  • 캡슐화
  • 상속
  • 추상화
  • 다형성

클래스

클래스와 객체

클래스: 객체를 정의, 객체를 생성하기 위해 필요하다 (붕어빵 기계)
객체: 실제로 존재하는 사물, 개념 (붕어빵), 객체가 가진 속성과 기능을 사용한다
인스턴스: 특정 클래스로부터 생성된 객체

객체 = 속성(변수) + 기능(메서드)
클래스 --(인스턴스화)--> 인스턴스(객체)

하나의 소스파일에 여러 클래스 작성

public class가 있는 경우 - 소스파일 이름은 반드시 public class 이름과 일치
public class가 하나도 없는 경우 - 소스파일 이름은 파일 내 class명 아무거나 무관
public class는 소스파일 내에 '하나'만 존재해야한다
가능하면 하나의 소스파일에는 하나의 클래스만 작성하는 것이 바람직하다.
소스파일명과 main method가 들어있는 클래스 명은 동일해야 한다

객체의 생성과 사용

TV t;				// 클래스명 변수명
t = new Tv();		// 객체 생성 후 객체주소를 참조변수에 저장

t.channel = 7;		// 멤버변수 channel = 7
t.channelDown(); 	// 메서드 호출
  1. 클래스 작성
  2. 객체 생성
  3. 객체 사용

객체배열 == 참조변수 배열

Tv tv1, tv2, tv3;

Tv[] tvArr = new Tv[3];
tvArr[0] = new Tv();	//객체 생성 후 배열의 각 요소에 저장
tvArr[1] = new Tv();
tvArr[2] = new Tv();

Tv[] tvArr = {new Tv(), new Tv(), new Tv()};

클래스의 정의

  1. 클래스는 객체를 생성하기 위한 설계도이다
  2. 클래스 == 데이터 + 함수
    • 변수 : 하나의 데이터
    • 배열 : 같은 종류의 여러 데이터
    • 구조체 : 서로 관련된 여러 데이터(종류 관계 없이)
    • 클래스 : 데이터와 함수의 결합(구조체 + 함수)
  3. 사용자 정의 타입 : 원하는 타입을 직접 만들 수 있다

속성

선언 위치에 따른 변수의 종류

  1. 클래스 영역
    ⎻ 클래스 변수(static), 인스턴스 변수
  2. 메서드 영역
    ⎻ 지역 변수
class Variables{
	int iv;				// 인스턴스 변수
    static int cv;		// 클래스변수 (static 변수, 공유변수)
    
    void method(){
    	int lv = 0;		// 지역변수
    } // 메서드영역 - 메서드선언만 가능
} //클래스영역 - 선언문만 가능
  • 클래스 변수(cv) - 클래스가 메모리에 올라갈 때 생성
    ☞ 객체 생성 불필요, 아무때나 사용할 수 있다
    ☞ 모든 인스턴스의 공통 속성
  • 인스턴스 변수(iv) - 인스턴스가 생성될 때 생성
    ☞ 객체가 생성이 되어야 사용할 수 있다
    ☞ 각 인스턴스의 개별 속성
  • 지역 변수(lv) - 변수 선언문 수행될 때 생성

    멤버 변수(iv, cv) - 지역 변수(lv)

class Card{
	String shape;
    int number;
    
    static int width = 100;
    static int height = 250;
}

Card c1 = new Card();
c1.shape = "HEART";
c1.number = 5;
c1.width = 200;	//c1.width 참조변수도 사용가능하나 권장하지 않음.
Card.height = 300; // cv는 혼동하지 않도록 클래스명으로 선언하는 것 권장
Card c2 = new Card(); //c2의 width, height도 200,300

메서드

  1. 문장들을 묶어놓은 것 : 작업단위로 묶어서 이름 붙인 것
  2. 입력을 받아서 처리하고, 결과를 반환한다
  • 코드의 중복 줄일 수 있다
  • 코드의 관리가 쉽다
  • 코드 재사용 가능
  • 코드 간결해서 이해 용이

하나의 메서드는 한 가지 기능만 수행하도록 작성한다

메서드 = 선언부 + 구현부
⎻ 선언부: 반환타입 메서드명 (매개변수 타입, 변수명 ...)

메서드 호출: 메서드이름(값1, 값2...);
return: 반환 타입이 void가 아닌 경우 반드시 return문 필요, 반환타입과 반환하는 값이 타입이 일치해야 한다

호출 스택(call stack)

메서드 수행에 필요한 메모리가 제공되는 공간
메서드가 호출되면 호출스택에 메모리 할당
종료되면 메모리 해제
아래에 있는 메서드가 위의 메서드를 호출한 것이다
맨 위의 메서드 하나만 실행 중이고, 나머지는 대기 중이다.

❗️매개변수

⎻ 기본형 매개변수: 변수의 값을 읽기만 할 수 있다
☞ 별도 스택 공간에 개별 값 저장
⎻ 참조형 매개변수: 변수의 값을 읽고 변경할 수 있다
☞ 주소값을 복사, 같은 주소를 참조하기에 update가 가능한 구조

❗️static 메서드, 인스턴스 메서드

⎻ 인스턴스 메서드 : 인스턴스 생성 후, '참조변수.메서드이름()'으로 호출, 메서드 내에서 인스턴스 변수 사용 가능
⎻ static 메서드 : 객체 생성 없이, '클래스이름.메서드이름()'으로 호출, 메서드 내에서 인스턴스 변수 사용 불가

class MyMath2{
	long a,b;	//iv
    
    long add(){ // 인스턴스 메서드
    	return a+b;
    }
    
    static long add(long a, long b){ // static 메서드(=클래스메서드)
    	return a+b; //lv
    }
}

💡static은 언제 붙여야 할까?

  1. 변수: 속성(멤버 변수) 중에서 공통 속성에 static을 붙인다.
  2. 메서드: 인스턴스 멤버(iv, im)를 사용하지 않는 메서드에 static을 붙인다.

오버로딩(Overloading)

한 클래스 안에 같은 이름의 메서드여러 개 정의하는 것
매개변수는 다르지만 같은 의미의 기능을 수행한다

메서드 : 메서드명 = 1 : 1 ☞ 메서드 : 메서드명 = N : 1
(과적하다 - Overloading)

성립조건

  • 메서드 이름 동일
  • 매개변수의 개수 혹은 타입이 달라야 한다!
  • 반환 타입은 영향 없다

생성자(constructor)

인스턴스가 생성될 때마다 호출되는 인스턴스(iv) 초기화 기능
인스턴스 생성 시 수행할 작업(iv 초기화 등)에 사용

Time t = new Time();
t.hour = 12;
t.minute = 34;
t.second = 56;

Time t1 = new Time(12, 34, 56); 	// 생성자
  • 이름이 클래스 이름과 같아야 한다
  • 리턴 값이 없다. void를 붙이지 않는다.
  • 모든 클래스는 반드시 1개 이상의 생성자를 가져야 한다.
class Card {
	Card () {	// 매개변수 없는 생성자
    	// 인스턴스 초기화
    }
    
    Card (String shape, int number) {	// 매개변수 있는 생성자
    	// 인스턴스 초기화
    }
}

Card c = new Card(); 			// 생성자 호출(기본 생성자)
Card c1 = new Card("HEART", 7);	// 매개변수 있는 생성자 호출

기본 생성자 : 매개변수가 없는 생성자. '생성자가 하나도 없을 때' 컴파일러가 자동으로 추가한다.

생성자 this()

생성자에서 같은 클래스의 다른 생성자를 호출할 때 사용
☞ 코드의 중복 제거
다른 생성자 호출 시 첫 줄에서만 사용 가능하다

class Car2 {
	String color;
    String gearType;
    int door;
    
    Car2() {
    	this("white", "auto", 4);	// 지정 안했을 시 default 값. this를 사용하여 아래의 생성자를 호출하도록 한다.
    }
    Car2(String color) {
    	this(color, "auto", 4);
    }
    Car2(String color, String gearType, int door){
    	this.color = color;
        this.gearType = gearType;
        this.door = door;
    }
}

참조변수 this

인스턴스 자신을 가리키는 참조변수. 인스턴스의 주소가 저장되어 있다.
별도 선언을 안해도 사용할 수 있다.
인스턴스 메서드(생성자 포함)에서 사용 가능, 클래스 메서드에서는 사용 불가
지역 변수와 인스턴스 변수를 구별할 때 사용

Car(String color, String gearType, int door){
	this.color = color;			//좌: iv(참조변수.변수이름), 우: lv
    this.gearType = gearType;
    this.door = door;
}

❗️생성자 this()와 참조변수 this는 완전히 다른 것이다

변수의 초기화

지역 변수는 사용 전 반드시 값을 수동 초기화 해야 한다.

멤버변수(iv, cv) 초기화

  • 자동 초기화
  • 명시적 초기화 : 대입연산자(=) 사용 (간단 초기화)
  • 초기화 블럭: 인스턴스 초기화 블럭 {}, 클래스 초기화 블럭 static {} (복잡 초기화)
  • 생성자 : iv 초기화 (복잡 초기화)
class StaticBlockTest {
	static int[] arr = new int[10]; // 명시적 초기화
    
    static { // 클래스 초기화 : 배열 arr에 난수로 값 초기화
    	for(int i=0;i<arr.length;i++){
        	arr[i] = (int)(Math.random()*10)+1;
        }
    }
}

⎻ 클래스 변수 초기화 시점: 클래스 처음 로딩될 떄 단 한 번(메모리에 올라갈 때)
⎻ 인스턴스 변수 초기화 시점: 인스턴스 생성될 때 마다

초기화 순서
cv 초기화(1회) ➣ iv 초기화
자동초기화 ➣ 간단초기화 ➣ 복잡초기화 순

클래스 간 관계

상속

기존의 클래스로 새로운 클래스를 작성하는 것 (코드의 재사용)
두 클래스를 부모와 자식으로 관계를 맺어 주는 것
( 자식클래스 → 부모클래스)

class 자식클래스 extends 부모클래스 {

};

class Parent { }
class Child extends Parent{}

자손은 조상의 모든 멤버를 상속받는다 (생성자, 초기화 블럭 제외)
자손의 멤버 개수는 조상보다 적을 수 없다. = 같거나 많다
자손의 변경은 조상에 영향을 미치지 않는다.

class Point{	// Point3D 변경에 영향을 받지 않는다
	int x;
    int y;
}

class Point3D extends Point{	//Point 변경에 영향을 받는다
	int z;
}

단일상속

JAVA는 단일상속만을 허용한다

☞ 비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 한다

Oject클래스

모든 클래스의 조상이다. 부모가 없는 클래스는 자동으로 Object 클래스를 상속받는다
Object 클래스에 정의된 11개의 메서드를 상속받는다(toString(), equals() 등)

포함

클래스의 멤버로 참조변수를 선언하는 것
작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다

class Point{
	int x;
    int y;
}

class Circle{
	Point c = new Point(); // 참조변수의 초기화. Circle과 Point는 포함관계이다
    int r;
}

public class InheritanceTest{
	public static void main(String[] args){
    	Circle c = new Circle();
        c.p.x = 1;
        c.p.y = 2;
        c.r = 3;
    }
}

상속관계 : A는 B이다
포함관계 : A는 B를 가지고 있다
☞ 더 자연스러운 문장의 관계를 채택한다 (대부분 포함이 많다)

오버라이딩(Overriding)

상속받은 조상의 메서드를 자신에 맞게 변경하는 것(=덮어쓰다)

class Point {
	int x;
    int y;
    
    String getLocation() {
    	return "x: " + x + ", y: " + y;
    }
}

class Point3D extends Point {
	int z;
    
    String getLocation() { // 조상의 함수 오버라이딩
    	return "x: " + x + ", y: " + y ",z:" +z;
    }
}

오버라이딩 조건

  • 선언부가 조상클래스의 메서드와 일치해야 한다
  • 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다
    ❗️public protected default private
  • 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

Overloading vs Overriding

오버로딩 : 기존에 없는 새로운 메서드 정의. 이름만 같다.
오버라이딩 : "상속"받은 메서드의 내용을 변경하는 것

참조변수 super

객체 자신을 가리키는 참조변수. 인스턴스 메서드(생성자)내에서만 존재(=static 메서드 내에 사용 불가)
조상의 멤버를 자신의 멤버와 구별할 때 사용한다
(cf: this - lv와 iv 구별에 사용)

class Main {
	public static void main(String args[]){
    	Child c = new Child();
        c.method();
    }
}

Class Parent { int x = 10; // super.x }

// Case 1
Class Child extends Parent {	 // this.x
	int x = 20;

	void method(){
    	System.out.println(x);	// 20
        System.out.println(this.x);	//20
        System.out.println(super x);	//10
    }
}

// Case 2
Class Child2 extends Parent {
	void method(){
    	System.out.println(this.x); // 10
        System.out.println(super.x); // 10
    }
}

조상의 생성자 super()

조상의 생성자를 호출할 때 사용한다
조상의 멤버는 조상의 생성자를 호출해서 초기화

class Point {
	int x,y;
    
    Point(int x, int y){
    	this.x = x;
        this.y = y;
    }
}

Class Point3D extends Point {
	int x;
    
    Point3D(int x, int y, int z){
    	super(x,y);	// 조상클래스의 생성자 Point(int x, int y) 호출
        this.z = z;	// 자신의 멤버 초기화
    }
}

❗️super()의 조건

  • 생성자의 첫 줄에 반드시 다른 생성자를 호출해야 한다.
    그렇지 않으면 컴파일러가 생성자의 첫줄에 super();를 삽입한다
    ☞ 항상 클래스를 만들 때 '기본 생성자(매개변수 없는 것)'는 필수적으로 생성해준다

패키지

서로 관련된 클래스의 묶음
클래스의 실제 이름(full name)은 패키지를 포함한다

패키지의 선언

패키지는 소스파일 첫 번째 문장으로 한 번 선언
(package com.codechobo.book;)
같은 소스파일 클래스들은 모두 같은 패키지에 소속
패키지 선언이 없으면 unnamed 패키지에 소속

classpath

클래스 파일의 위치를 알려주는 경로
환경변수 classpath로 관리하며, 경로간의 구분자는 ; 를 사용

import문

클래스를 사용할 때 패키지명을 생략할 수 있다
import java.util.Date;
컴파일러에게 클래스가 속한 패키지를 알려준다
java.lang 패키지의 클래스는 import하지 않고도 사용 가능 - String, Object, System, Thread 등

static import문

static멤버를 사용할 때 클래스 이름을 생략할 수 있게 해준다.

import static java.lang.Math.random;
import static java.lang.System.out;

out.println(random()); // System.out.println(Math.random());

제어자

클래스와 클래스의 멤버(멤버 변수, 메서드)에 부가적인 의미 부여

  • 접근제어자 : public, protected, default, private
  • 그 외 : static, final, abstract 등
    하나의 대상에 여러 제어자를 같이 사용할 수 있다. 접근제어자를 제일 먼저 쓰는 게 관례.
    (단 접근제어자는 하나만 사용)

static

멤버변수

  • 모든 인스턴스에 공통적으로 사용하는 cv가 된다
  • 인스턴스 생성하지 않고도 사용 가능
  • 메로리 로드 시 생성
    메서드
  • 인스턴스 생성하지 않고도 호출이 가능한 메서드
  • static 메서드 내에서는 iv 멤버들을 직접 사용할 수 없다 (iv 변수는 인스턴스 생성 후에야 사용 가능)

final

클래스

  • 변경될 수 없는 클래스
  • final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다(=부모가 될 수 없다) ex. String, Math 등
    메서드
  • final 지정 메서드는 오버라이딩 불가
    멤버변수/지역변수
  • final 붙은 변수는 상수

abstract

클래스

  • 클래스 내 추상 메서드가 선언되어 있음을 의미
    메서드
  • 선언부만 작성하고 구현부는 작성하지 않았음.(미완성)

추상 클래스의 인스턴스는 생성 불가.
☞ 해당 클래스를 사용하려면 '상속'을 통해 완전한 클래스로 만든 후 객체 생성이 가능하다.(=구상클래스)

abstract class AbstractTest {
	abstract void move();	// 구현부 {} 가 없는 메서드
}

접근제어자

  • private : 같은 클래스에서만 접근 가능
  • default : 같은 패키지에서만 접근 가능
  • protected : 같은 패키지 + 다른 패키지의 '자손클래스'에서 접근 가능
  • public : 접근 제한 없음

클래스 - public, default
(하나의 소스파일에 public class는 하나여야 한다 / public class와 소스파일명이 일치해야한다)
멤버 - public, protected, default, private

접근제어자 사용 이유
1. 외부로부터 데이터를 보호하기 위해
2. 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서

캡슐화

외부의 직접 접근을 막아 데이터를 보호한다

public class Time{
	private int hour;
    
    public void setHour(int hour){	// 간접접근 허용
    	if ( hour < 0 || hour > 23 ) return;
        this.hour = hour;
    }
}
public class Main{
  Time t = new Time();
  t.hour = 25; // X. 멤버변수에 직접 접근해서 오데이터 등록 안됨
  t.setHour(25); // 범위밖의 데이터이므로 그냥 return
}

다형성(Polymorphism)

개념

여러 가지 형태를 가질 수 있는 능력
조상 타입 참조 변수로 자손 타입 객체를 다루는 것
자손 타입의 참조 변수로 조상 타입의 객체를 가리킬 수 없다.

Tv t = new Tv();
SmartTv s = new SmartTv();

Tv t = new SmartTv(); // 타입 불일치 : 조상 타입 참조변수로 자손 타입 객체를 생성했다

객체와 참조변수 타입이 일치할 경우 vs 불일치할 경우

참조변수로 사용할 수 있는 멤버의 개수가 달라진다

ex) Tv 클래스(멤버변수 5개)와 SmartTv 자식클래스(자식 멤버변수 2개)

SmartTv s = new SmartTv();
Tv t = new SmartTv();
  1. 일치할 경우
  • 객체 s는 7개의 멤버변수를 모두 사용 할 수 있다
  1. 불일치할 경우
  • 객체 t는 5개의 멤버변수만 사용 가능하나, 7개의 속성을 모두 갖고는 있다

참조변수의 형변환

사용할 수 있는 멤버의 개수를 조절하는 것
조상-자손 관계의 참조변수는 서로 형변환이 가능하다

class Car { }
class FireEngine extends Car { }
class Ambulance extends Car { }

FireEngine f = new FireEngine();
Car c = (Car) f;					// 조상인 Car 타입으로 형변환 -> FireEngine에만 있는 멤버속성 사용 불가
FireEngine f2 = (FireEngine) c;		// 자손인 FireEngine 타입으로 형변환 -> FireEngine에만 있는 멤버속성 사용 가능
Ambulance a = (Ambulance)f;			// 에러. 상속관계 아님

instanceof 연산자

참조변수의 형변환 가능 여부 확인에 사용. 가능하면 true 반환한다.
단, 모든 조상들에 대해서 true 값이 나온다. (Object 클래스로도 형변환이 가능하다)

void doWork (Car c) { 
	if ( c instanceof FireEngine) {	// 형변환이 가능한지 조건문에서 먼저 확인 후 형변환을 진행하기
    	FireEngine fe = (FireEngine) c;
     }
}

장점 1. 매개변수의 다형성

메서드 호출 시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다

class Product {
	int price; 
    int bonusPoint;
}

class Tv extends Product {}
class Computer extends Product {}
class Audio extends Product {}

class Buyer {
	int money = 1000;
    int bonusPoint = 0;
}
void buy (Tv t) { ... }
void buy (Computer c) { ... }


하나의 Type으로 구현이 가능해진다

Product p1 = new Tv();
Product p2 = new Computer();

void buy (Product P) { ... }

장점 2. 한 배열에 여러 종류의 객체 저장

조상 타입의 배열에 자손들의 객체를 담을 수 있다

Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

추상 클래스, 메서드

추상클래스

미완성 메서드를 갖고 있는 클래스
인스턴스 생성 불가, 다른 클래스 작성에 도움을 주기 위함
☞ 상속을 통해 추상 메서드를 완성해야 인스턴스 생성 가능

추상메서드

구현부가 없는 메서드
꼭 필요하지만 자손마다 다르게 구현될 것으로 예상될 경우 사용

사용

추상화된 코드는 구체화된 코드보다 유연하여 변경에 유리하다.

추상메서드의 호출

메서드는 선언부만 알면 호출 가능하므로, 추상메서드도 호출은 가능하다.
그러나 인스턴스 생성이 어차피 불가하기에, 추후 상속을 통해 완성되고 인스턴스가 생성이 될 때 실질적으로 코드 실행이 가능하다.

추상클래스의 작성

여러 클래스에 공통적으로 사용될 수 있는 추상클래스를 바로 작성하거나, 기존 클래스의 공통 부분을 뽑아서 추상클래스를 만든다 ☞ 코드 중복 제거

abstract class Unit {
	int x, y;
    abstract void move(int x, y);
    void stop() { // } ;
}

class Marine extends Unit {
	void move(int x, int y) {
    	System.out.println("Marine move");
    }
}

class Tank extends Unit {
	void move(int x, int y) {
    	System.out.println("Tank move");
    }
}

class Ship extends Unit {
	void move(int x, int y) {
    	System.out.println("Ship move");
    }
}

...

Unit[] group = { new Marine(), new Tank(), new Ship() };
group[0].move(); // Marine 객체의 move
group[1].move(); // Unit 객체의 move
group[2].move(); // Ship 객체의 move

인터페이스

추상 메서드의 집합
구현된 것이 하나도 없는 설계도. 모든 멤버가 public이다.

추상클래스 vs 인터페이스

추상클래스는 일반 클래스인데 추상 메서드를 포함하고 있는 것
인터페이스는 추상 메서드의 집합. 인터페이스는 iv를 가질 수 없다

interface 인터페이스명 {
	public static final 타입 상수이름 = 값;
    public abstract 메서드명(매개변수목록);
}

⎻interface 내 public, abstract 생략 가능 (interface에서는 항상 예외없이 public이자 abstract이다)

인터페이스의 조상은 인터페이스만 가능하다(Object가 최고 조상이 아니다)
다중상속이 가능하다
☞ 추상메서드는 메서드명 동일해도 충돌 문제가 없다
선언부가 다르면 둘 다 상속받으면 그만인데, 선언부가 같고 구현부가 다르면 어느 쪽을 상속받을지 결정할 수 없다

인터페이스 구현

인터페이스에 정의된 추상 메서드를 완성하는 것 ☞ implements
인터페이스에 정의된 추상 메서드를 모두 구현해야 한다
⎻ 일부만 구현하는 경우, 클래스 앞에 abstract 붙여야 한다

class 클래스명 implements 인터페이스명 { }

인터페이스를 이용한 다양성

interface Fightable{
	void move(int x, int y);
    void attack(Fightable f); // Fightable 인터페이스를 구현한 클래스의 인스턴스만 가능
}

class Fighter extends Unit implements Fightable {
	public void move (int x, int y) { }
    public void attack(Fightable f) {}
}

Unit u = new Fighter(); //조상클래스
Fightable f = new Fighter(); //인터페이스로 구현

디폴트 메서드

인터페이스를 메서드의 리턴타입으로 지정할 수 있다

인터페이스의 장점

  1. 두 대상 간의 연결, 대화, 소통을 돕는 중간 역할
  2. 선언(설계)와 구현을 분리시킬 수 있게 한다 (= 느슨한 결합)
  3. 개발 시간 단축 가능
  4. 변경에 유리한 유연한 설계 가능
  5. 표준화 가능
  6. 서로 관계 없는 클래스들을 관계를 맺어줄 수 있음.

디폴트 메서드와 static 메서드 추가 가능 (JDK1.8)

디폴트 메서드

인터페이스에 새로운 메서드를 추가하면, 각 클래스별로 새로운 메서드를 구현해야 하기에 새로운 메서드 추가가 어렵다
☞ 디폴트 메서드

충돌 시 해결책
1. 여러 인터페이스와 디폴트 메서드간의 충돌
☞ 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩
2. 디폴트 메서드와 조상클래스 메서드 간의 충돌
☞ 조상클래스의 메서드가 상속, 디폴트 메서드는 무시

0개의 댓글