JAVA 공부 4일차
객체지향 Part. 2 (상속, 오버라이딩, 캡슐화, 다향성, 추상 클래스, 인터페이스 등)
1) 상속
ㄱ. 상속 : 기존의 클래스로 새로운 클래스를 작성하며 extends 를 이용해 부모자식 관계를 만들어 준다.
- 자손은 조상의 모든 멤버를 상속 받는다. (생성자와 초기화 블럭은 제외)
- 자손의 변경은 조상에게 영향을 주지 않는다.
- 상속받은 클래스를 상속받을 수 있다. (부모가 아니라 조상까지 갈 수 있다)
- java는 단일 상속만 허용, Diamond Problem
- 모든 클래스는 Object 클래스로 부터 상속 받는다.
ㄴ. Overriding : 상속받은 메서드를 자신에게 맞게 변경
- 선언부는 변경 불가능
- 메서드 내부의 내용만 변경 가능
- 선언부가 조상의 메서드와 일치해야함
- 접근 제어자를 조상의 메서드 보다 좁은 범위로 변경할 수 없음
- 예외는 조상 클래스의 메서드 보다 많이 선언할 수 없음.
- ※오버로딩 : 기존에 없는 새로운 메서드를 정의
ㄷ. super & super() : this & this()와 반대라고 볼 수 있으며 조상의 멤버를 자신의 멤버와 구별 할 때 사용한다.
- super
- 객체 자신을 가리키는 참조 변수 ex) super.params
- 인스턴스 메서드(생성자) 내에서만 존재
- 조상의 멤버를 자신의 멤버와 구별할 때 사용
- super()
- 조상의 생성자를 호출
- 조상의 멤버를 조상의 생성자를 호출해서 초기화
- 생성자의 첫 줄에 반드시 생성자를 호출
class Parent {
int x,y,z;
public Parent(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}
class Child extends Parent {
Child() {
// super() 를 통해서 부모 클래스의 멤버변수를 초기화합니다.
super(10,20,30);
}
}
2) package와 import
ㄱ. package
- 서로 관련된 클래스의 묶음
- 클래스의 실제 이름은 패키지를 포함 ex) java.lang.String
ㄴ. package 선언
- 패키지는 소스파일의 첫 번째 문장으로 단 한번만 선언
- 같은 소스 파일의 클래스들은 모두 같은 패키징에 속함
- 패키지 선언이 없으면 default 패키지에 속함
ㄷ. package 선언
- 클래스 파일(.class)의 위치를 알려주는 경로
- classpath(환경변수)로 관리하며 경로간의 구분자는 ; 사용
- classpath에 패키지의 루트를 등록해줘야 한다.
ㄹ. import
- 클래스가 속한 패키지를 알려주며, 클래스 사용시 패키지 이름을 생략할 수 있게 해준다.
- java.lang 패키지는 중요해서 생략 가능하게 되어있음
ㅁ. static import
- static 멤저를 사용할 때 클래스 이름 생략 가능
- ex ) import static java.lang.System.out; >> out.println("출력가능");
3) 제어자와 접근 제어자
ㄱ. 제어자
- 클래스와 멤버에 부가적인 의미 부여, 하나의 대상에 여러 제어자 사용 가능
- static
- final
- abstract
ㄴ. 접근 제어자
- private : 같은 클래스 내에서만 접근이 가능합니다.
- (default) : 같은 패키지 내에서만 접근이 가능합니다. (생략가능)
- protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능합니다.
- public : 접근 제한이 전혀 없습니다.
ㄷ. 접근 제어자 조합 주의
대상
|
사용가능한 접근 제어자
|
클래스
|
public, (default), final, abstract
|
메서드
|
모든 접근제어자, final, abstract, static
|
멤버변수
|
모든 접근제어자, final, static
|
지역변수
|
final
|
- 메서드에 static과 abstract 함께 사용 물가 : static 메서드는 몸통이 있는 메서드만 사용 가능
- class에는 abstract와 final을 동시 사용 불가 : abstract와 final의 기능 모순
- abstract메서드의 접근 제어자가 private일 수 없음 : 자손 클래스에서 구현해야하기 때문
- 메서드에서 private과final을 같이 사용할 필요는 없음 : 이 둘 중 하나만 사용해도 의미가 충분
3) 여러가지 특성(캡슐화,다형성,형변환 등)
ㄱ. 캡슐화
- 외부로부터 데이터를 보호하기 위해 사용
- 내부적으로만 사용되는 것을 외부로 노출시키지 않고 감추기 위해서
- 데이터 그자체가 아닌 메서드를 통해 확인 가능
public class Capsule {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
ㄴ. 다형성
- 여러 가지 혀ㅇ태를 가질 수 있는 능력
- 조상의 타입의 참조변수로 자손의 타입의 객체를 다루는 것,
- 하지만 조상에 없고 자손만 가지는 기능 및 속성은 사용 불가
- 아래 코드에서 Mammalia 클래스를 선언할 때 Whale로 초기화를 했다.(반대는 불가하다)
class Whale extends Mammalia{
// 고래는 포유류 이면서 바다에 살며 수영이 가능하다.
public void swimming() {
System.out.println("수영 하다.");
}
@Override
public void feeding() {
System.out.println("고래는 모유 수유를 합니다.");
}
@Override
public void giveBirth() {
System.out.println("고래는 새끼를 낳습니다.");
}
}
class Mammalia {
// 포유류는 새끼를 낳고 수유를 한다.
public void feeding() {
System.out.println("모유 수유를 합니다.");
}
public void giveBirth() {
System.out.println("새끼를 낳습니다.");
}
}
class PolyTest1 {
public static void main(String[] args) {
// 고래는 포유류이기 때문에 Mammalia 에 담길 수 있다.
Mammalia mammalia = new Whale();
// 하지만 포유류 전부가 바다에 살고 수영을 할 수 있는 것은 아니기 때문에
// 수영 하다 메서드는 실행 불가
// mammalia.swimming(); // Error 발생
// 또한 모든 포유류가 전부 고래 처럼 수영이 가능한 것이 아니기 때문에 아래 상황은 불가능 하다.
// Whale whale = new Mammalia(); // Error 발생
mammalia.giveBirth();
mammalia.feeding();
}
}
ㄷ. 참조변수의 형변환
- 사용할 수 있는 멤버의 개수를 조절하는 것
- 조상, 자손 관계의 참조변수는 서로 형변환이 가능
class Whale extends Mammalia{
// 고래는 포유류 이면서 바다에 살며 수영이 가능하다.
public void swimming() {
System.out.println("고래만 수영 하다.");
}
@Override
public void feeding() {
System.out.println("고래는 모유 수유를 합니다.");
}
@Override
public void giveBirth() {
System.out.println("고래는 새끼를 낳습니다.");
}
}
class Mammalia {
// 포유류는 새끼를 낳고 수유를 한다.
public void feeding() {
System.out.println("모유 수유를 합니다.");
}
public void giveBirth() {
System.out.println("새끼를 낳습니다.");
}
}
class Bird {
public void fly() {
System.out.println("Bird.fly");
}
}
class PolyTest2 {
public static void main(String[] args) {
Whale whale = new Whale();
Mammalia mammalia = (Mammalia) whale; //(Mammalia) 생략 가능!
mammalia.giveBirth();
mammalia.feeding();
//현재 swimming() 불가
// 형변환을 통해 담긴 mammalia 참조변수를 형변환을 통해
// 다시 Whale 로 변환할 수 있습니다.
Whale whale2 = (Whale) mammalia; // (Whale) 생략 불가능!
whale2.swimming();
whale2.feeding();
// 조상, 자손 관계에서만 형변환이 가능합니다.
Bird bird = new Bird();
// Mammalia mammalia1 = bird; // Error
// Mammalia mammalia2 = (Mammalia) bird; // Error
}
}
ㄹ. A(객체) instanceof B(클래스) 연산자
- A객체가 B클래스로 부터 상속을 받았는지 확인
- 참조변수를 형변환 하기 전에 형변환 가능 여부를 확인 하기 위해 사용
- 형변호나 전에는 반드시 instanceof로 확인 해야함
class A {}
class B extends A{}
class Instanceof {
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println("a instanceof A = " + (a instanceof A));
// a 객체는 B 클래스의 부모 클래스 입니다.
// 따라서 아래는 false 입니다.
System.out.println("a instanceof B = " + (a instanceof B));
System.out.println("b instanceof A = " + (b instanceof A));
System.out.println("b instanceof B = " + (b instanceof B));
}
}
ㄹ. 매개변수 다형성
- 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다
- 여러 종류의 객체를 배열로 다룰 수 있으며, 클래스 선언시 같은 클래스를 배열로 선언할 수 도 있다.
3) 추상클래스와 인터페이스
ㄱ. 추상클래스
- 일반 클래스와 똑같은데 추상 메서드가 추가된 미완성된 클래스
- 자녀 클래스에서 오버라이딩 후 완성 시켜 사용한다
ㄴ. 인터페이스
- 추상 메서드의 집합, 구현된 것이 전혀 없는 설계도
- 모든 멤버가 public이다.
- 상수 이외의 인스턴스 변수, 클래스 변수는 가질 수 없음
- 아래와 같은 example로 사용
interface PlayingCard {
public static final int SPADE = 4;
final int DIAMOND = 3; // public static final int DIAMOND = 3;
static int HEART = 2; // public static final int HEART = 2;
int CLOVER = 1; // public static final int CLOVER = 1;
public abstract String getCardNumber();
String getCardKing(); // public abstract String getCardKing();
}
ㄷ. 인터페이스의 상속
- 인터페이스의 조상은 언테이스만 가능, class처럼 object가 최고 조상이 아님
- 상속 받으면서 구현부를 작성하기 때문에 충돌해도 상관없음 >> 다중 상속 가능
interface Fightable extends Movable, Attackable {} // 인터페이스 다중 상속
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
ㄹ. 인터페이스의 구현
- class 클래스이름 implements 인터페이스이름 {} 으로 구현
- 추상 클래스 때와 마찬가지로 구현을 다 못한 클래스는 미완성으로 취급함으로 abstract 제어자를 클래스에 추가 해야한다.
class Unit {}
interface Fightable extends Movable, Attackable {}
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
abstract class InterfaceTest implements Fightable {
@Override
public void move(int x, int y) {
}
// attack(Unit u); // 미 구현
}
ㅁ. 인터페이스의 다형성
- 스마트폰을 할머니에게 전화기라고 말씀드리면 할머니는 전화기라고만 생각해서 다른 기능은 쓰지 않을 수 있다.또, 스마트폰을 꼬마한테 게임이야 라고 말하면 꼬마는 게임기라고 생각되어 다른 기능을 쓰지 않을 수 있다.또한 꼬마에게 줄 때, 통화 기능 등의 다른 기능들을 못쓰도록 방지하고자 잠글 수 있는데 interface는 이러한 기능 및 역할들을 모~~~~두 할 수 있기 때문에 interface다형성을 사용하는 이유이다.
ㅂ. 인터페이스의 장점
- 두 객체 간의 '연결,대화, 소통'을 돕는 '중간 다리 역할'을 한다.
- 선언(설계)와 구현을 분리시킬 수 있게 해준다.
4)참조 링크
- interface 다형성 사용 이유 : https://2ham-s.tistory.com/1032
2. 자바-다형성의 이해 및 예제
https://kadosholy.tistory.com/99