JAVA_4

moonazn·2022년 4월 12일
0

Java

목록 보기
5/5

Week 4.

-상속(Inheritance): 클래스 사이의 상속,, 객체 사이의 상속이 Xx!

>슈퍼클래스를 확장한다는 개념

-new에 의해 서브클래스의 객체가 생성될 때 -> 슈퍼클래스의 생성자와 서브클래스 생성자 모두 실행됨

  • 호출순서 :
  1. 서브클래스의 생성자 먼저 호출
  2. 실행 전 서브클래스의 생성자가 슈퍼클래스의 생성자 호출
  • 실행순서 :
  1. 슈퍼클래스의 생성자가 먼저 실행
  2. 서브 클래스의 생성자 실행

호출과 실행은 다르다!!

-상속관계에서 슈퍼클래스와 서브클래스 각각 여러 생성자 작성 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

  1. 추상 메소드가 하나도 없지만 abstract로 선언된 클래스

-추상 클래스의 상속 2가지 경우
1. 추상 클래스의 단순 상속
: 추상 클래스를 상속받아, 추상 메소드를 구현하지 않으면 추상 클래스가 됨
(>객체 생성하면 Xx,,)
(객체를 생성할 수 있는 실제적인 클래스가 되기 위해서는 추상 클래스를 전-부 구현해주어야 함!)
-> 서브클래스도 abstract로 선언해야 O!!

ex) ```
abstract class Shape {
	abstract public void draw(); 	//추상 메소드
}
abstract class Line extends Shape {
	//추상 클래스. draw()를 상속받았기 때문에,,
}
```

-> 추상 클래스 Shape를 상속받는 Line 클래스에서 추상 메소드인 draw()를 오버라이딩하지 않으면 자동으로 추상 클래스가 됨,,
	>> Line은 abstract 키워드를 사용하여 추상클래스임을 명시해야 한다.
  1. 추상 클래스의 구현 상속
    : 서브 클래스에서 슈퍼 클래스의 "추상 메소드" 구현(오버라이딩)
    -> 추상 메소드가 아닌 일반 메소드를 오버라이딩할 필요Xx
    (서브 클래스는 추상 클래스가 X)

-추상 클래스의 용도: 설계・구현 분리(슈퍼클래스에서는 개념 정의,, 서브클래스마다 다른 구현이 필요한 메소드는 추상 메소드로 선언), 계층적 상속 관계를 갖는 클래스 구조를 만들 때

-정해진 규격 -> 인터페이스,,
-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,,

profile
개발 공뷰

0개의 댓글