기존의 클래스로 새로운 클래스를 작성하는 것(코드의 재사용)
두 클래스를 부모와 자식으로 관계를 맺어주는 것
class Parent() {} // 부모 관계
class Child extends Parent {} // 자식 관계
자손은 조상(부모의 부모)의 모든 멤버를 상속받는다.(생성자, 초기화블럭 제외)
자손의 멤버 개수는 조상보다 적을 수 없다.(같거나 많다)
자손의 변경은 조상에 영향을 미치지 않는다.
class Parent {
int age;
}
class Child extends Parent {
void play() {
System.out.println("놀자~");
}
}
class Point {
int x;
int y;
}
1. class Point3D extends Point{ 2. class Point3D {
int z; int x;
} int y;
int z;
}
Point3D p = new Point3D();
클래스의 멤버로 참조변수를 선언하는 것
class Point {
int x;
int y;
}
1. class Circle { 2. class Circle {
Point p = new Point(); int x;
int r; int y;
} int r;
}
Circle c = new Circle();
작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다.
상속 관계 : ~은 ~이다(is-a)
포함 관계 : ~은 ~을 가지고 있다(has-a)
Java는 단일 상속(하나의 부모만 허용)만을 허용한다.
class Tv {
boolean power;
int channel;
void power() { power = !power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
class DVD {
boolean power;
void power() { power = !power; }
void play() {/*내용 생략*/}
void stop() {/*내용 생략*/}
void rew() {/*내용 생략*/}
void ff() {/*내용 생략*/}
}
class TvDVD extends Tv {
DVD dvd = new DVD();
void play() {
dvd.play();
}
void stop() {
dvd.stop();
}
void rew() {
dvd.rew();
}
void ff() {
dvd.ff();
}
부모가 없는 클래스는 자동적으로 Object 클래스를 상속받게 된다.
모든 클래스는 Object 클래스에 정의된 11개의 메서드를 상속받는다.
Circle c = new Circle();
System.out.println(c.toString());
System.out.println(c); // c.toString() 과 c 는 같은 값을 출력한다.
상속 받는 조상의 메서드를 자신에 맞게 변경하는 것
class Point {
int x;
int y;
String getLocation() {
return "x= " +x+", y= "+y;
}
}
class Point3D extends Point {
int z;
String getLocation() { // 오버라이딩, 선언부는 변경 불가
return "x= " +x+", y= "+y+", z= "+z; // 내용(구현부)만 변경 가능
}
}
1. 선언부(반환타입, 메서드 이름, 매개변수 목록)가 조상 클래스의 메서드와 일치해야 한다.
2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
오버로딩(Overloading) : 기존에 없는 새로운 메서드(이름이 같은)를 정의하는 것(new)
오버라이딩(Overriding) : 상속 받은 메서드의 내용을 변경하는 것(modify)
class Parent {
void parentMethod() {}
}
class Child extends Parent {
void parentMethod() {} // 오버라이딩
void parentMethod(int i) {} // 오버로딩
void childMethod() {} // 메서드 정의
void childMethod(int i) {} // 오버로딩
void childMethod() {} // 중복정의, 에러
}
객체 자신을 가리키는 참조변수, 인스턴스 메서드(생성자)내에만 존재
조상의 멤버를 자신의 멤버와 구별할 때 사용
class Ex7_2 {
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);
}
}
결과
x=20
this.x=20
super.x=10
class Parent { int x=10; }
: 조상의 멤버 x = super.x조상의 생성자를 호출할 때 사용
조상의 멤버는 조상의 생성자를 호출해서 초기화
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
int z;
Point3D(int x, int y, int z) {
super(x, y); // 조상클래스의 생성자 Point(int x, int y)를 호출
this.z = z;
}
}
class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
class Point3D extends Point {
int z;
Point3D(int x, int y, int z) { this.x = x; this.y = y; this.z = z; }
}
public class PointTest {
public static void main(String[] args) {
Point3D p3 = new Point3D(1, 2, 3);
}
}
Point3D p3 = new Point3D(1, 2, 3);
에서 에러 발생Point(int x, int y) { this.x = x; this.y = y; }
Point3D(int x, int y, int z) { this.x = x; this.y = y; this.z = z; }
생성자의 첫 줄에 생성자를 호출하지 않아서 자동으로 첫 줄에 super(); 추가
Point(int x, int y) {
super(); // Object();
this.x = x;
this.y = y;
}
Point3D(int x, int y, int z) {
super(); // Point(); 호출
this.x = x;
this.y = y;
this.z = z;
}
해결 방법 2가지
class Point {
int x, y;
Point() {} // 기본 생성자 추가
Point(int x, int y) { this.x = x; this.y = y; }
}
Point3D(int x, int y, int z) {
super(x, y); // Point(int x, int y); 호출
this.z = z;
}
클래스와 클래스의 멤버(멤버변수, 메서드)에 부가적인 의미 부여
하나의 대상에 여러 제어자를 같이 사용 가능(접근 제어자는 하나만)
접근 제어자를 제일 왼쪽에 쓰는게 좋다.
사용 대상 : 멤버변수, 메서드
class StaticTest {
static int width = 200; // 클래스 변수(cv)
static int height = 100; // 클래스 변수(cv)
static { // 클래스 초기화 블럭
// static 변수의 복잡한 초기화 수행
}
static int max(int a, int b) { // 클래스 메서드(static 메서드)
return a + b;
}
}
사용 대상 : 클래스, 메서드, 멤버변수, 지역변수
final class FinalTest { // 조상이 될 수 없는 클래스
final inx Max = 10; // 값을 변경할 수 없는 변수(상수)
final void getMaxSize() { // 오버라이딩할 수 없는 메서드
final int LV = Max;
return Max;
}
}
사용 대상 : 클래스, 메서드
abstract class AbstractTest {
abstract void move();
}
AbstractTest a = new AbstractTest(); // 에러
private : 같은 클래스 내에서만 접근 가능
(default) : 같은 패키지 내에서만 접근 가능(아무것도 쓰지 않는 것)
protected : 같은 패키지 + 다른 패키지의 자손 클래스에서 접근 가능
public : 접근 제한 x
접근 제어자를 사용하는 이유
-> 외부로부터 데이터를 보호하기 위해서(캡슐화)
public class Time {
public int hour, minute, second; // 접근 제한 x
}
Time t = new Time();
t.hour = 25; // 멤버변수에 직접 접근
class Time {
private int hour, minute, second;
public void setHour(int hour) {
if(isNotValidHour(hour)) return;
this.hour = hour;
}
private boolean isNotValidHour(int hour) {
return hour < 0 || hour > 23;
}
public int getHour() { return hour; }
}
public class TimeTest {
public static void main(String[] args) {
Time t = new Time();
t.setHour(21);
System.out.println(t.getHour());
t.setHour(210);
System.out.println(t.getHour());
}
}
private int hour, minute, second;
외부에서 접근하지 못하도록 private로 지정
public void setHour(int hour) { if(isNotValidHour(hour)) return; this.hour = hour; }
- 메서드를 public 으로 설정하여 간접 접근 허용
- 매개변수 hour의 범위가 유효한지 확인하기 위한 메서드 생성
private boolean isNotValidHour(int hour) { return hour < 0 || hour > 23; }
접근 제어자의 범위는 가능한 최소한으로 설정(private)
-> 나중에 코드를 수정하고 확인할 때 접근 제어자의 범위만 확인하면 되기 때문에 시간을 절약할 수 있다.