[Java] 명품 Java Programming 정리 - 5장

근이의 개발일기·2024년 8월 19일
0
post-thumbnail

5장

클래스 상속과 객체

  • 객체 지향의 상속: 부모클래스에 만들어진 필드, 메소드를 자식 클래스가 물려받음
    • 상속을 통해 간결한 자식클래스 작성; 동일한 특성을 재정의할 필요 없어 자식 클래스가 간결해짐

      Untitled

  • 객체 지향에서 상속의 장점
    • 클래스의 간결화: 멤버의 중복 작성 불필요
    • 클래스 관리 용이: 클래스들의 계층적 분류
    • 소프트웨어의 생산성 향상: 클래스 재사용과 확장 용이 및 새로운 클래스의 작성 속도 빠름
  • 자바의 상속 선언 Untitled
    • 부모 클래스 = 슈퍼 클래스로 부름

    • 자식 클래스 = 서브 클래스로 부름

    • extends 키워드 사용; extends Super_Class_Name
      - 슈퍼 클래스를 확장한다는 개념

      상속 예시: Point와 ColorPoint 클래스

      class Point{
          private int x,y;
          public void set(int x, int y)
          {
              this.x = x;
              this.y = y;
          }
          public void showPoint(){
              System.out.println("("+x+","+y+")");
          }
      }
      class ColorPoint extends Point{
          private String color;
          public void setColor(String color){
              this.color = color;
          }
          public void showColorPoint(){
              System.out.print(color);
              showPoint();
          }
      }
      
      public class ColorPointEx extends Point {
          public static void main(String[] args) {
              Point p = new Point();
              p.set(1,2);
              p.showPoint();
      
              ColorPoint cp = new ColorPoint();
              cp.set(3,4);
              cp.setColor("red");
              cp.showColorPoint();
          }
      }

      출력 결과:

      (1,2)

      red(3,4)

      Untitled

    • 중요 컴파일러의 흐름을 알아야함 → 서브클래스의 객체를 생성하고 메소드를 호출할 때, 서브 클래스의 선언부를 먼저 확인하고 메소드가 없을 때 슈퍼 클래스의 선언부로 가서 확인한다.

      ㄴ하위에서부터 상위로 멤버 호출!
      
      - this.으로 부모의 메소드 사용까지 가능하다!

      Untitled

    • 주의! 서브 클래스에서 슈퍼 클래스의 private 변수에 접근할 수 없다

자바 상속의 특징과 접근지정자

  • 자바 상속의 특징
    • 클래스의 다중 상속 지원하지 않음 (한 클래스가 2개 이상의 부모클래스를 가질 수 없음)

    • 상속 횟수 무제한

    • 중요 상속의 최상위 조상 클래스는 java.lang.Object 클래스
      - 모든 클래스는 자동으로 java.lang.Object를 상속받음
      - 자바 컴파일러에 의해 자동으로 이루어짐

      Untitled

  • 중요 상속과 접근 지정자
    • 자바의 접근 지정자 4가지
      - public, protected, 디폴트, private
      - 상속 관계에서 주의할 접근 지정자는 private와 protected
      - 슈퍼 클래스의 private 멤버
      - 슈퍼 클래스의 private 멤버는 다른 모든 클래스(서브클래스 일지라도)에 접근 불허
      - 클래스내의 멤버들에게만 접근 허용
      - 슈퍼 클래스의 디폴트 멤버
      - 슈퍼 클래스의 디폴트 멤버는 패키지 내 모든 클래스에 접근 허용
      - 슈퍼 클래스의 public 멤버
      - 슈퍼 클래스의 public 멤버는 다른 모든 클래스에 접근 허용
      - 슈퍼 클래스의 protected 멤버
      - 같은 패키지 내의 모든 클래스 접근 허용
      - 주의! 다른 패키지에 있어도 서브 클래스는 슈퍼 클래스의 protected 멤버 접근 가능

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/6db20fe2-825c-4ee3-a055-f6eff701985c/Untitled.png)

      상속관계에 있는 클래스 간 멤버 접근 예시

      class Person{
          public String name;
          int age;
          protected int height;
          private int weight;
          public void setWeight(int weight) {
              this.weight = weight;
          }
          public int getWeight() {
              return weight;
          }
      }
      
      class Student extends Person {
          public void set() {
              name = "홍길동";
              age = 30;
              height = 175;
              //weight = 99;
              setWeight(99);
          }
      }
      
      public class IngeritanceEx {
          public static void main(String[] args) {
              Student s = new Student();
              s.set();
          }
      }

서브클래스(Student)의 set() 함수에서 슈퍼클래스(Person)의 멤버 접근

name: 슈퍼클래스의 public 멤버 접근 가능

age: 슈퍼클래스의 디폴트 멤버 접근 가능

ㄴ만약 다른 패키지라면 디폴트 멤버도 접근 불가

height: 슈퍼클래스의 protected 멤버 접근 가능

ㄴ만약 다른 패키지 일지라도 디폴트 멤버는 접근 가능

weight: 슈퍼클래스의 private 멤버이므로 접근 불가

중요 상속에 따른 생성자

  • 중요 서브 클래스 / 슈퍼 클래스의 생성자 호출 및 실행
    • 서브 클래스 객체가 생성될 때 서브 클래스의 생성자와 슈퍼 클래스의 생성자는 모두 실행된다!

    • 호출 순서: 서브클래스의 생성자가 먼저 호출되고 서브 클래스의 생성자는 실행 전 슈퍼 클래스 생성자 호출

    • 실행 순서: 슈퍼 클래스의 생성자가 먼저 실행된 후 서브 클래스의 생성자 실행

    • 주의! 서브클래스 생성자가 먼저 호출되지만 실행하기 전에 슈퍼클래스의 생성자를 호출하여서 서브클래스는 나중에 실행됨

      Untitled

  • 중요 서브 클래스에서 슈퍼 클래스의 생성자 선택
    • 슈퍼 클래스와 서브 클래스 모두 각각 여러 생성자 작성 가능

    • 서브 클래스 생성자에서 인자를 이용한 super()를 이용하여 슈퍼클래스의 생성자를 하나 무조건 선택을 해야한다. (바로 상속 위의 생성자 호출) ←this() 생성자를 호출하는 것과 유사하다

    • 주의! 선택하지 않으면 컴파일러가 자동으로 슈퍼 클래스의 기본 생성자를 선택한다. 이 때, 기본 생성자가 없을 시 컴파일 오류가 난다. (선택하지 않는다고 슈퍼클래스의 생성자를 호출하지 않는 것이 아님)

      Untitled

    • 주의! 슈퍼클래스에 기본생성자가 아닌 생성자만이 있고, 기본 생성자를 추가 하지 않는다면, 무조건 서브 클래스의 생성자는 기본 생성자가 아닌 슈퍼클래스의 생성자를 super()를 통해 호출해야만 한다. 심지어 객체를 생성하지 않아서 생성자 호출을 하지 않더라도 만들어져 있어야한다.

    • 슈퍼클래스에 기본 생성자가 없어 오류 난 경우

      Untitled

    • 서브 클래스의 생성자에서 super()를 이용한 사례

      Untitled

      super()를 활용한 ColorPoint 클래스의 작성

      class Point{
          private int x,y;
          public Point(int x, int y)
          {
              this.x = x;
              this.y = y;
          }
          public void showPoint(){
              System.out.println("("+x+","+y+")");
          }
      }
      class ColorPoint extends Point{
          private String color;
          public ColorPoint(int x, int y, String color){
              super(x,y);
              this.color = color;
          }
          public void showColorPoint(){
              System.out.print(color);
              showPoint();
          }
      }
      
      public class ColorPointEx extends Point{
          public static void main(String[] args) {
              Point p = new Point(1,2);
              p.showPoint();
      
              ColorPoint cp = new ColorPoint(3,4,"blue");
              cp.showColorPoint();
          }
          public ColorPointEx(){
              super(0,0); // 객체를 생성하지 않더라도 안만들어주면 컴파일 에러가 발생한다. 
          }
      }

      ㄴsuper()를 이용하여 ColorPoint 클래스의 생성자에서 슈퍼 클래스 Point의 생성자를 호출하는 예를 보인다

중요 업/다운캐스팅

  • 업캐스팅:
    • 서브 클래스의 객체는 슈퍼 클래스의 멤버를 모두 가지고 있음

    • 슈퍼 클래스의 객체로 취급할 수 있음

    • 상위 타입 레퍼런스로 하위 타입 객체를 다형성을 위해 가리킬 수 있다.

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/b2c2e868-caa6-4e2e-84b0-594d9057930d/Untitled.png)

      Untitled

      → 서브 클래스 객체를 슈퍼 클래스 타입으로 타입 변환 (자동 형변환)

      Untitled

      주의! 업캐스팅된 레퍼런스는 슈퍼 클래스의 멤버만 접근 가능하다

  • 다운 캐스팅:
    • 슈퍼 클래스 객체를 서브 클래스 타입으로 변환 (강제 형변환)

    • 개발자의 명시적 타입 변환 필요

      Untitled

    • 주의! 강제적 캐스팅이 없으면 무조건 컴파일 에러; 타입만 보고 평가하기 때문이다. 실제로 가리키고 있는 객체와 상관이 없다.

      → 런타임에 오류 발생 가능함

      Untitled

  • 정리
    • 서브 클래스 객체는 슈퍼 클래스로 캐스팅 할 수 있음 ← 업캐스팅

    • 슈퍼클래스 객체는 서브 클래스로 캐스팅 할 수 없음 ←다운캐스팅

      ㄴ 명시적 형변환 필요

      *객체에 변화가 생기는 것이 아니라 reference 변수가 위 아래로 이동하는 느낌

      *자식 타입을 부모 타입으로 가리키는 연습을 하자(업캐스팅) ← 다형성의 구현

      *최상위 타입 클래스를 인자로써 받아오면 상속되는 모든 클래스를 받아올 수 있다!

중요 instanceof 연산자

  • instanceof 연산자와 객체의 타입 판단
    • 업캐스팅 된 레퍼런스로 객체의 타입 판단 어려움

      ㄴ 슈퍼 클래스는 여러 서브 클래스에 상속되기 때문

      Untitled

  • instanceof 연산자
    • 레퍼런스가 가리키는 객체 타입 식별을 위해서 사용한다

    • 객체에 대한 레퍼런스만 사용해야한다 (literal x)

    • ‘객체 레퍼런스가 클래스 타입으로 가리켜도 될까?’라는 의미를 가지고 있음

    • 사용법: 레퍼런스(객체이름) instaceof 타입(클래스이름)

      ㄴ JVM이 실행 중에 판단해서 true/false 불린 값으로 알려준다

    • 중요 true를 return하는 경우 (객체 instanceof 타입):
      - 객체의 실제 클래스 타입
      - 객체의 상위 클래스 타입
      - 객체가 구현한 인터페이스 타입
      - 객체의 상위 클래스가 구현한 인터페이스 타입
      - 추상 클래스 타입
      - 다형성의 실현: 부모 타입으로 선언된 객체가 실제로 자식 타입의 인스턴스인 경우 (업캐스팅 된 경우)

          ```java
          class Animal {}
          class Dog extends Animal {}
          
          Animal myAnimal = new Dog();
          System.out.println(myAnimal instanceof Dog); // true
          ```
          
      - 다형성의 사용2: 인터페이스 타입으로 선언된 객체가 해당 인터페이스를 구현한 클래스의 인스턴스일 경우
          
          ```java
          interface Pet {}
          class Dog implements Pet {}
          
          Pet myPet = new Dog();
          System.out.println(myPet instanceof Dog); // true
          ```
          

      Untitled

주의! 아예 상속구조에 속하지 않는 클래스를 넣으면 컴파일에러! ←루트가 아예 없는 경우를 뜻함

주의! 문자열 literal도 사실 참조에 속한다 값이면서 참조를 나타냄

<전형적 사용법>

if( p instance of Student ){
	Student s = (student)p;
	s.grade = "A";
}

<확장된 사용법>

if( p instanceof Student s ){ //참이면 s에 p 타입 캐스팅(자동형변환)하여 복사
	s.grade = "A";
}

ㄴ s=(Student)p 타입 캐스팅을 자동으로 해주는 것이다.

instanceof 연산자 활용 예시

class Person{}
class Student extends Person{}
class Researcher extends Person{}
class Professor extends Researcher{}

public class InstanceOfEx {
    static void print(Person p) {
        if (p instanceof Person)
            System.out.print("Person ");
        if (p instanceof Student)
            System.out.print("Student ");
        if (p instanceof Researcher)
            System.out.print("Researcher ");
        if (p instanceof Professor)
            System.out.print("Professor ");
        System.out.println();
    }

    public static void main(String[] args) {
        System.out.print("new Student() -> \t");
        print(new Student());
        System.out.print("new Researcher() -> \t");
        print(new Researcher());
        System.out.print("new Professor() -> \t");
        print(new Professor());
    }
}

출력 예시:

new Student() -> Person Student
new Researcher() -> Person Researcher
new Professor() -> Person Researcher Professor

주의! new professoer() 객체는 Person 타입이기도 하고, Rescarcher, Professor 타입이기도 함 → instanceof는 객체 본인의 타입과 상위 타입까지 포함하여서 검사한다는 점!

중요 메소드 오버라이딩

  • 오버라이딩
    • 슈퍼 클래스에 선언된 메소드를 각 서브 클래스들에서 자신만의 내용으로 새로 구현(재정의)하는 기능

      • 슈퍼 클래스 메소드의 이름, 매개변수 타입 및 개수, 리턴 타입 등 모든 것을 동일하게 작성
    • 동적 바인딩 발생
      - 서브 클래스에 오버라이딩 된 메소드가 무조건 실행되는 동적 바인딩

      Untitled

      Untitled

    • Shape 클래스 타입 레퍼런스로 여러 하위 객체의 메소드를 실행가능하게 함

      → 상속을 통해 하나의 인터페이스(같은 이름)에 서로 다른 내용을 구현할 수 있도록 함

    • 재정의가 되어있어야 오버라이딩 된 것! → 객체와 상관없이 무조건 오버라이딩 된 서브클래스의 메소드가 호출됨

    • 서브 클래스라면 서브클래스의 메소드를 실행함 ← 이것도 동적바인딩

    • 슈퍼 클래스라면 jvm이 동적 바인딩을 통해 서브클래스의 메소드와 연결해줌

      메소드 오버라이딩 예시

      class Shape {
          public Shape next;
          public Shape() { next = null; }
          public void draw(){
              System.out.println("Shape");
          }
      }
      class Line extends Shape{
          @Override
          public void draw() {
              System.out.println("Line");
          }
      }
      class Rect extends Shape{
          @Override
          public void draw() {
              System.out.println("Rect");
          }
      }
      class Circle extends Shape{
          @Override
          public void draw() {
              System.out.println("Circle");
          }
      }
      public class MethodOverridingEx {
          static void paint(Shape p){
              p.draw();
          }
      
          public static void main(String[] args) {
              Line line = new Line();
              paint(line);
              paint(new Shape());
              paint(new Line());
              paint(new Rect());
              paint(new Circle());
          }
      }

      출력 예시:

      Line
      Shape
      Line
      Rect
      Circle

      ㄴpaint 함수에서 Shape타입 레퍼런스로 하위 객체들도 매개변수로 받은 다음, p.draw(); 에서 동적 바인딩에 의해서 p가 가리키는 객체 내의 오버라이딩된 draw() 호출!

      < Anti Pattern >

    1. 상위 클래스의 타입으로 객체를 받아주는 이유

      paint(Line l) { l.draw(); }
      paint(Circle c) { c.draw(); } 
      paint(Rect r) { r.draw(); }
    • Line, Circle, Rect의 정의가 우선시 되어야 사용할 수 있는 함수 → 다형성의 의미가 떨어짐..
    1. instanceof 조건문에서 오버라이딩을 사용해야 하는 이유

      paint(Shape p){
      	if(p instanceof Line){
      		Line l = (Line)p;
      		l.draw();
      	}
      }
    • Line의 정의가 필요해지기 때문에 Line에 종속적임

      → 다형성의 의미가 떨어짐..
      
      ㄴ Line에서 오버라이딩을 해주어서  Shape 타입으로 검사 후 오버라이딩한 메소드 실행

      Untitled

    • 최상위 타입만 잘 만들고 상속과 오버라이딩을 통해 다형성 구현

    • 최상위 타입 하나만 있다고 생각하고 상속 변화해도 영향없도록 함

  • 오버라이딩 활용 예제 (연결리스트) Untitled ㄴ 최상위 타입 자체를 레퍼런스 변수로써의 활용 ← C의 포인터로써의 역할을 기능할 수 있다 Untitled

중요 오버라이딩과 super 키워드 활용

  • 오버라이딩과 super 키워드
    • super는 슈퍼 클래스의 멤버를 접근할 때 사용되는 레퍼런스

    • 서브 클래스에서만 사용

    • 슈퍼 클래스의 메소드 호출

    • 컴파일러는 super의 접근을 정적바인딩으로 처리 → 만약 접근할 수 없는 상위 클래스의 메소드를 super로 호출 시, 컴파일 오류가 난다.

    • 오버라이딩 안되는 메소드 → 정적바인딩 (클래스의 메소드)

      오버라이딩 되는 메소드 → 동적바인딩 (객체의 메소드)

    • 상위 클래스의 메소드 실행하고 나면 제어는 다시 super. 을 호출한 위치로 돌아온다.

      Untitled

      ㄴ메소드 뿐만 아니라 필드도 super를 통해 호출할 수 있다.

      ㄴ name으로 이름이 같은 필드를 구분해줄 수 있다.

      Untitled

      Untitled

    • 중요 super와 this의 차이

    • super는 정적으로 서브 클래스보다 상위 클래스 중 정의된 가장 가까운 위치의 멤버를 접근 ( 바로 위의 클래스가 아님, 상위로 찾아가면서 있으면 바로 그것을 호출함 )

    • this는 항상 동적으로 객체의 오버라이딩된 메소드를 실행중에 결정하여 호출함

      ㄴ **주의!** super가 오버라이딩 된 메소드를 가리킬 수도 있지만 그건 정적바인딩에 의한 것, 객체를 판단한 것이 아니다

      메소드 오버라이딩 예시

      class Weapon {
          protected int fire(){
              return 1;
          }
      }
      class Cannon extends Weapon {
          @Override
          protected int fire(){
              return 10;
          }
      }
      public class Game {
          public static void main(String[] args) {
              Weapon weapon;
              weapon = new Weapon();
              System.out.println("기본 무기의 살상 능력은 "+weapon.fire());
              weapon = new Cannon();
              System.out.println("대포의 살상 능력은 "+weapon.fire());
          }
      }

      출력 결과:

      기본 무기의 살상 능력은 1
      대포의 살상 능력은 10

중요 오버라이딩과 오버로딩의 차이

  • 오버라이딩실행 시간 다형성 실현 (상속관계에서 부모클래스의 메소드 정의)→ 동적바인딩을 통해 실행중에 다형성 실현
    • 주의! 규칙:
      • 메소드 이름, 매개변수, 리턴 타입이 같아야한다
      • 접근 제어자는 동일하거나 더 넓은 범위여야 한다
        class A{
        	protected void f(){}
        }
        class B extends A {
        	public void f(){} // public > protected
        	//void f(){} // default < protected
        }
      • 예외는 상위 클래스의 메소드가 던질 수 있는 예외의 하위타입이거나 동일해야한다
      • 메소드는 상속되어야 한다
      • private, final, static 메소드는 오버라이딩 할 수 없다
  • 오버로딩컴파일 타임 다형성 실현
    • 주의! 규칙:
      - 매개변수의 타입, 개수, 순서가 다른 메소드 오버로딩 정의,
      - this를 활용한 위타입의 메소드 호출 생성자 오버로딩 가능
      - 반환 타입과 접근 제어자, 예외처리는 영향을 주지 않는다!

      오버라이딩 되는 메소드 → 동적바인딩(오버라이딩) 처리(객체의 것 실행)

      오버라이딩 되지 않는 메소드 → 정적바인딩(super) 처리(클래스의 것 실행)

Untitled

상속의이해예시코드상속의 이해 예시 코드

상속관계에서 접근 지정자의 적용의 이해를 위한 예시

package aa;

public class AA {
    protected void f() {
        System.out.println("A f");
    }
}
package bb;

import aa.AA;
import cc.CC;

public class BB extends AA{
    /*public void f() {
        System.out.println("B f");
    }*/
    void g() {
        this.f();
        super.f();

        AA obj1=new AA();
        //obj1.f();

        AA obj2=new BB();
        //obj2.f();

        AA obj3 = new CC();
        //obj3.f();

        BB obj4 = new BB();
        obj4.f();

        BB obj5 = new CC();
        obj5.f();

        CC obj6 = new CC();
        obj6.f();
    }

    public static void main(String[] args) {
        BB b = new BB();
        b.g();
    }
}
package cc;

import aa.AA;
import bb.BB;

public class CC extends BB{
    /*public void f() {
        System.out.println("C f");
    }*/
    void g() {
        this.f();
        super.f();

        AA obj1=new AA();
        //obj1.f();

        AA obj2=new BB();
        //obj2.f();

        AA obj3 = new CC();
        //obj3.f();

        BB obj4 = new BB();
        //obj4.f();

        BB obj5 = new CC();
        //obj5.f();

        CC obj6 = new CC();
        obj6.f();
    }

    public static void main(String[] args) {
        CC c = new CC();
        c.g();
    }
}

설명: 다른 패키지에서 상속관계일 때 protected의 호출 범위이다!

BB클래스에서 BB이하의 타입(BB부터 자식으로 판단)은 AA에 접근 가능

CC클래스에서 CC이하의 타입(CC부터 자식으로 판단)은 AA에 접근 가능

→ 그 클래스에서 자식 타입으로써만 부모 타입에 접근이 가능함

→ 자식인지 아닌지 판단 기준은 그 클래스에서 자신과의 비교로 판단한다!

주의! 심지어 AA타입의 객체도 위치가 BB, CC 클래스이므로 호출할 수 없다 (다른 패키지의 protected → 자기 자신의 클래스여도 실행할 수 없음) → 동일 패키지 내의 클래스 혹은 하위 클래스 내에서만 접근할 수 있음

주의! protected 접근제어자는 선언된 위치와 상속 관계에 따른 타입으로 결정된다

상속관계에서 필드와 메소드의 오버라이딩에 대한 이해를 위한 예시

class Parent {
    public int field = 10;

    public void display() {
        System.out.println("Parent field: " + field);
    }
}

class Child extends Parent {
    public int field = 20; // 필드 숨기기

    @Override
    public void display() { // 메서드 오버라이딩
        System.out.println("Child field: " + field);
    }
}

public class Main {
    public static void main(String[] args) {
        Parent p = new Parent();
        Child c = new Child();
        Parent pc = new Child();

        System.out.println("Parent reference:");
        p.display(); // Parent field: 10
        System.out.println("Field: " + p.field); // Field: 10

        System.out.println("\nChild reference:");
        c.display(); // Child field: 20
        System.out.println("Field: " + c.field); // Field: 20

        System.out.println("\nParent reference with Child object:");
        pc.display(); // Child field: 20
        System.out.println("Field: " + pc.field); // Field: 10
    }
}

설명:

  1. Parent 클래스:
    • field 필드는 10으로 초기화됨.
    • display() 메서드는 field 값을 출력.
  2. Child 클래스:
    • field 필드는 20으로 초기화됨. 이는 Parent 클래스의 field 필드를 숨김.
    • display() 메서드는 Parent 클래스의 display() 메서드를 오버라이딩하여 Child 클래스의 field 값을 출력.
  3. 중요 Main 클래스:
    • Parent 객체 p는 Parent 클래스의 field와 display() 메서드를 사용.
    • Child 객체 c는 Child 클래스의 field와 display() 메서드를 사용.
    • Parent 참조 변수 pc는 Child 객체를 참조하지만, field는 Parent 클래스의 것을 사용하며, display() 메서드는 Child 클래스의 것을 사용 (다형성).

결론:

자바에서 필드는 오버라이딩되지 않고 숨기기만 가능합니다. 메서드는 오버라이딩이 가능하여 다형성을 제공하지만, 필드는 상속 관계에서 하위 클래스에서 동일 이름으로 선언되면 상위 클래스의 필드를 숨기는 형태로 동작합니다. → 중요 필드는 레퍼런스 타입에 따라간다!

상속관계에서 super와 this 및 생성자 대한 이해를 위한 복합적 예시

class A{
    public String name;
    void draw(){
        System.out.println(name);
        System.out.println(super.toString());
        System.out.println(this.toString());
    }
}
class B extends A{
    public String toString(){
        return "B";
    }
    B(){
        super.name="A";
    }
}
class C extends B{
    public String name;
    void draw(){
        super.draw();
        System.out.println(super.name);
        System.out.println(name);
        System.out.println(super.toString());
        System.out.println(this.toString());
    }
    C(){
        this.name="C";
    }
}
public class Test1 extends C{
    public static void main(String[] args) {
        Test1 t = new Test1();
        t.draw();
        A at = new Test1();
        at.draw();
    }
}

출력 결과:

A
Test1@3b07d329
B
A
C
B
B
A
Test1@41629346
B
A
C
B
B

설명: 필드 케이스 나눠보기!!!!!!

<메소드와 super>

  1. 클래스 C에서 draw()가 오버라이딩 되었으므로 t.draw();at.draw(); 모두 C타입의 draw()를 실행한다.

  2. 클래스 C의 draw()에 super.draw();에 의해서 클래스 A의 draw()가 실행된다.

    주의! super는 바로 상위 타입만 호출 가능한 것이 아니라 상위 타입 중 가장 가까운 상속관계의 멤버 호출 (필드여도 마찬가지로 작동됨)

  3. 클래스 A의 super.toString()은 클래스 Object의 toString()을 호출한다. this.toString()은 오버라이딩 된 클래스 B의 toString()을 호출한다. → 중요 super는 정적 바인딩이지만, this는 동적 바인딩을 통해서 오버라이딩 된 메소드를 호출한다.

  4. 다시 클래스 C의 draw()로 제어를 return하여서 C를 출력하고, 여기서 super.toString()은 클래스 B의 toString()을 호출한다. this.toString()은 오버로딩 된 클래스 B의 toString()을 호출한다.

    중요 호출하는 위치(상위, 하위)에 따라서 super로 호출되는 메소드는 달라질 수 있지만, this로 호출되는 메소드는 동일하다!

<생성자 및 필드와 super>

  1. C()가 제일 먼저 호출되지만, 바로 B()가 디폴트로 호출된다.
  2. B()에서도 A의 디폴트 생성자가 디폴트로 먼저 호출된다.
  3. 다시 B()로 돌아와 super.name=”A”;를 실행하여 A 클래스의 name에 “A”를 할당한다.
  4. 다시 C()로 돌아와 this.name="C";을 실행하여 C 클래스의 name에 “C”를 할당한다.
  5. 클래스 C의 draw()에서 super.name은 클래스 A의 name을 뜻하고, name은 클래스 C의 name을 뜻한다.
  6. 만약 클래스 B에서 this.name을 사용한다면, 이는 클래스 A의 name이다. → 주의! 메소드와 다르게 필드는 오버라이딩이 되지는 않는다!

중요 추상 메소드와 추상 클래스

  • 추상메소드: 선언되어 있으나 구현되어 있지 않은 메소드, abstract로 선언 Untitled
    • 추상메소드는 서브 클래스에서 오버라이딩하여 구현해야함
  • 추상클래스: 추상메소드를 하나라도 가진 클래스 / 추상 메소드가 없어도 abstract로 선언된 클래스 → 클래스 앞에 반드시 abstract라고 선언해야함 주의! 추상클래스는 객체를 생성하지 못하고 super로도 추상메소드를 실행할 수 없다 ← 컴파일에러 Untitled
  • 추상클래스의 상속 2가지 경우
  1. 추상 클래스의 단순 상속: 추상 클래스를 상속하고 추상 메소드를 구현하지 않으면 추상 클래스 됨 (abstract 붙이기)
  2. 추상 클래스 구현 상속: 서브클래스에서 슈퍼 클래스의 추상 메소드 구현 → 구현해준 서브 클래스는 추상 클래스 아님 (abstract 떼도 됌)

Untitled

주의! 추상 메소드를 구현해주지 않았는데 abstract 안붙어있을 시에 컴파일 에러

Untitled

  • 추상클래스의 용도
    • 추상클래스는 설계와 구현의 분리를 위해 쓰임

    • 오버라이딩에 강제성을 부여할 수 있음

    • 슈퍼클래스에서는 개념을 정의하고 서브 클래스마다 다른 구현이 필요한 메소드는 추상 메소드로 선언한다.

    • 계층적 상속 관계를 갖는 클래스 구조를 만든다

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/fdd14744-5076-40c9-8d16-49d3f0cfc32d/Untitled.png)

      추상 클래스의 구현 예시

      abstract class Calculator {
          public abstract int add(int a, int b);
          public abstract int subtract(int a, int b);
          public abstract double average(int[] a);
      }
      
      public class GoodCalc extends Calculator{
          @Override
          public int add(int a, int b){
              return a+b;
          }
          @Override
          public int subtract(int a, int b){
              return a - b;
          }
          @Override
          public double average(int[] a){
              double sum = 0;
              for (int i = 0; i < a.length; i++)
                  sum += a[i];
              return sum/a.length;
          }
      
          public static void main(String[] args) {
              GoodCalc c = new GoodCalc();
              System.out.println(c.add(2,3));
              System.out.println(c.subtract(2,3));
              System.out.println(c.average(new int [] {2,3,4}));
          }
      }
      

      출력 결과:

      5

      -1

      3.0

중요 인터페이스

  • 인터페이스: 인터페이스는 스펙을 주어서 클래스들이 그 기능을 다르게 구현할 수 있도록 하는 클래스의 규격선언이다. Untitled
    • 클래스가 구현해야 할 메소드들이 선언되는 추상형

    • interface 키워드로 선언

    • 인터페이스의 상속(구현)은 implements 키워드를 사용한다

    • 주의! 멤버 변수(필드)는 선언 불가, 추상클래스에서는 static이든 아니든 가능한 반면에 인터페이스에서는 상수만 가능하다

      Untitled

    • 상수필드 / 추상메소드 / 디폴트 메소드 / private 메소드 / static 메소드만을 가진다.
      - 상수필드: public만 허용, public static final 생략가능
      - 추상메소드: public abstract 생략가능
      - default 메소드: 인터페이스에 코드가 작성된 메소드
      - 인터페이스를 구현하는 클래스에 자동 상속
      - public 접근 지정만 허용, 생략 가능
      - private 메소드: 인터페이스 내에 메소드 코드가 작성되어야함
      - 인터페이스 내에 있는 다른 메소드에 의해서만 호출 가능
      - static 메소드: public, private 모두 지정 가능, 생략하면 public

      Untitled

    • 인터페이스의 목적은 다중상속을 위한 것

    • 인터페이스의 객체 생성 불가 (추상 클래스와 마찬가지)

      Untitled

    • 주의! 인터페이스 타입의 레퍼런스 변수만 선언 가능 → 슈퍼 클래스의 레퍼런스 변수처럼 인터페이스를 구현한 객체를 받을 수 있음

      Untitled

  • 중요 인터페이스 구현: 인터페이스를 구현하려면 인터페이스를 상속받는 클래스는 인터페이스의 모든 추상 메소드를 반드시 구현해야함, 추상클래스는 전부 구현 안해도 됨 Untitled 인터페이스 구현 예시
    interface PhoneInterface{
        int TIMEOUT = 10000;
        void sendCall();
        void receiveCall();
        default void printLogo(){
            System.out.println("** PHONE **");
        }
    }
    class SamsungPhone implements PhoneInterface{
        @Override
        public void sendCall(){
            System.out.println("따라라랑");
        }
        @Override
        public void receiveCall(){
            System.out.println("전화가 왔습니다.");
        }
        public void flash() {
            System.out.println("전화기에 불이 켜졌습니다.");
        }
    }
    public class InterfaceEx {
        public static void main(String[] args) {
            SamsungPhone phone = new SamsungPhone();
            phone.printLogo();
            phone.sendCall();
            phone.receiveCall();
            phone.flash();
        }
    }
    출력 결과: PHONE
    따라라랑
    전화가 왔습니다.
    전화기에 불이 켜졌습니다. 설명: 인터페이스의 추상 메소드(sendCall(), receiveCall())를 모두 구현하고 필요한 메소드(flash())는 추가 작성하였다.
  • 인터페이스 상속 중요 다른 인터페이스 상속 가능하고 인터페이스는 다중 상속이 가능하다
    • 인터페이스끼리의 상속은 클래스처럼 extends로 상속을 한다 ㄴ 상위 인터페이스에 없는 추상 메소드를 추가해준다! Untitled
  • 다중 인터페이스 구현
    • 다중 인터페이스 상속(구현)

      Untitled

    • 클래스는 하나 이상의 인터페이스를 구현할 수 있음

    • 주의! 클래스에서 인터페이스의 메소드를 구현할 때 public을 생략하면 오류 발생

      Untitled

인터페이스의 상속과 다중 인터페이스의 구현 예시

interface PhoneInterface{
    int TIMEOUT = 10000;
    void sendCall();
    void receiveCall();
    default void printLogo(){
        System.out.println("** PHONE **");
    }
}
interface MobilePhoneInterface extends PhoneInterface {
    void sendSMS();
    void receiveSMS();
}
interface MP3Interface {
    public void play();
    public void stop();
}
class PDA{
    public int calcualte(int x, int y){
        return x+y;
    }
}
// SmartPhone 클래스는 PDA를 상속받고
// MobilePhoneInterface, MP3Interface 인터페이스에 선언된 추상 메소드를 전부 구현한다.
class SmartPhone extends PDA implements MobilePhoneInterface, MP3Interface{
    //MobilePhoneInterface의 추상메소드 구현
    @Override
    public void sendCall(){
        System.out.println("따라라랑");
    }
    @Override
    public void receiveCall(){
        System.out.println("전화가 왔습니다.");
    }
    @Override
    public void sendSMS() {
        System.out.println("문자 보내요~");
    }
    @Override
    public void receiveSMS(){
        System.out.println("문자 왔당께");
    }
    //MP3Interface의 추상 메소드 구현
    @Override
    public void play(){
        System.out.println("음악 틀어요");
    }
    @Override
    public void stop() {
        System.out.println("음악 꺼줘요");
    }
    public void flash() {
        System.out.println("전화기에 불이 켜졌습니다.");
    }
}
public class InterfaceEx {
    public static void main(String[] args) {
        SmartPhone phone = new SmartPhone();
        phone.printLogo();
        phone.sendCall();
        phone.receiveCall();
        phone.play();
        System.out.println("3과 5를 더하면 "+phone.calcualte(3,5));
        phone.flash();
    }
}

출력 결과:

PHONE
따라라랑
전화가 왔습니다.
음악 틀어요
3과 5를 더하면 8
전화기에 불이 켜졌습니다.

중요 추상 클래스와 인터페이스의 차이

[ 추상 클래스와 인터페이스의 차이 ]

  • 추상 클래스:
    • 클래스 계층 구조를 정의하고 일부 메서드의 구현을 공유하거나 기본 구현을 제공하려고 할 때 사용됩니다.
    • 클래스이기 때문에 상태(필드)와 행동(메서드)을 모두 가질 수 있습니다.
  • 인터페이스:
    • 클래스가 수행해야 할 행동을 명시적으로 정의합니다.

    • 메서드 서명(시그니처)만 정의하며, 기본적으로 상태(필드)를 가지지 않습니다. 자바 8부터는 디폴트 메서드와 정적 메서드를 가질 수 있습니다.

      <키워드>

    • 추상 클래스: abstract 키워드로 정의됩니다.

      java코드 복사
      abstract class Animal {
          abstract void makeSound();
      }
      
    • 인터페이스: interface 키워드로 정의됩니다.

      ```java
      java코드 복사
      interface Animal {
          void makeSound();
      }
      
      ```

      <메소드 구현>

    • 추상 클래스:

      • 일부 메서드는 구현할 수 있고, 일부는 추상 메서드로 남길 수 있습니다.

      • 추상 메서드는 하위 클래스에서 반드시 구현해야 합니다.

        java코드 복사
        abstract class Animal {
            abstract void makeSound(); // 추상 메서드
        
            void sleep() {
                System.out.println("Sleeping...");
            } // 구현된 메서드
        }
        
    • 인터페이스:
      - 기본적으로 메서드는 구현이 없으며, 모든 메서드는 추상 메서드로 간주됩니다.
      - 자바 8 이후부터 디폴트 메서드와 정적 메서드를 가질 수 있습니다.

      ```java
      java코드 복사
      interface Animal {
          void makeSound(); // 추상 메서드
      
          default void sleep() {
              System.out.println("Sleeping...");
          } // 디폴트 메서드
      
          static void eat() {
              System.out.println("Eating...");
          } // 정적 메서드
      }
      
      ```

      주의! <필드>

    • 추상 클래스: 인스턴스 변수와 클래스 변수를 가질 수 있습니다.

      java코드 복사
      abstract class Animal {
          String name; // 인스턴스 변수
          static int count; // 클래스 변수
      }
      
    • 인터페이스: 기본적으로 상수(static final)만 가질 수 있습니다.

      ```java
      java코드 복사
      interface Animal {
          int AGE = 5; // 암묵적으로 static final
      }
      
      ```

      <다중상속>

    • 추상 클래스: 단일 상속만 가능합니다.

      java코드 복사
      class Dog extends Animal { // 하나의 부모 클래스만 상속 가능
      }
      
    • 인터페이스: 다중 구현이 가능합니다.

      ```java
      java코드 복사
      class Dog implements Animal, Pet { // 여러 인터페이스를 구현 가능
      }
      
      ```

      사용 예시

    • 추상 클래스: 공통된 코드가 있고 상태를 공유해야 할 때 사용합니다.

      java코드 복사
      abstract class Animal {
          String name;
          abstract void makeSound();
          void sleep() {
              System.out.println("Sleeping...");
          }
      }
      
      class Dog extends Animal {
          void makeSound() {
              System.out.println("Woof");
          }
      }
      
    • 인터페이스: 여러 클래스가 공통의 행동을 구현해야 할 때 사용합니다.

      ```java
      java코드 복사
      interface Animal {
          void makeSound();
      }
      
      interface Pet {
          void play();
      }
      
      class Dog implements Animal, Pet {
          public void makeSound() {
              System.out.println("Woof");
          }
      
          public void play() {
              System.out.println("Playing...");
          }
      }
      
      ```

      <접근 제어자>

    • 추상 클래스: 모든 접근 제어자(public, protected, private)를 사용할 수 있습니다.

      java코드 복사
      abstract class Animal {
          private String name; // private 필드
          protected abstract void makeSound(); // protected 메서드
      }
      
    • 인터페이스: 자바 9 이전에는 모든 메서드가 public이며, public을 명시적으로 선언할 필요가 있습니다. 자바 9 이후부터는 private 메서드도 허용됩니다.

      ```java
      java코드 복사
      interface Animal {
          void makeSound(); // 암묵적으로 public
          private void breathe() { // 자바 9 이후부터 사용 가능
              System.out.println("Breathing...");
          }
      }
      
      ```

      결론

    • 추상 클래스는 상태와 행동을 모두 가질 수 있고, 단일 상속만 가능합니다. 공통된 코드를 공유하려는 경우에 사용됩니다.

    • 인터페이스는 다중 구현이 가능하며, 클래스가 특정 행동을 구현하도록 강제하는 경우에 사용됩니다. 자바 8 이후부터는 디폴트 메서드와 정적 메서드를 통해 약간의 구현도 제공할 수 있습니다.

      두 개념은 설계 목적에 따라 적절하게 사용되어야 하며, 서로 보완적인 역할을 합니다.

      유사점:

    • 객체를 생성할 수 없고, 상속을 위한 슈퍼 클래스로만 사용

      주의! 레퍼런스는 생성가능 → 서브클래스의 객체를 가리킴

    • 클래스의 다형성을 실현하기 위한 목적

      차이점:

      Untitled

인터페이스추가강의인터페이스 추가 강의

  • Java 8 Interface Changes Untitled
    • 자바 8에서는 상수와 추상 메소드 이외에 default 메소드static 메소드가 추가되었다.
      - 간단한 규칙을 알아보자면 상위 인터페이스에서 이름 충돌이 발생한다면 하위 클래스에서 오버라이딩을 통해 충돌을 해결한다
      - 디폴드 메소드의 이름이 같으면 인터페이스에서 못내려온다
      - 인터페이스의 추상 메소드 접근은 무조건 타입이름과 메소드 이름으로 접근한다.

          → 자세한 예시는 아래에서 살펴보자
          

      Untitled

    • 디폴트 메소드: 추상메소드가 아닌 구현되어 상속되는 디폴트 메소드; 인터페이스에 새로운 요소의 추가가 필요할 때, 인터페이스에 디폴트 메소드를 추가하여서 인터페이스를 구현하는 클래스마다 전부 구현해 줄 필요가 없어짐


    • 디폴트 메소드의 상속의 효과

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/bde5294f-102f-4c52-8115-781376eb3a10/9430962c-b13a-4373-900c-b785019cd4e7.png)
      
      - 디폴트 메소드가 상속의 효과를 내면서 컴파일 에러는 내지 않고 있다.

    • 디폴트 메소드의 오버라이딩

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/64711542-e989-4315-a75a-92341a8c9dd5/2291b55a-78f2-4a81-bb5e-58f1ae881b41.png)
      
      - 디폴트 메소드 또한 구현이 맘에 들지 않을 시에 클래스 부분에서 오버라이딩이 가능하다!

    • 중요 인터페이스의 super 사용방법 (디폴트 메소드의 정적 호출)
      - 클래스의 상속에서 상위 클래스 메소드를 호출할때 super.으로 호출한 것처럼 인터페이스의 구현에서 구현한 인터페이스의 디폴트 메소드를 호출할 수 있다
      - (인터페이스 이름).super.(메소드이름)(); 의 형태로 호출한다. → 주의! 인터페이스의 이름 꼭 앞에 붙여주기! 인터페이스는 다중 상속이 가능하기 때문에 어떤 인터페이스의 메소드를 호출하는 것인지 이름을 통해서 알려주어야한다!

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/a92712e7-9ab5-468f-9a70-6e880c8b4ac9/be00e435-57c0-4ebd-866f-5b8dfba87cdb.png)
      
      - **주의!** 인터페이스에서 super의 사용은 바로 상위 타입이 아니면 컴파일 에러가 난다
      - 주로 디폴트 메소드의 오버라이딩에서 호출하는 경우이다.

    • 인터페이스의 상속과 구현
      - 인터페이스 내부의 추상 메소드는 어짜피 선언부가 아닌 구현부이기 때문에 상속 관계끼리 겹쳐도 상관이 없다.

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/65ff168b-35e6-4a00-b405-8d082af05087/4c9ece97-9afc-4bcd-a23a-a0fc89cfc591.png)
      
      - 상속관계이기 때문에 obj, obj2, obj3는 오버라이딩된 method()를 실행하고, 디폴트 메소드인 newDefaultMethod()를 실행한다.

    • 중요 인터페이스끼리의 상속에서의 오버라이딩

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/90a7d11f-3a9f-423e-baf4-96539b41e104/7b541d74-7c1d-43d8-b4cc-b30da79acf79.png)
      
      - 인터페이스의 상속관계에서 오버라이딩이 가능하다
      - **주의!** 단 인터페이스의 상속관계에서 super를 사용하면 상속된 것의 direct 부모의 메소드만 호출 가능하다

      <Default Method의 메소드 충돌>

    • 상속관계는 다중 상속을 지원하지 않았기 떄문에 메소드 이름 충돌의 가능성이 없었음, 그러나 인터페이스의 사용으로 다양한 경우에서 메소드가 충돌함


    • 인터페이스의 디폴트 메소드 VS 슈퍼 클래스의 메소드 이름 충돌

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/87f283d4-7c8d-4542-a22f-1005c45d41bc/7ee5b069-d42d-47c8-b1f8-6dcbb8bd7ff8.png)
      
      - **주의!** 클래스의 함수를 우선시 한다!
          - 상위 클래스는 객체에 포함되고 그 다음 인터페이스의 메소드를 오버라이드 하는 효과가 나기 때문이다. → 클래스 레퍼런스로 가리키든, 인터페이스 레퍼런스로 가리키든 동일함

    • 인터페이스의 디폴트 메소드 VS 인터페이스’의 추상 메소드 이름 충돌
      - 인터페이스의 추상메소드를 다른 인터페이스의 디폴트 메소드로 구현해줄 수 없음
      - 추상 메소드는 구현하는 클래스에서만 구현해야한다!

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/ca1a079d-84a4-4df0-8a3f-b4d24794352b/8d5deb73-f74a-4b5a-ba80-b05cf17d2f7a.png)
      
                                                        → 해결 방법 →
      
      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/91949283-a1ff-41c3-89fb-21ce7a5c915c/06241877-9526-4a90-9cec-8743b0261a16.png)
      
      - ***중요*** 위의 케이스의 경우에는 Cls 클래스에서 newDefaultMethod()를 구현하여서 Interface 인터페이스에서의 newDefaultMethod()에서는 오버라이딩의 효과를, AnotherInterface 인터페이스에서의 newDefaultMethod()에서는 추상 메소드의 구현의 효과를 주면 문제가 없다!

    • 인터페이스의 디폴트 메소드 VS 인터페이스’의 디폴트 메소드 이름 충돌
      - 인터페이스들의 디폴트 메소드의 중복으로 인해서 컴파일 에러

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/bf65eb35-3a93-4aca-9318-71a80568901e/e4a9576f-f0c1-47f0-9594-18313b0e32b0.png)
      
                                                      → 해결 방법 →
      
      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/45187f65-d9db-4820-a276-10fe3f6809df/6e4d8c81-c0a1-44b4-9a38-3a71481c55dc.png)
      
      - 구현하는 클래스 부분에서 오버라이드로 정의해준다. Interface 인터페이스와 AnotherInterface 인터페이스의 newDefaultMethod()부분 모두 오버라이딩 하는 효과를 가진다.

    • 여러 인터페이스의 이름이 같은 디폴트 메소드 호출 방식
      1. 클래스에서 인터페이스를 각각 implements 후 클래스의 메소드에서 오버라이드와 super를 통한 메소드 접근

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/65b23782-1af2-4d16-9430-0b68fca81dab/e31a590b-43bf-46c5-88e5-43405b8af4fb.png)
      
      1. 인터페이스끼리 상속한 이후 클래스에서 하위 인터페이스 implements 후, 인터페이스의 메소드에서 오버라이드와 super를 통한 메소드 접근
      
      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/a891d201-259f-41ad-966b-f28afec0bffb/b1791d64-b062-4ff9-9f95-6121a8186209.png)

    • 인터페이스의 디폴트 메소드 VS 추상 클래스의 추상 메소드 이름 충돌
      - 인터페이스의 디폴트 메소드들끼리의 충돌과 유사하다

          → 마찬가지로 클래스에서 오버라이드 해준다. Interface의 newDefaultMethod()와 AbstractClass의 newDefaultMethod()를 동시에 오버라이드 하는 것이다.
          

      Untitled


      Untitled

    • 클래스에서와 마찬가지로 정적 바인딩을 표현함, 구현부가 있어야함

    • 주의! 무조건 인터페이스의 이름만으로 메소드를 호출할 수 있음 → 객체 이름으로 호출할 수 없게함

    • 추상 메소드에 static 붙일 수 없음

  • Java 9 Interface Changes Untitled
    • 자바 9에서는 Private 메소드가 추가되었다.

    • 목적: 인터페이스 내부의 서브루틴을 포현하고 인터페이스 내부에서만 사용하기 위해 private 사용

    • 특징:
      - 추상 메소드, 디폴트 메소드에는 private 붙이지 않는다
      - private 함수꼴이거나 private static 함수꼴로써 존재한다

      ![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/d48a8b3a-0902-461a-8e65-1e3bd3ed9699/e8433bd2-0874-42f4-b1ae-8442c5290b69/8b6639e9-86d9-4e21-ae2c-6caca104d011.png)
      
      - ***중요*** private 메소드 내부에는 private 메소드, 디폴트 메소드, 추상 메소드의 호출이 가능하다; 이미 구현부 가지는 것이 보장되기 때문이다 → 클래스에서 override된 method()를 호출한다!

      Untitled


    • 목적: 인터페이스 내부의 static 함수의 서브루틴을 표현하고 인터페이스 내부에서만 사용하기 위해 private static사용

    • 특징:
      - private static안에서는 static 메소드와 private static 메소드만 호출 O
      - Static 메소드 내에서 앞에 this가 생략된 non-static 메소드 호출 X

      Untitled

원본 노션 링크

https://believed-poinsettia-f0f.notion.site/5-eccce4bd7273448da16ec923548b691e?pvs=4

0개의 댓글