상속(Inheritance) : extends
- 기존의 클래스로 새로운 클래스를 작성하는 것(코드의 재사용)
- 두 클래스를 부모와 자식으로 관계를 맺어주는 것
- 자손은 조상의 모든 멤버를 상속받는다(생성자, 초기화블럭 제외)
- 자손의 멤버 개수는 조상보다 적을 수 없다(같거나 많다)
- 자손의 변경은 조상에 영향을 미치지 않는다
포함(composite)이란?
- 클래스의 멤버로 참조변수를 선언하는 것
- 작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다.
class Point {
int x;
int y;
}
class Circle {
Point c = new Point();
int r;
}
단일 상속
- Java는 단일상속만을 허용한다.
- 비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 한다.
Object클래스 - 모든 클래스의 조상
- 부모가 없는 클래스는 자동적으로 Object클래스를 상속받게 된다.
- 모든 클래스는 Object클래스에 정의된 11개의 메서드를 상속받는다.
-> toString(), equals(Object obj), hashCode()...
오버라이딩(overriding)
- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것
오버라이딩의 조건
1 .선언부가 조상 클래스의 메서드와 일치해야 한다.
2 .접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
3 .예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
오버로딩 vs 오버라이딩
- 오버로딩 : 기존에 없는 새로운 메서드를 정의하는 것(new), 이름이 같은 메서드를 매개변수만 다르게 해서 정의하는 것
- 오버라이딩 : 상속받은 메서드의 내용을 변경하는 것(change, modify)
참조변수 super
- 객체 자신을 가리키는 참조변수. 인스턴스 메서드(생성자)내에서만 존재
- 조상의 멤버를 자신의 멤버와 구별할 때 사용
public class AAA {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
class Parent { int x = 10; } //super.x
class Child extends Parent {
int x = 20; // this.x
void method() {
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("super.x=" + super.x);
}
}
조상의 생성자 super()
- 조상의 생성자를 호출할 때 사용
- 조상의 멤버는 조상의 생성자를 호출해서 초기화
- 자손의 생성자는 자손 요소만 초기화해야함 / 조상의 요소는 조상의 생성자를 호출해 초기화
- ⭐생성자의 첫 줄에 반드시 생성자를 호출해야 한다. 그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 삽입
패키지 package
- 서로 관련된 클래스의 묶음
- 클래스는 클래스 파일(*.class), 패키지는 폴더, 하위 패키지는 하위 폴더
- 클래스의 실제이름은 패키지를 포함(java.lang.String). rt.jar는 클래스들을 압축한 파일(JDK설치경로 \jre\lib에 위치)
import문
- 클래스를 사용할 때 패키지이름을 생략할 수 있다.
- 컴파일러에게 클래스가 속한 패키지를 알려준다.
- java.lang패키지의 클래스는 import하지 않고도 사용할 수 있다.
제어자 modifier
- 클래스와 클래스 멤버(멤버변수, 메서드)에 부가적인 의미 부여
- 하나의 대상에 여러 제어자를 같이 사용가능(접근 제어자는 하나만)
접근제어자 : public, protected, (default), private
그 외 : static, final, abstract, natice, synchronized...
static - 클래스의, 공통적인
final - 마지막의, 변경될 수 없는
abstract - 추상의, 미완성의
접근제어자
- private : 같은 클래스 내에서만 접근이 가능하다.
- (default) : 같은 패키지 내에서만 접근이 가능하다.
- protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
- public : 접근 제한이 전혀 없다.
캡슐화
접근제어자를 사용하는 이유
- 외부로부터 데이터를 보호하기 위해서
---> iv 접근제어자를 private으로 하여 외부에서 직접 접근하지 못하도록 한다.
---> 메서드는 public으로 해서 메서드를 통해 iv에 접근할 수 있도록
- 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서
public class AAA {
public static void main(String[] args) {
Time t = new Time();
t.setHour(21);
System.out.println(t.getHout());
}
}
class Time {
private int hour;
private int minute;
private int second;
public void setHour(int hour) {
if (hour<0 || hour>23) return;
this.hour = hour;
}
public int getHour() { return hour; }
}
Q. 참조변수의 타입은 인스턴스의 타입과 반드시 일치해야 하나요?
A. No. 일치하는 것이 보통이지만 일치 하지 않을 수도 있다.SmartTv s = new SmartTv(); //참조 변수와 인스턴스의 타입이 일치 Tv t = new SmartTv(); //조상 타입 참조변수로 자손 타입 인스턴스 참조
Q. 참조변수가 조상타입일 때와 자손타입일 때의 차이?
A. 참조변수로 사용할 수 있는 멤버의 갯수가 달라집니다.
Q. 자손 타입의 참조변수로 조상 타입의 객체를 가리킬 수 있나요?
A. Nope.Tv t = new SmartTv(); //허용 SmartTv s = new Tv(); //허용x
⛔ 7-23 다형성 다시 ⛔
⛔ 7-24,25 참조변수의 형변환 다시 ⛔
public class AAA {
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, Brrrr");
}
void stop() {
System.out.println("stop!");
}
}
class FireEngine extends Car {
void water() {
System.out.println("water!");
}
}
instanceof 연산자
- 참조변수의 형변환 가능여부 확인에 사옹. 가능하면 true 반환
- 형변환 전에 반드시 instanceof로 확인해야 함
Q. 참조변수의 형변환은 왜 하나요?
A. 참조변수(리모콘)을 변경함으로써 사용할 수 있는 멤버의 갯수를 조절하기 위해서
Q. instanceof 연산자는 언제 사용하나요?
A. 참조변수를 형변환하기 전에 형변환 가능여부를 확인할 때
매개변수의 다형성
- 참조형 매개변수는 메서드 호출 시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.
⛔ 7-27,28 매개변수 다형성 예제 다시 ⛔
⛔⛔ 7-29,30 여러종류의 객체를 배열로 다루기~ 다시 ⛔⛔
추상 클래스 abstract class
- 미완성 설계도. 미완성 메서드를 갖고 있는 클래스
- 다른 클래스 작성에 도움을 주기 위한 것. 인스턴스 생성 불가
- 상속을 통해 추상 메서드를 완성해야 인스턴스 생성 가능
추상 메서드 abstract method
- 미완성 메서드. 구현부(몸통 {})가 없는 메서드
- 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우
- 추상메서드 호출 가능(호출할 때는 선언부만 필요)
추상 클래스의 작성
- 여러 클래스에 공통적으로 사용될 수 있는 추상클래스를 바로 작성하거나 기존클래스의 공통 부분을 뽑아서 추상클래스를 만든다.
- 추상화된 코드는 구체화된 코드보다 유연하다. 변경에 유리
인터페이스 interface
- 추상 메서드 집합
- 구현된 것이 전혀 없는 설계도, 껍데기(모든 멤버가 public)
- interface의 모든 메서드는 항상 public abstract이기 때문에 생략가능하다
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수목록);
}
class 클래스이름 implements 인터페이스이름 {
//인터페이스에 정의된 추상메서드를 모두 구현해야 한다.
}
Q. 인터페이스란?
A. 추상 메서드의 집합
Q. 인터페이스의 구현이란?
A. 인터페이스의 추상메서드 몸통{} 만들기 (미완성 설계도 완성하기)
Q. 추상클래스와 인터페이스의 공통점은?
A. 추상 메서드를 가지고 있다.(미완성 설계도)
Q. 추상 클래스와 인터페이스의 차이점은?
A. 인터페이스는 iv를 가질 수 없다.
interface Fightable {
void move (int x, int y);
void attack (Fightable f); //Fightable 인터페이스를 구현한 클래스의 인스턴스만 매개변수 가능
}
인터페이스의 장점
- 두 대상(객체)간의 '연결, 대화, 소통'을 돕는 '중간역할'을 한다.
- 선언(설계)와 구현을 분리시킬 수 있게 한다.
- 인터페이스 덕분에 B가 변경되어도 A는 안바꿀 수 있게 된다.(느슨한 결합)
- 개발 시간을 단축할 수 있다.
- 변경에 유리한 유연한 설계가 가능하다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들을 관계 맺어줄 수 있다.
default 메서드, static 메서드
- 인터페이스에 디폴트 메서드, static메서드 추가 가능 (JDK1.8부터)
- 인터페이스에 새로운 메서드(추상메서드)를 추가하기 어려움
-> 해결책으로 default 메서드
- default 메서드는 인스턴스 메서드(인스턴스 원칙 위반)
디폴트 메서드가 기존의 메서드와 충돌할 때의 해결책
1 .여러 인터페이스의 디폴트 메서드 간의 충돌
-> 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩 해야한다.
2 .디폴트 메서드와 조상 클래스의 메서드 간의 충돌
-> 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.