객체2(야마)
- 상속(inheritance)
- 1 상속의 정의와 장점
조상 클래스 부모(parent)클래스, 상위(super)클래스, 기반(base)클래스
자손 클래스 자식 (child)클래스. 하위 (sub)클래스, 파생된 (derived) 클래스
만일 Parent클래스에 age라는 정수형 변수를 멤버변수로 추가하면, 자손 클래스는 조상
의 멤버를 모두 상속받기 때문에, Child클래스는 자동적으로 age라는 멤버변수가 추가된
것과 같은 효과를 얻는다.
class Parent {
int age;
}
class Child extends Parent ( )
Child클래스에 새로운 코드가 추가되어도 조상인 Parent클래스는 아무런 영향도 받지 않
는다.
조상 클래스가 변경되면 자손 클래스는 자동적으로 영향을 받게 되지만,자손 클래스가 변경되는 것은 조상 클래스에 아무런 영향을 주지 못한다.
자손 클래스는 조상 클래스의 모든 멤버를 상속 받으므로 항상 조상 클래스보다 같거나
많은 멤버를 갖는다. 즉,상속에 상속을 거듭할수록 상속받는 클래스의 멤버 개수는 점점
늘어나게 된다.
그래서 상속을 받는다는 것은 조상 클래스를 확장(extend)한다는 의미로 해석할 수도
있으며 이것이 상속에 사용되는 키워드가 ‘extends’인 이유이기도 하다.
- 생성자와 초기화 블럭은 상속되지 않는다. 멤버만 상속된다.
- 자손 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.
자손 클래스는 조상 클래스의 모든 멤버를 물려받으므로 GrandChild클래스는 Child클래
스의 모든 멤버,Child클래스의 조상인 Parent클래스로부터 상속받은 멤버까지 상속받
게 된다. 그래서 GrandChild클래스는 Child클래스의 자손이면서 Parent클래스의 자손
이기도 하다. 좀 더 정확히 말하자면,Child클래스는 GrandChild클래스의 직접 조상이
고. Parent클래스는 GrandChild클래스의 간접 조상이 된다. 그래서 GrandChild클래스
는 Parent클래스와 간접적인 상속관계에 있다고 할 수 있다.
class Parent {
int age;
}
class ChilId extends Parent { }
class Child2 extends Parent { }
class GrandChild extends Child { }
Parent클래스는 클래스 Child, Child2, GrandChild의 조상이므로 Parent클래스에 추가
된 멤버변수 age는 Parent클래스의 모든 자손에 추가된다. 반대로 Parent클래스에서 멤
버변수 age를 제거 한다면,Parent의 자손클래스인 Child, Child2, GrandChild에서도
제거된다.
이처럼 조상 클래스만 변경해도 모든 자손 클래스에, 자손의 자손 클래스에까지 영향을
미치기 때문에, 클래스간의 상속관계를 맺어 주면 자손 클래스들의 공통적인 부분은 조상
클 래 스 에 시 관 리 하 고 자 손 클 래 스 는 지 - 신 에 정 의 된 멤 버 들 만 관 - 리 하 면 되 므 로 각 클래스
의 코드가 적어져서 관리가 쉬워진다.
1.2 클래스간의 관계 _ 포함관계
1.3클래스간의 관계 결정하기
두 경우를 비교해 보면 Circle클래스를 작성하는데 있어서 Point클래스를 포함시키거나
상속받도록 하는 것은 결과적으로 별 차이가 없어 보인다
그 럴 때 는 ‘〜 은 〜 이 다 (i s - a)’와 ‘〜은 〜을 가지고 있다(h a s _a ),를 넣어서 문장을 만들어
보면 클래스 간의 관계가 보다 명확해 진다.
원 (Circle)은 점 (Point) 이다. - Circle is a Point.
원 (Circle) 은 점 (Point)을 가지고 있다. - Circle has a Point.
상속관계 '〜은〜이다.(is-a)’
포함관계 、은 〜을 가지고있다.(has-a)'
class DrawShape {
public static void main(String[] args) {
Point[] p = ( new Point(100, 100),
new Point(140, 50),
new Point(200, 100)
};
Triangle t = new Triangle(p);
Circle c = new Circle(new Point(150z 150), 50);
t.draw(); // 삼각형을그린다.
c.draw(); // 원을그린다.
}
}
class Shape {
String color = "black";
void draw() {
System.out.pr丄ntf(”[color=%s]%nn, color);
class Point {
int x;
int y;
Point(int x ,int y) {
this.x = x;
this.y = y;
}
Point(){
this (0,0);
}
String getXY() {
return " ("+x+", "+y+"》// x외 y의 값을 문자열로 반환
}
class Circle extends Shape {
Point center; // 원의원점좌표
int r; //반지름
Circle()
this(new Point(0,0),100;//Circle(point center, int r)호출
}
도형을 의미하는 Shape클래스를 정의하고, 2차원 좌표에서의 점을 의미하는 Point클래
스토 한 다유,이 두 클래스를 재활용해서 Circle클래스와 Triangle클래스를 정의하
였다. 앞서 배운 ‘is-a’와 ‘has_a’로 클래스간의 관계를 어떻게 맺어야하는지 확인해보
자.
Circle을 Shapes와 상속관계로, 그리고 Point외는 포함관계로 정의하면 다음과 같다.
class Circle extends Shape { // Circle과 Shape는 상속관계
Point center; // Circle과 Point는포함관계
int r;
}
Circle클래스에도 draw()가 정의되어 있다. 그러면 둘 중에 어떤 것이 호출되는
것일까? 이미 결과를 통해 알 수 있듯이 Circle클래스의 draw()가 호출된다.
class Circle extends Shape {
void draw() ( // 원을 그리는 대신에 원의 정보를 출력하도록 했다.
System.out.printf (H [center = (%d,%d), r = %dr color = %s] %nnf
center .xz center', y, r, color);
Circle c = new Circle(new Point(150, 150), 50);
위 문장이 좀 복잡해 보이지만,아래의 두 문장을 하나로 합쳐놓은 것일 뿐이다.
Point p = new Point(150, 150);
Circle c = new Circle(p, 50);
1.4 단일 상속(single inheritance)
다른 객체지향언어인 C++에서는 여러 조상 클래스로부터 상속받는 것이 가능한 ‘다중상
속(m ultiple inheritance)을 허용하지만 자바에서는 단일 상속만을 허용한다. 그래서 하
나 이상의 클래스로부터 상속을 받을 수 없다. 예를 들면,TV클래스와 VCR클래스가 있을
때, 이 두 클래스로부터 상속을 받는 TVCR클래스를 작성할 수 없다.
그래서 TVCR클래스는 조상 클래스로 TV클래스와 VCR클래스 중 하나만 선택해야한다.class TVCR extends TV, VCR { // 에러 . 조상은 하나만허용된다.
1.5 Object클래스 _ 모든 클래스의 조상
Object클래스는 모든 클래스 상속계층도의 최상위에 있는 조상클래스이다. 다른 클래스
로부터 상속 받지 않는 모든 클래스들은 자동적으로 Object클래스로부터 상속받게 함으
로써 이것을 가능하게 한다.
만일 다음과 같이 다른 클래스로부터 상속을 받지 않는 Tv클래스를 정의하였다고 하자.class Tv {
}
위의 코드를 컴파일 하면 컴파일러는 위의 코드를 다음과 같이 자동적으로 ‘extends
Object'를 추가하여 Tv클래스가 Object클래스로부터 상속받도록 한다.class Tv extends Object ( }
이렇게 함으로써 Object클래스가 모든 클래스의 조상이 되도록 한다. 만일 다른 클래스로
부터 상속윤 받는다고 하더라도 상속계충도를 따라 조상클래스, 조상클래스의 조상클래
스를 찾아 올라가다 보면 결국 마지막 최상위 조상은 Object클래스일 것이다.
모든 상속계층도의 최상위에는 Object클래스가 위치한다. 그래서 자바의 모든 클
래스들은 Object클래스의 멤버들을 상속 받기 때문에 Object클래스에 정의된 멤버들을
사용할 수 있다.
그동안 toString()이나 equals(Object o)와 같은 메서드를 따로 정의하지 않고도 사용
할 수 있었던 이유는 이 메서드들이 Object클래스에 정의된 것들이기 때문이다.
Ob ject클래스에는 toString(), equals()와 같은 모든 인스턴스가 가져야 할 기본적인
11개의 메서드가 정의되어 있으며 이에 대해서는 ‘9장 java.lang패키지와 유용한 클래스’
에서 자세히 학습하게 될 것이다.
2. 오버라이딩
2.1 오버라이딩
부모 클래스로부터 상속받은 메소드의 내용을 자식 클래스에서 변경하는 것
2.2 오버라이딩 조건
선언부가 조상클래스의 메소드와 일치해야한다.접근 제어자를 조상클래스의 메소드보다 좁은 범위로 변경할 수 없습니다.예외는 조상클래스의 메소드보다 많이 선언할 수 없습니다.
2.3 오버라이딩? 오버로딩?
오버로딩 (overloading)기존에 없는 새로운 메소드를 정의하는것
vs
오버라이딩 (overriding)상속받은 메소드의 내용을 변경하는 것
2.4 super
this()처럼 super()도 생성자이며,조상의 생성자를 호출하는데 사용됩니다.
3. 제어자
3.1 static
'클래스의', '공통적인' 의미를 가지고 있으면 JVM 메소드 영역에 저장되며 인스턴스를 생성하지 않아도 사용할 수 있다. 인스턴스 변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만, 클래스변수 (static 멤버변수)는 인스턴스에 관계없이 같은 값을 갖는다.
3.2 final
변수에 사용되면 값을 변경할 수 없는 상수가 되며, 메소드에 사용되면 오버라이딩 불가, 클래스에 사용되면 상속이 불가능하다.
abstrack
- 추상 메소드 : 선언부만 작성하고 구현부는 작성하지 않는 메소드
- 추상 클래스 : 클래스 내에 추상 메소드가 선언되어 있음을 의미
- 추상 클래스는 아직 완성되지 않은 메소드가 존재하기 때문에 인스턴스를 생성할 수 없다.
3.4 접근 제어자
접근 제어자는 멤버 또는 클래스에 사용되어 해당 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 합니다.
public > protected > (default) > private
제어자 | 같은 클래스 | 같은 패키지 | 자손 클래스 | 전체 |
---|---|---|---|---|
public | O | O | O | O |
protected | O | O | O | |
(default) | O | O | ||
private | O | |||
- 접근 제어자 default 는 아무런 접근 제어자도 붙이지 않은 것을 의미합니다. |
접근 제어자
- 멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할
- 접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버 변수, 메서드, 생성자
private
: 같은 클래스 내에서만 접근 가능default
: 같은 패키지 내에서만 접근 가능protected
: 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근 가능public
: 접근 제한 x
접근 범위
public > protected > (default) > private
접근 제어자를 이용한 캡슐화
- 클래스의 내부에 선언된 데이터를 보호하기 위해서 클래스나, 멤버에 접근 제어자를 사용
- 외부로부터의 접근을 제한하는 것을 데이터 감추기(data hiding)라고 하며, 객체지향개념의 캡슐화(encapsulation)에 해당하는 내용이다.
접근 제어자를 사용하는 이유
- 외부로부터 데이터를 보호하기 위해서
- 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서
생성자의 접근 제어자
- 생성자에 접근 제어자를 사용함으로써 인스턴의 생성을 제한할 수 있음
- 생성자의 접근 제어자를
private
로 지정하면,외부에서 생성자에 접근할 수 없으므로 클래스 내부에서 인스턴스를 생성해 반환해주는public
메서드를 제공함으로써 외부에서 인스턴스를 사용할 수 있게 할 수 있음 - 생성자가
private
인 클래스는 자손클래스에서 조상클래스 생성자 호출이 불가능하기 때문에 다른 클래스의 조상이 될 수 없음
제어자(modifier)의 조합
제어자를 조합해서 사용할 때 주의해야 할 사항
- 메서드에
static
과abstract
를 함께 사용할 수 없다.static
메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.
- 클래스에
abstract
와final
을 동시에 사용할 수 없다.- 클래스에 사용되는
final
은 클래스를 확장할 수 없다는 의미이고abstract
는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다.
- 클래스에 사용되는
abstract
메서드의 접근 제어자가private
일 수 없다.abstract
메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가private
이면, 자손클래스에서 접근할 수 없기 때문이다.
- 메스드에
private
과final
을 같이 사용할 필요는 없다.- 접근 제어자가
private
인 메서드는 오버라이딩될 수 없기 때문이다.
- 접근 제어자가
4. 다형성
4.1 다형성
다형성은 '여러 가지 형태를 가질 수 있는 능력'을 의미하며, 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현하였습니다. 일반적으로 인스턴스의 타입과 참조변수의 타입이 일치하지만, 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조하는 것도 가능합니다.
다형성(Polymorphism)
객체지향개념에서 다형성이란 '여러 가지 형태를 가질 수 있는 능력'을 의미하며, 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함으로써 다형성을 프로그램적으로 구현하였다.
- 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하였다.
class Tv {
...
}
class CationTv extends Tv {
...
}
Tv t = new CationTv();
CationTv c = new CationTv();
실제 인스턴스가 CationTv타입이라 할지라도, 참조 변수 t로는 CationTv인스턴스의 모든 멤버를 사용할 수 없다. 둘 다 같은 타입의 인스턴스지만 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.
CationTv c = new Tv();
와 같은 코드는 컴파일 에러가 발생한다. 그 이유는 실제 인스턴스인 Tv의 멤버 개수보다 참조변수 c가 사용할 수 있는 멤버 개수가 더 많기 때문이다.참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다.
4.2 참조변수의 형변환
참조변수의 형변환은 사용할 수 있는 멤버의 개수를 조절하기 위한 것 이며, 서로 상속관계에 있는 클래스 사이에서만 가능합니다.자손타입에서 조상 타입으로 형변환하는 경우, 형변환은 생략이 가능 하지만조상타입에서 자손타입으로 형변환하는 경우 형변환은 생략이 불가능합니다.
형변환 예제
public class CastingTest1 {
public static void main(String[] args) {
Car car = null;
FireEngine fe = new FireEngine();
FireEngine fe2 = null;
fe.water();
car = fe; // car = (Car) fe; 형변환 생략 가능
// car.water(); 자식 클래스에 정의된 메서드 호출 불가
fe2 = (FireEngine) car; // 자식 타입 <- 부모 타입 형변환 생략 불가능
fe2.water(); // 자식 클래스에 정의된 메서드 호출 가능
}
}
class Car{
String color;
int door;
void drive() {
System.out.println("drive");
}
void stop() {
System.out.println("stop");
}
}
class FireEngine extends Car { // Car 클래스 상속
void water() {
System.out.println("water");
}
}
참조변수의 형변환
서로 상속관계에 있는 클래스사이에서만 가능하기 때문에 자손타입의 참조변수를 조상타입의 참조변수로, 조상타입의 참조변수를 자손타입의 참조변수로의 형변환만 가능하다.
자손타입 -> 조상타입(Up-casting) : 형변환 생력가능
자손타입 <- 조상타입(Down-casting) : 형변환 생략불가
형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다. 단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위를 조절하는 것뿐이다.
서로 상속관계에 있는 타입의 형변환은 양방향으로 자유롭게 수행될 수 있으나, 참조변수가 가리키는 인스턴스의 자손타입으로 형변환은 허용되지 않는다. 따라서 참조변수가 가리키는 인스턴스의 타입이 무엇인지 확인하는 것이 중요하다.
[instanceof
연산자](https://seongho96.tistory.com/56#instanceof%--%EC%--%B-%EC%--%B-%EC%-E%--)
참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 istanceof
연산자를 사용한다.어떤 타입에 대한 instanceof
연산의 결과가 true 라는 것은 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.
참조변수와 인스턴스의 연결
멤버변수가 조상 클래스의 자손 클래스에 중복으로 정의된 경우, 조상타입의 참조변수를 사용했을 때는 자손 클래스에 선언된 멤버변수가 사용된다. 하지만 중복 정의되지 않는 경우, 조상타입의 참조변수를 사용했을 때와 자손타입의 참조변수를 사용했을 때의 차이는 없다.
추상 클래스(abstract class)
추상 클래스는 클래스로서의 역할을 다 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상 클래스로서 중요한 의미를 갖는다. 추상 클래스는 키워드 abstract
를 붙인다.
추상 클래스는 추상 메서드를 포함하고 있다는 것을 제외하고는 일반 클래스와 전혀 다르지 않다.
추상화
- 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업
구체화
- 상속을 통해 클래스를 구현, 확장하는 작업
추상 메서드(abstract method)
추상 메서드란 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이다.
추상 클래스로부터 상속받는 자손 클래스는 오버라이딩을 통해 조상인 추상 클래스의 추상 메서드를 모두 구현해주어야 한다. 만일 조상으로부터 상속받은 추상 메서드 중 하나라도 구현하지 않는다면, 자손 클래스 역시 추상 클래스로 지정해 주어야 한다.
인터페이스(interface)
- 인터페이스는 일종의 추상 클래스
- 인터페이스는 추상 메서드와 상수만을 멤버로 가질 수 있음
- 모든 멤버변수는
public static final
이어야 하며, 생략 가능 - 모든 메서드는
public abstract
이어야 하며, 생략 가능
interface InterfaceName {
(public static final) 타입 상수이름 = 값;
(public static) 메서드이름(args);
}
인터페이스의 상속
- 클래스와 달리 다중 상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능
인터페이스의 구현
- 인터페이스는 구현 클래스를 구현한다는 의미의 키워드
implements
를 사용 - 구현 클래스의 메서드 중 일부만 구현한다면,
abstract
를 붙임
리턴 타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.
인터페이스의 장점
- 개발시간을 단축시킬 수 있음
- 표준화 가능
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있음
- 독립적인 프로그래밍 가능
[default
메서드와 static
메서드](https://seongho96.tistory.com/56#default%--%EB%A-%--%EC%--%-C%EB%--%-C%EC%--%--%--static%--%EB%A-%--%EC%--%-C%EB%--%-C)
JDK1.8부터 인터페이스에 default 메서드와 static 메서드를 추가할 수 있게 됐다.
가장 대표적인 예: java.util.Collecltions
default 메서드인터페이스가 확장된다는 것은 추상 메서드를 추가한다는 것이고, 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 한다. 이를 방지하기 위해 default method
가 나오게 되었다. default 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드로, 추상 메서드가 아니기 때문에 default 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다.
public interface MyInterface {
void method();
default void newMethod();
}
위와 같이 default 메서드를 추가하면, 기존의 MyInterface
를 구현한 클래스를 변경하지 않아도 된다. 즉, 조상 클래스에 새로운 메서드를 추가한 것과 동일해 지는 것이다.
새로 추가된 default 메서드가 기존의 메서드의 이름이 중복되어 충돌하는 경우 해결하는 규칙- 여러 인터페이스의 default 메서드 간의 충돌 - 인터페이스를 구현한 클래스에서 default 메서드를 오버라이딩해야 한다.- default 메서드와 조상 클래스의 메서드 간의 충돌 - 조상 클래스의 메서드가 상속되고, default 메서드는 무시된다.
내부 클래스(inner class)
내부 클래스란 클래스 내에 선언되는 클래스를 뜻한다.
public class Outer {
class InstanceInner { }
static class StaticInnter { }
}
내부 클래스의 장점- 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근 가능- 코드의 복잡성을 줄일 수 있음 ➡️ 캡슐화
내부 클래스의 종류
내부 클래스 | 특징 |
---|---|
인스턴스 클래스(instance class) | 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 인스턴스멤버 처럼 다루어진다. 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언된다. |
스태틱 클래스 (static class) | 외부 클래스의 멤버변수 선언 위치에 선언하며, 외부 클래스의 static 멤버처럼 다루어진다. 주로 외부 클래스의 static 멤버, 특히 static 메서드에서 사용될 목적으로 선언된다. |
지역 클래스 (local class) | 외부 클래스의 메서드나 초기화 블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다. |
익명 클래스 (anonymous class) | 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용) |
익명 클래스 (anonymous class)
익명클래스는 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.
'취준 note 2023 > 자바의정석' 카테고리의 다른 글
자바의정석 기초편 - 변수의 초기화 ~객체지향 개념 2-2 (0) | 2023.01.11 |
---|---|
자바의 정석 요약본 한번에 정리하기 - 객체 1-2~6. 변수으 초기화 (0) | 2023.01.10 |
자바의 정석 기초편 -요약파일 한꺼번에 정리하기 변수~객체1 (0) | 2023.01.09 |
자바의 정석 -상속 (3) | 2022.12.21 |
자바의정석-객체지향 -클래스와 객체, 인스턴스 (1) | 2022.11.20 |