상속이란? 부모클래스에 만들어진 필드와 메소드를 자식클래스가 물려받는 것. 클래스 사이의 상속 (NOT 객체사이 상속)
아래처럼 코드가 중복되면 클래스 유지 보수가 힘들다.
Person클래스를 만들어서 상속받고, 확장하도록 구성하면 더 편하지.
클래스 상속과 객체
상속선언
슈퍼클래스(super class) : 부모 클래스
서브클래스(sub class) : wktlr zmffotm
상속선언 : extends 키워드 사용
public class Person{
...
} //슈퍼 클래스
public class Student extends Person{
...
} //Person을 상속받는 클래스 Student 선언
class Point{
private int x,y;
public void set(int x,int y) {
this.x=x;
this.y=y;
}
public void showPoint() {
System.out.println("("+x+","+y+")");
}
}
class ColorPoint extends Point{
private String color;
public void setColor(String color) {
this.color = color;
}
public void showColorPoint() {
System.out.print(color);
showPoint();
}
}
public class ColorPointEx {
public static void main(String[] args) {
Point p = new Point();
p.set(1, 2);
p.showPoint();
ColorPoint cp = new ColorPoint();
cp.set(3, 4);
cp.setColor("red");
cp.showColorPoint();
}
}
상속 선언 Point를 상속받는 ColorPoint 클래스 상속 선언
class ColorPoint extends Point{
...
}
서브클래스 객체 생성 Point 클래스 객체 p, ColorPoint 클래스 객체 cp 생성 이때 p는 Point 클래스 멤버만 가지고 cp는 Point,ColorPoint 클래스 멤버 전부 가짐.
Point p = new Point();
ColorPoint cp = new ColorPoint();
서브클래스에서 슈퍼클래스 멤버 접근 서브클래스는 슈퍼클래스의 private 멤버제외 모든 멤버에 접근할 수 있음.
자바 상속의 특징
자바에서는 클래스의 다중상속을 지원하지 않는다. (※다중상속 : 클래스를 여러개 상속받는 것) extends 다음에는 클래스 이름 하나만 지정할 수 있음.
상속 횟수에 제한을 두지 않는다.
최상위에 java.lang.Object 클래스가 있다.
상속과 protected 접근 지정자
슈퍼클래스에 대한 접근 지정
슈퍼클래스의 private 멤버 : 어떤 클래스에서도 접근할 수 없음
슈퍼클래스의 디폴트 멤버 : 패키지에 있는 모든 클래스 접근 가능
슈퍼클래스의 public 멤버 : 같은 패키지든, 다른 패키지든 모든 클래스에서 접근 가능
슈퍼클래스의 protected 멤버 - 다음 2가지 경우에 접근 허용
같은 패키지에 속한 모든 클래스들
상속받는 서브 클래스
상속과 생성자 : 슈퍼클래스의 생성자가 먼저 실행된 후 서브 클래스의 생성자가 나중에 실행됨!
서브클래스에서 슈퍼클래스 생성자 선택
슈퍼클래스의 기본 생성자가 자동선택되는 경우 : 명시적 지시가 없는 경우. 자바 컴파일러에 의해 강제로 선택된다.
super()를 이용한 명시적인 슈퍼클래스 생성자 선택
super() : 슈퍼클래스 생성자를 호출하는 코드. ex5-3.super()를 이용하여 ColorPoint 클래스 생성자에서 슈퍼클래스 Point 생성자를 호출하기
class Pointp{
private int x,y;
public Pointp() {
this.x=this.y=0;
}
public Pointp(int x,int y) {
this.x=x;
this.y=y;
}
public void showPoint() {
System.out.println("("+x+","+y+")");
}
}
class ColorPointp extends Pointp{
private String color;
public ColorPointp(int x,int y, String color) {
super(x,y);
this.color=color;
}
public void showColorPoint() {
System.out.print(color);
showPoint();
}
}
public class SuperEx {
public static void main(String[] args) {
ColorPointp cp = new ColorPointp(5,6,"blue");
cp.showColorPoint();
}
}
업캐스팅과 instanceof 연산자 캐스팅(Casting) : 타입변환
업캐스팅 : 서브클래스의 객체에 대한 레퍼런스를 슈퍼 클래스 타입으로 변환하는 것 업캐스팅 비유를 하자면 이런 느낌이다.
Person p;
Student s = new Student();
p=s; //업캐스팅
다운캐스팅 : 업캐스팅과 반대로 캐스팅 하는 것. 명시적으로 타입변환을 지정해야함
Person p = new Student("이티샤"); //업캐스팅
Student s= (Student)p; //다운캐스팅, (Student)타입변환을 반드시 표시.
업캐스팅과 instanceof연산자
업캐스팅의 경우 레퍼런스가 가리키는 객체의 진짜 클래스타입을 구분하기 어렵다. Person 클래스와 상속받는 클래스가 있다고 할 때..
class Person{
....
}
class Student extends Person{
....
}
class Researcher extends Person{
....
}
class Professor extends Person{
....
}
Person클래스를 상속받은 객체들을 업캐스팅을 통해 Perosn 클래스의 레퍼런스 p로 가리키는 것. 모두 정상입니다..
Person p = new Person();
Person p = new Student(); //업캐스팅
Person p = new Researcher(); //업캐스팅
Person p = new Professor(); //업캐스팅
p는P Person, Student, Researcher, Professor 중 어떤걸 가리키는지 모르는 상태임.
instanceof 연산자 사용 : 레퍼런스가 가리키는 객체가 어떤 클래스 타입인지 구분하기 위해서! 연산자 결과값은 boolean.
class Person{ }
class Student extends Person {}
class Researcher extends Person{}
class Professor extends Researcher{}
public class InstanceOfEx {
static void print(Person p) {
if(p instanceof Person)
System.out.print("Person ");
if(p instanceof Student)
System.out.print("Student ");
if(p instanceof Researcher)
System.out.print("Researcher ");
if(p instanceof Professor)
System.out.print("Professor ");
System.out.println();
}
public static void main(String[] args) {
System.out.print("new student() ->\t"); print(new Student());
System.out.print("new Researcher() ->\t"); print(new Researcher());
System.out.print("new Professor() ->\t"); print(new Professor());
}
}
메소드 오버라이딩
메소드 오버라이딩이란?
슈퍼클래스와 서브클래스의 메소드 사이에서 발생하는 관계.
슈퍼클래스에 선언된 메소드와 같은 이름, 리턴타입, 매개변수 리스트를 갖는 메소드를 서브클래스에서 재작성하는 것!
슈퍼클래스 메소드 무시하기 혹은 덮어쓰기 : 동적 바인딩
오버라이딩 사례 이해
class Shape{
public void draw(){
system.out.println("Shape");
}
}
//shpqe 클래스의 draw()메소드를 Line,Rect,Circle클래스에서 각각 오버라이딩함
class Line extends Shape{
public void draw(){
System.out.println("Line");
}
}
class Rect extends Shape{
public void draw(){
System.out.println("Rect");
}
}
class Circle extends Shape{
public void draw(){
System.out.println("Circle");
}
}
여기서 오버라이딩된 메소드 호출
Line line = new Line();
line.draw();
new Line()에 의해 생성된 객체에는 2개의 메소드가 존재함 (Shape drow()와 Line draw() 2개.)
Shape shape = new Line();
shape.draw();
이 경우는 ... new Line()에 의해 생성된 객체 역시 draw() 메소드가 2개이지만... 레퍼런스 shape이 Shape타입. shaple.draw()를 컴파일할때, 컴파일러는 Shaple클래스에 draw()멤버가 있는지 확인 후 Shape의 Draw() 호출이지만... shape.draw()의 실행시 shape이 가리키는 객체는 Line()의 Draw()이므로... Line의 Draw()가 실현됨 (이게 뭔소리여???)
오버라이딩의 목적, 다형성 실현
class Shape { //슈퍼클래스
public Shape next;
public Shape() {
next = null;
}
public void draw() {
System.out.println("Shape");
}
}
class Line extends Shape{
public void draw() {
System.out.println("Line");
}
}
class Rect extends Shape{
public void draw() {
System.out.println("Rect");
}
}
class Circle extends Shape{
public void draw() {
System.out.println("Circle");
}
}
public class MethodOverridingEx {
static void paint(Shape p) {
p.draw(); //p가 가리키는 객체 내에 오버라이딩된 draw() 호출, 동적 바인딩
}
public static void main(String[] args) {
Line line = new Line();
paint(line);
paint(new Shape());
paint(new Line());
paint(new Rect());
paint(new Circle());
}
}
메소드 오버라이딩 제약사항
슈퍼클래스의 메소드와 동일한 원형으로 작성한다.
슈퍼클래스 메소드의 접근지정자보다 접근의 범위를 좁혀 오버라이딩할 수 없다.
static, private, final 선언 메소드는 서브클래스에서 오버라이딩할 수 없음
메소드 오버라이딩 활용 : 서브 클래스 개발자가 슈퍼 클래스의 특정 메소드를 자신의 특성에 맞게 새로 만들어 사용하고자 하는 경우에 활용
동적 바인딩 : 오버라이딩된 메소드 호출
오버라이딩과 super키워드 : 서브클래스가 아닌 슈퍼 클래스 메소드를 소환하고 싶을때 사용하는 super키워드...
오버로딩(overloading)과 오버라이딩(overriding)
비교 요소
메소드 오버로딩
메소드 오버라이딩
선언
같은 클래스나 상속관계에서 동일한 이름의 메소드 중복 작성
서브 클래스에서 슈퍼클래스에 있는 메소드와 동일한 메소드 재작성
관계
동일한 클래스 내 혹은 상속 관계
상속관계
목적
이름이 같은 여러 개의 메소드를 중복 작성하여 사용의 편리성 향상, 다형성 실현
슈퍼 클래스에 구현된 메소드를 무시하고 서브 클래스에서 새롱룬 기능의 메소드를 재정의하고자함. 다형성 실현
조건
메소드 이름은 반드시 동일하고, 매개변수 타입이나 개수가 달라야 성립
메소드 이름, 매개변수 타입과 개수, 리턴 타입이 모두 동일하여야 성립
바인딩
정적 바인딩, 호출된 메소드는 컴파일시에 결정
동적 바인딩, 실행 시간에 오버라이딩된 메소드 찾아 호출하기
추상클래스
추상메소드 : 선언은 되어있으나 코드가 구현되어있지 않은 껍데기만 있는 메소드. abstract 키워드와 함께 원형만 선언, 코드 작성 x
public abstract String getName();
public abstract void setName(String s);
추상클래스 만들기 (1)추상메소드를 포함하는 클래스
abstract class Shape{ //추상 클래스 선언
public Shape()
public void paint(){ draw();}
abstract public void draw(); //추상 메소드 선언
}
(2)추상 클래스 선언
추상클래스는 객체를 생성할 수 없다.
추상클래스 상속 : 추상클래스를 단순히 상속받는 서브클래스는 추상 클래스가 된다.
추상클래스 구현과 목적
구현 : 슈퍼클래스에 선언된 모든 추상 메소드를 서브 클래스에서 오버라이딩하여 실행가능한 코드로 구현하는 것.
추상클래스의 용도
추상 메소드를 통해 서브 클래스가 구현할 메소드를 명로하게 알려주는 인터페이스.
추상 클래스 = 책의 목차
서브 클래스 = 목차에 따라 작성된 책
추상클래스 이용시 응용프로그램의 설계와 구현을 분리할 수 있음.
인터페이스 : 서로 다른 하드웨어 장치들이 상호 데이터를 주고받을 수 있는 규격
자바의 인터페이스 > interface 키워드 사용
interface PhoneInterface{
public static final int TIMEOUT=10000;
public abstract void sendCall();
public abstract void receiveCall();
public default void printLogo(){
System.out.println("**Phone **");
};
}
인터페이스의 구성 : 필드(멤버변수)를 만들 수 없다.
상수와 추상메소드(public abstract 로 정해짐. 생략 가능)
default 메소드 : 인터페이스 내에 코드 작성되어야함.접근지정은 public
private 메소드 : 인터페이스 내에 코드 작성되어야함. 인터페이스 내에서만 호출 가능
static 메소드 : 인터페이스 내에 코드 작성되어야함. 접근지정 생략시 public, private 지정가능
인터페이스는 객체를 생성할 수 없고, 레퍼런스 변수는 선언 가능!
인터페이스끼리 상속됨
인터페이스를 상속받아 클래스 작성시 인터페이스 모든 추상메소드를 구현해야함.
interface PhoneInterface{
final int TIMEOUT = 10000;
void sendCall();
void receiveCall();
default void printLogo(){
System.out.println("** Phone **");
}
}
class SamsungPhone implements PhoneInterface{
public void sendCall() {
System.out.println("띠리리리링");
}
public void receiveCall() {
System.out.println("전화가 왔습니다.");
}
public void flash() {
System.out.println("전화기에 불이 켜졌습니다.");
}
}
public class InterfaceEx {
public static void main(String[] args) {
SamsungPhone phone = new SamsungPhone();
phone.printLogo();
phone.sendCall();
phone.receiveCall();
phone.flash();
}
}
인터페이스 상속 역시 extends 키워드 사용.
자바는 인터페이스의 다중 상속을 허용함.
클래스 상속과 함께 인터페이스 구현
interface PhoneInterface{
final int TIMEOUT = 10000;
void sendCall();
void receiveCall();
default void printLogo(){
System.out.println("** Phone **");
}
}
interface MobilePhoneInterface extends PhoneInterface{
void sendSMS();
void receiveSMS();
}
interface MP3Interface{
public void play();
public void stop();
}
class PDA{
public int calculate(int x, int y) {
return x+y;
}
}
class SmartPhone extends PDA implements MobilePhoneInterface,MP3Interface{
public void sendCall() {
System.out.println("따르릉따르릉~~");
}
public void receiveCall() {
System.out.println("전화왔어요.");
}
public void sendSMS() {
System.out.println("문자갑니다.");
}
public void receiveSMS() {
System.out.println("문자왔어요.");
}
public void play() {
System.out.println("음악 연주합니다.");
}
public void stop() {
System.out.println("음악 중단합니다.");
}
public void schedule(){
System.out.println("일정 관리합니다.");
}
}
public class InterfaceEx {
public static void main(String[] args) {
SmartPhone phone = new SmartPhone();
phone.printLogo();
phone.sendCall();
phone.play();
System.out.println("3과 5를 더하면 "+phone.calculate(3, 5));
phone.schedule();
}
}