-상속(Inheritance): 클래스 사이의 상속,, 객체 사이의 상속이 Xx!
>슈퍼클래스를 확장한다는 개념
-new에 의해 서브클래스의 객체가 생성될 때 -> 슈퍼클래스의 생성자와 서브클래스 생성자 모두 실행됨
호출과 실행은 다르다!!
-상속관계에서 슈퍼클래스와 서브클래스 각각 여러 생성자 작성 O
-> 서브클래스에서 슈퍼클래스의 생성자 선택 방법
1. 기본생성자 자동 선택
(서브클래스에서 슈퍼클래스의 생성자를 선택하지 않는 경우, 자동으로 컴파일러가 슈퍼클래스의 기본 생성자 선택)
2. 서브클래스에서 super() 이용 > 슈퍼클래스의 생성자 선택
(서브클래스의 생성자에서 슈퍼클래스의 생성자를 명시적으로 선택하는 것이 원칙)
이때 기본 생성자도 꼭 넣어주기!!
-super() : 서브클래스에서 명시적으로 슈퍼클래스의 생성자 선택 호출.
>괄호 안의 인자를 이용 -> 슈퍼클래스의 적당한 생성자 호출
>❗️**반드시 서브클래스 생성자 코드의 제일 첫라인에 와야 함!**
ex)```
class A {
public A() {} //기본 생성자
public A(int x) {} //매개변수 생성자
}
class B extends A {
public B() {} //슈퍼클래스 A의 기본생성자 자동 선택
public B(int x) {
super(x); //슈퍼클래스 A의 매개변수 생성자를 명시적으로 선택
...
}
}
```
서브 클래스의 객체는 슈퍼 클래스의 멤버를 모두 가지고 있음
-> 슈퍼클래스의 객체로도 취급 O
-업캐스팅(upcasting) : 서브클래스에서 생성한 객체를 슈퍼클래스 타입으로 변환! > 서브클래스의 객체에 대한 레퍼런스를 슈퍼클래스 타입으로 변환.
->> 슈퍼클래스의 레퍼런스로 서브클래스의 객체를 가리키게 함
ex) ```
class Person { ... }
class Student extends Person { ... }
//main()
Student s = new Student();
Person p = s; //업캐스팅, 자동 타입 변환
//s, p > 레퍼런스 변수
**//업캐스팅된 레퍼런스 변수 p는 Student 객체를 가리킴
//‼️But! 레퍼런스 p로는 객체 내의 슈퍼클래스(Perosn) 멤버만 접근 가능하다.**
```
사실 동일한 객체를 가리키는 것 같이 되어있지만,, 전체를 가리킬건지, 슈퍼클래스만 가리킬 것인지의 문제!
-업캐스팅은 명시적 타입 변환을 하지 않아도 O!
-> Student 객체는 Person 타입의 정보를 모두 갖고있기 때문,,,
ex)```
Person p;
Student s = new Student("~");
p = (Person) s; //명시적 타입 변환
// p = s; 이렇게도 가능
```
-다운캐스팅(downcasting) : 슈퍼클래스 객체를 서브클래스 타입으로 변환
-> 개발자의 명시적 타입 변환 필요!
-> 다운캐스팅을 위해서는 업캐스팅이 선행되어야 한다.
-업캐스팅된 레퍼런스로 객체의 타입 판단 어려움,,
>슈퍼클래스는 여러 서브클래스에 상속,,
따라서 업캐스팅된 레퍼런스를 가지고 어느 서브클래스로부터 업캐스팅되었는지 판단 불가.
-instanceof 연산자 : 레퍼런스가 가리키는 객체의 타입 식별을 위해 사용, 레퍼런스가 가리키는 객체가 어떤 클래스 타입인지 구분
> 이항연산자 : 객체레퍼런스 instanceof 클래스명
> 연산결과 : true / false의 boolean값.
-레퍼런스가 가리키는 객체가 해당 클래스 타입의 객체 > true
-아니면 > false
> 객체에 대한 레퍼런스만 사용. (값X)
단, 문자열은 객체로 취급!
if( 3 instanceof int ) //error
if( "java" instanceof String ) //true
ex) ```
//상속 관계
class Person {}
class Student extends Person {}
class Researcher extends Person {}
class Professor extends Researcher {}
//4가지의 경우가 가능
Person p = new Person();
Person p = new Student(); //업캐스팅
Person p = new Researcher(); //업캐스팅
Person p = new Professor(); //업캐스팅
void print(Person person){
...
//person이 가리키는 객체가 Person/Student/Researcher/Professor,, 중 어떤 타입인지 알 수 X
}
print(p);
//print() 메소드에서 person이 어떤 객체를 가리키는지 알 수 X
Person jee = new Stuent();
Person kim = new Professor();
Person lee = new Researcher();
if( jee instanceof Person ) //true
if( jee instanceof Student ) //true
if( kim instanceof Student ) //false
if( kim instanceof Professor ) //true
if( kim instanceof Researcher ) //true, Professor 객체는 Researcher 타입이기도 하므로..
if( lee instanceof Professor ) //false
```
부모클래스로 가면 업캐스팅,,
내려가면 다운캐스팅,,class A {} class B extends A {} // A a = new B(); //B -> A는 올라가는거니까,, 업캐스팅 B b = (B) a; //A -> B는 내려가는거니까,, 다운캐스팅 ```
-메소드 오버라이딩 (Method Overriding) : 슈퍼클래스의 메소드를 서브클래스에서 재정의.
> ‼️**슈퍼클래스의 메소드 이름, 매개변수 타입 및 개수, 리턴 타입들을 모두 동일하게 작성!**
>> 원형과 다르면 오버로딩으로 간주될 수도 O
(그대로 가지고 오되, 사용방법만 조금 바
꾸겠다 ~~)
>이때, 완전 똑같게 생긴 메소드가 2개..
-> 메소드를 호출하면 _서브클래스에서 재정의된 메소드에 우선순위가 O!_
>동적 바인딩 발생 (서브클래스에 오버라이딩된 메소드가 무조건 실행되는 동적 바인딩),, (오버라이딩 메소드가 항상 호출!)
정적 바인딩 vs 동적 바인딩
-정적 바인딩(Static Binding) : 컴파일Compile 시간에 성격이 결정됨, 변수의 타입이 슈퍼클래스이니 슈퍼클래스의 메소드를 호출한다.
-동적 바인딩(Dynamic Binding) : 다형성을 사용하여 메소드를 호출할 때 발생,, 실행 시간Runtime, 즉 파일을 실행하는 시점에 성격이 결정됨, 실제 참조하는 객체는 서브클래스이니 서브클래스의 메소드를 호출한다.
(동적 바인딩은 Runtime 시점에 해당 메소드를 구현하고 있는 실제 객체 타입을 기준으로 찾아가서 실행될 함수를 호출한다.)
ex) ```
class Shape { //슈퍼클래스
**public void draw (){**
System.out.println("Shape");
}
}
class Line extends Shape { //서브클래스
**public void draw (){** //오버라이딩
System.out.println("Line");
}
}
```
상속을 통해 '하나의 인터페이스(같은 이름)에 서로 다른 내용 구현'이라는 객체 지향의 다형성 실현.
++ 오버라이딩 > 실행시간 다형성 실현 / 오버로딩 > 컴파일 타임 다형성 실현
슈퍼클래스 메소드의 접근지정자보다 접근 범위를 좁혀 오버라이딩 할 수 X
(접근지정자 범위 : public > protected > default > private)
static, private, final로 선언된 메소드는 서브클래스에서 오버라이딩할 수 X
>static : 기본적으로 객체 생성과 관련 X -> 상속과 관련 X
>private : 아예 상속이 X (서브클래스가 사용할 수 없는데 변경? 또한 불가능,,)
>final :
class의 final은 상속 X.
변수의 final은 상수처리.
메소드의 final은 오버라이딩 X.
-super : 슈퍼클래스의 멤버를 접근할 때 사용되는 레퍼런스.
>서브클래스에서만 사용(상위클래스를 명시적으로 알아야만 사용O)
>슈퍼클래스의 메소드 호출
>컴파일러 -> super의 접근을 _정적 바인딩_으로 처리.
ex) ```
class Shape {
🔅protected String name;
public void paint() {
draw();
}
⭕️public void draw() {
System.out.println(name);
}
}
public class Circle extends Shape {
protected String name;
//Override
public void draw() {
name = "Circle";
🔅super.name = "Shape";
⭕️super.draw(); //super 키워드로 부모쪽 멤버에 접근!
System.out.println(name);
}
public static void main(String [] args) {
Shape b = new Circle();
b.paint();
}
}
```
this & this() > 생성자를 가리킴
super & super() > 객체, 멤버를 가리킴
-추상 메소드(abstract method): 선언된어 있으나 구현되어있지 않은 메소드, abstract로 선언
public abstract String getName();
public abstract void setName(String s);
>리턴타입은 이걸로, 이름이랑 파라미터는 이걸로,, but! 동작은 정의 아직 X,, 너가 정의해,,!(나를 상속받는 애가 구체적으로 알아서 구현하세요 ~)> 동작 정의는 서브클래스에게 위임,,
추상 메소드는 서브클래스에서 오버라이딩하여 구현해야함.
-추상 클래스의 2종류 :
1. 추상 메소드를 하나라도 가진 클래스
(클래스 앞에 반드시 abstract라고 선언해야 함)
ex) ```
**abstract** class Shape { //추상 클래스 선언
public Shape() {}
public void paint(){draw();}
**abstract** public void draw();
//추상 메소드
}
```
>꼭 서브클래스에서 추상 메소드를 구현해준 후에 객체를 생성해야함
추상 클래스는 객체를 생성할 수 X
-추상 클래스의 상속 2가지 경우
1. 추상 클래스의 단순 상속
: 추상 클래스를 상속받아, 추상 메소드를 구현하지 않으면 추상 클래스가 됨
(>객체 생성하면 Xx,,)
(객체를 생성할 수 있는 실제적인 클래스가 되기 위해서는 추상 클래스를 전-부 구현해주어야 함!)
-> 서브클래스도 abstract로 선언해야 O!!
ex) ```
abstract class Shape {
abstract public void draw(); //추상 메소드
}
abstract class Line extends Shape {
//추상 클래스. draw()를 상속받았기 때문에,,
}
```
-> 추상 클래스 Shape를 상속받는 Line 클래스에서 추상 메소드인 draw()를 오버라이딩하지 않으면 자동으로 추상 클래스가 됨,,
>> Line은 abstract 키워드를 사용하여 추상클래스임을 명시해야 한다.
-추상 클래스의 용도: 설계・구현 분리(슈퍼클래스에서는 개념 정의,, 서브클래스마다 다른 구현이 필요한 메소드는 추상 메소드로 선언), 계층적 상속 관계를 갖는 클래스 구조를 만들 때
-정해진 규격 -> 인터페이스,,
-Java의 인터페이스 : 클래스가 구현해야 할 메소드들이 선언되는 추상형
->선언: interface 키워드
ex) public interface SerialDriver{
...
}
인터페이스에는 필드(멤버 변수) 선언 불가!
메소드들 선언만 가능.
<인터페이스 구성요소들의 특징>
상수: public만 허용,, public static final 생략
추상 메소드: public abstract 생략O
default 메소드: 인터페이스에 코드가 작성된 메소드,,
>인터페이스를 구현하는 클래스에 자동 상속.
public 접근지정만 허용(생략O)
private 메소드: 인터페이스 내에 메소드 코드가 작성되어야 O
(인터페이스 내에 있는 다른 메소드에 의해서만 호출 O)
static 메소드: public, private 모두 지정O (생략 시 public)
-인터페이스의 특징
>객체 생성 불가
>인터페이스 타입의 레퍼런스 변수 선언O
>인터페이스를 상속받는 클래스는 인터페이스의 모든 추상 메소드 반드시 구현
>다른 인터페이스 상속 가능
>인터페이스의 다중 상속 O
(-> 다중 상속을 해야하면 인터페이스로 만들어버리기~~)
-인터페이스의 추상 메소드를 모두 구현한 클래스 작성
-> implements 키워드
->여러개의 인터페이스 동시 구현 O
-인터페이스 상속 => 인터페이스 확장!
(extends 키워드 이용)
다중 인터페이스 상속도 O!!
-인터페이스 : 클래스들의 그 기능을 서로 다르게 구현할 수 있도록 하는 클래스의 규격 선언.
클래스의 다형성을 실현하는 도구,,
->다중 인터페이스 구현
-추상 클래스 vs 인터페이스
both > 객체 생성 불가, 상속을 위한 슈퍼 클래스로만 사용, 클래스의 다형성을 실현하기 위한 목적
다중상속 필요하면? 인터페이스
추상 메소드면,, 추상 클래스로 굳이 만들 필요는 Xx,,