2023. 1. 3. 21:39ㆍJava
1. 상속(Inheritance)
1-1. 상속의 개념
- 상속이란, 기존 클래스의 변수와 메서드를 물려받아 기존 클래스를 재사용한 새로운 클래스를 구성하는 것임.
- 즉, 연관있는 클래스의 공통적인 구성요소를 정의하여 대표하는 클래스(부모 클래스)를 만듦.
- 자식 클래스는 상속을 통해 부모 클래스의 특징을 물려받아 사용함으로써
1.코드의 중복 제거
2. 코드의 재사용성
의 이점을 얻을 수 있음.

조상 클래스 : 부모 클래스, 상위 클래스, 기반 클래스
- 자손 클래스에게 어떠한 영향도 받지 않음
자손 클래스 : 자식 클래스, 하위 클래스, 파생된 클래스
- 조상 클래스의 모든 멤버를 상속받으므로 항상 조상클래스보다 같거나 큰 멤버를 가짐
- 단, 상속자와 초기화 블록은 상속되지 않음
- 상속을 '확장'의 의미로도 볼 수 있기에 extends 키워드를 사용함
1-2. 상속관계와 포함관계
- 포함(composite) 관계
- 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것
- A가 B를 가지고 있으면 A는 B를 포함한다.
- 상속 관계
- A가 B이고, B가 A, A2, A3, ...를 통칭하는 말이라면 A는 B를 상속한다.
class Circle {
int x;
int y;
int r;
}
class Point {
int x;
int y;
}
이를 포함관계로 Point 클래스를 재사용하여 작성하면, 다음과 같이 작성할 수 있음.
class Point{
int x;
int y;
}
class Circle {
Point p = new Point();
int r;
}
1-3. 단일상속(Single inheritance)
- 한 클래스는 오직 한 클래스만 상속 가능하다는 것임.
- 단일상속을 통해 클래스 간 관계가 명확해지고 코드의 신뢰성이 높아짐.
- A extends B (O)
- A extends B, C (X)
1-4. Object 클래스
- 모든 클래스의 최상위에 있는 조상클래스
- 다른 클래스로부터 상속 받지 않는 모든 클래스는 자동적으로 Object 클래스로부터 상속받음
2. 오버라이딩(Overriding)
- 조상 클래스가 갖고 있는 메서드를 자손 클래스가 재정의해 사용하는 것.
- 즉, 조상 클래스에서 정의한 메서드를 자손 클래스가 상속받아 해당 메서드를 재정의해 사용하는 것임.
<오버라이딩의 조건>
1. 접근제어자는 조상클래스의 메서드보다 좁은 범위로 변경할 수 없음
(protected 메서드를 protected나 public으로 설정하는 것은 가능, but private나 default는 불가능함)
2. 조상 클래스보다 많은 에외 선언은 불가능함.
3. 조상 클래스 메서드의 선언부(이름, 매개변수, 반환타입)이 일치해야 함.
오버라이딩과 오버로딩

구분 | 오버로딩 | 오버라이딩 |
메서드 이름 | 동일 | 동일 |
매개변수, 타입 | 다름 | 동일 |
리턴 타입 | 상관없음 | 동일 |
class Parent{
void parentMehod(){}
}
class Child extends Parent {
//오버라이딩
void parentMethod(){
System.out.println("overriding");
}
//오버로딩
void parentMethod(String str){
System.out.println(str);
}
}
2-1. super와 super()
- super
- 부모 클래스로부터 상속받은 필드나 메서드를 자식 클래스에서 참조할 때 사용하는 참조변수
- 부모 클래스의 멤버와 자식 클래스의 멤버명이 같을 경우 'super'를 통해 구별(this 참조변수와 비슷한 기능)
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void method() {
System.out.println(x); //자식 인스턴스 변수 x
System.out.pritnln(super.x); //부모 인스턴스 변수 x
}
}
public class Main{
public static void main(String[] args){
Child c = new Child();
c.method;
// 20과 10 차례로 출력
}
}
- super()
- 부모 클래스의 생성자 호출시 사용됨
- 자식 클래스의 객체가 인스턴스화 될 때 기본적으로 부모 클래스의 default 생성자를 호출해야 하는데, 이를 호출하는 것이 super()
- 자식 클래스 생성자의 첫 줄에서 super() 메서드가 항상 실행되어야 하지만, 편의성을 위해 생략되어도 자동으로 인식됨
- 즉, 직접 생성자를 정의하거나 생성자 오버라이딩이 되어 있을 경우 올바른 생성자를 super 메서드로 직접 정의해서 호출해야 함
public class Parent {
private int x;
public Parent(int x){
this.x = x;
}
}
public class Child extends Parent {
private int y;
public Child(int y){ // super() 기본 생성자를 찾을 수 없어 컴파일 에러 발생
}
}
위의 예는 컴파일 에러가 발생하므로, 직접 부모 클래스 생성자를 호출하여야 함.
public class Parent {
private int x;
public Parent(int x){
this.x = x;
}
}
public class Child extends Parent {
private int y;
public Child(int x){
super(x);
}
3. 패키지(package)
3-1. 패키지

- 클래스의 묶음으로, 관련있는 클래스 파일을 저장하는 디렉터리임.
- 서로 다른 패키지라면, 같은 이름의 클래스더라도 구별이 가능해 존재하는 것이 가능함(이름 충돌을 피할 수 있음).
패키지는 다음과 같이 선언됨.
package 패키지명;
3-2. import문
- 다른 패키지의 클래스를 사용하려고 할 때, 사용하고자 하는 클래스의 패키지를 명시함.
- package문 다음과 클래스 선언문의 이전에 선언함.
static import
- static 멤버 호출시 클래스 이름 생략이 가능함
import static java.lang.Math.random;
import static java.lang.System.out;
class Main{
public static void main(String[] args){
out.println(random());
}
}
4. 제어자(modifier)
4-1. 제어자
- 클래스와 클래스 멤버의 선언 시 사용하여 부가적인 의미를 부여함.
- 하나의 대상에 대해 여러 제어자 조합을 사용할 수 있음(단, 접근 제어자의 경우 한 가지만 사용 가능함).
접근 제어자 : public, protected, private, (default)
그 외: static, final, abstract, ...
4-2. 접근 제어자
- 외부로부터 접근하지 못하도록 제어하여 보호하는 역할(캡슐화)


public 제어자

- 어디서나 접근이 가능함(모두 허용).
default 제어자

- 따로 접근 제어자를 명시하지 않으면 default 제어자임.
- 같은 패키지에 속하면 접근 가능하나, 다른 패키지에서는 접근 불가능함.
protected 제어자

- 다른 패키지에서는 접근 불가능하지만, 상속시에는 가능함.
- 이 멤버를 선언한 클래스의 멤버의 경우 접근 가능함.
- 이 멤버를 선언한 클래스가 속한 같은 패키지의 멤버일 경우에 접근 가능함.
- 이 멤버를 선언한 클래스를 상속받은 자식 클래스 멤버일 경우 접근 가능함.
private 제어자

- 외부에서는 직접 접근할 수 없으며, 공개되어 있지 않음.
- 클래스 내부의 세부적 동작을 구현하는 데 사용됨.
- getter/setter 구현 시 주로 이용됨.
4-3. 기타 제어자
static 제어자
- 동일 클래스 내의 모든 인스턴스가 공유.
- 인스턴스에 관계없이 같은 값을 지님.
final 제어자
- 변경할 수 없는 경우 사용함.
- field에 사용시, 값이 변경불가능한 상수(constant).
- 메서드에 사용시, 오버라이딩이 불가능한 메서드.
- 클래스에 사용시, 상속받을 수 없는 클래스.
abstract 제어자
- 선언부만 작성하고 실제 수행 내용은 구현하지 않은 추상 메서드를 선언할 때 사용.
5. 다형성
5-1. 다형성(ploymorphism)
- 하나의 객체가 여러 자료형 타입을 가질 수 있는 것.
- 부모 클래스의 참조변수로 자식 클래스 타입의 인스턴스를 참조할 수 있음.
- 단, 자식 클래스의 참조변수로 부모 클래스 타입의 인스턴스를 참조할 수는 없음
(자식 클래스에서 사용할 수 있는 멤버의 개수는 부모 클래스와 같거나 많기 때문임).
class Tv {
boolean power;
int channel;
void power() { power = !power; }
void channelUp() { ++channel;}
void channelDown() { --channel;}
}
class CaptionTv extends Tv {
String text;
void caption() {}
}
Tv t = new Tv();
CaptionTv c = new CaptionTv();
Tv t2 = new CaptionTv(); // 조상 타입 참조변수로 자손 타입 인스턴스 참조 가능
CaptionTv c2 = new Tv(); //오류, 자식 타입 참조변수로 부모 타입 인스턴스 참조 불가능
5-2. 참조변수의 형변환
- 서로 상속관계의 클래스에서는 참조변수도 형변환이 가능.
- 자식 클래스에서 부모 클래스로 형변환(업캐스팅)은 생략가능.
- 부모 클래스에서 자식 클래스로 형변환(다운캐스팅)은 반드시 명시해야 함.

업캐스팅
- 자식 클래스가 부모 클래스 타입으로 형변환(캐스팅)되는 것.
- 캐스팅 연산자 괄호 생략 가능.
- 자식 클래스에서만 존재하는 속성과 메서드는 실행 불가능하게 됨(부모 클래스의 멤버만 접근 가능).
- 즉, 업캐스팅 후 메소드 실행 시, 자식 클래스에서 오버라이딩한 메서드가 있다면 부모 클래스에서의 메서드가 아닌 오버라이딩 된 메서드를 실행하게 됨.
다운캐스팅
- 업캐스팅과는 반대로 부모 클래스가 자식 클래스 타입으로 캐스팅되는 것.
- 캐스팅 연산자 괄호 생략 불가능.
- 명시적으로 형변환을 지정해야 함.
- 주로 업캐스팅한 객체를 다시 자식 클래스 타입의 객체로 되돌리는 목적을 가짐.
class Car{}
class Truck extends Car {}
class FireEngine extends Car{}
Truck t = new Truck();
Car c = (Car) t; //조상 타입으로 형변환, 업캐스팅, 생략 가능
Truck t2 = (Truck) c; // 자손 타입으로 형변환, 다운캐스팅, 생략 불가
FireEngine f = (FireEngine) t; // 에러
5-3. instance of
- 참조하고 있는 인스턴스의 실제 타입을 알려주는 연산자.
- 어느 클래스 타입인지 판별하여 true/false를 반환함.
- true일 경우, 검사한 타입으로 형변환이 가능함.
- false일 경우, 형변환이 불가능하거나, 참조변수 값이 null임.
참조변수 instanceof 클래스명
class Parent{}
class Child extends Parent{}
class Brother extends Parent{}
public Class Main{
public static void main(String[] args){
Parent p = new Parent();
System.out.println(p instanceof Parent); //true
System.out.println(p instanceof Child); // false
Parent p2 = new Child();
System.out.println(p2 instanceof Parent); //true
System.out.pritnln(p2 instanceof Child); //true
}
}
6. 추상클래스(abstract class)
6-1. 추상클래스
- 구체적이지 않은 추상적인 데이터를 담고 있는 클래스.
- 일반 클래스와 달리 인스턴스화가 불가능한 클래스(인스턴스 생성 불가능).
- 즉, 하나 이상의 추상 메서드(미완성 메서드)를 포함하는 클래스.
- 추상 클래스를 상속받는 자손 클래스는 오버라이딩을 통해 추상 클래스의 추상 메서드를 모두 구현해야 함.
6-2. 추상 메서드
- 추상 메서드란 선언부만 작성하고 구현부는 작성하지 않은 미완성 메서드임.
- 미완성인 구현부는 해당 추상 메서드를 상속받은 클래스에서 구현함.
abstract class Player{ //추상클래스, 추상 메서드를 하나 이상 가짐.
abstract void play(int pos); //추상 메서드
abstract void stop(); //추상 메서드
}
abstract class AbstractPlayer extends Player{ //추상 메서드를 모두 완성하지 않아 추상클래스
void play(int pos){ /*구현*/} //추상 메서드 구현
}
class ChildPlayer extends Player{ //추상 메서드를 모두 완성함
void play(int pos){ /*구현*/} //추상 메서드 구현
void stop() {/*구현*/} //추상 메서드 구현
}
7. 인터페이스(interface)
7-1. 인터페이스
- 일종의 추상클래스로 틀만이 존재함.
- 추상화 정도가 높아 오직 추상메서드와 상수만을 멤버로 가짐.
- 인터페이스의 필드는 상수로만 정의가능함.
- 모든 멤버변수는 public static final이어야 하며, 이를 생략가능함(생략 시 컴파일러가 자동 추가).
- 모든 메서드는 public abstract이어야 하며, 이를 생략가능함.
7-2. 인터페이스 구현
- 인터페이스는 인스턴스를 생성할 수 없으며, 인터페이스가 자손 클래스에 상속되어 구현될 때 인스턴스 생성가능함.
- 여러개를 다중구현 할 수 있음.
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
class Fighter implements Movable, Attackable{ // 다중 구현 가능
public void move(int x, int y) {/*구현*/}
public void attack(Unit u){/*구현*/}
}
- 클래스 상속과 인터페이스 구현도 동시에 가능함.
//상속과 구현 동시 가능
class Fighter extends Unit implements Fightable {
public void move(int , int y) {/*구현*/}
public void attack(Unit u) {/*구현*/}
}
인터페이스의 추상 메서드는 public abstract가 생략된 상태이기에, 자식 클래스에서 오버라이딩 시에는 반드시 부모의 메서드보다 넓은 범위의 접근 제어자(public)로 설정해주어야 함.
7-3. 강한 결합과 느슨한 결합

- 인터페이스를 사용하는 주된 이유 중 하나.
강한 결합
- 두 클래스가 직접적 관계일 때.
- 위의 그림에서 A는 B에 의존함(A가 B의 메서드를 사용).
- 클래스 A가 클래스 C를 사용하려면, B에 의존적인 코드를 C에 의존하도록 변경해야 함.
느슨한 결합
- A는 인터페이스 I에 의존하고 있고, I를 구현한 클래스 B를 사용함.
- 이 때, A가 C를 사용하도록 수정하려면, A는 I에 의존하고 있으므로 I를 구현한 클래스 C 사용시 A의 코드를 변경할 필요가 없음.
7-4. 인터페이스 상속
- 클래스는 인터페이스를 상속받을 수 없음.
- 인터페이스는 인터페이스끼리만 상속 가능함.
- 여러 개를 다중 상속할 수 있음.
interface Fightable extends Movable, Attackable { } //다중 상속 가능
- 인터페이스의 최고 조상은 Object 클래스가 아님.
7-4. 인터페이스의 장점
독립적인 프로그래밍의 가능

- 인터페이스를 통해 선언과 구현부를 분리시켜 독립적인 프로그래밍이 가능함.
- 즉, 클래스와 클래스 간 직접적인 관계를 인터페이스를 이용한 간접적 관계로 변경함으로써 서로 다른 클래스 간 미치는 영향이 없어짐(객체간 의존성 줄어듦).
서로 관계 없는 클래스끼리의 관계 형성
- 아무 관계가 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하게 하여 관계를 형성할 수 있음.
개발시간 단축
표준화 가능
- 프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 후, 인터페이스를 구현함으로써 일관되고 정형화된 프로그램의 개발이 가능함.
- ex) JDBC, API, ...
<참고자료>
자바의 정석(3rd edition) - 도우출판
http://www.tcpschool.com/java/java_modifier_accessModifier
https://scshim.tistory.com/228
'Java' 카테고리의 다른 글
[JAVA]컬렉션 프레임워크(Collections Framework) (0) | 2023.01.15 |
---|---|
[JAVA] HashMap을 키(key), 값(value) 기준으로 정렬하는 방법 (1) | 2023.01.06 |
[JAVA] 객체지향 프로그래밍 (0) | 2023.01.03 |