상속 선언 : extends
자바 상속의 특징
public class Person { ... }
public class Student extends Person { ... } //Person 을 상속받는 클래스 student 선언
public class StudentWorker extends Students { ... } //Student 를 상속받는 StudentWorker 선언클래스 상속 만들기
(x,y) 의 한 점을 표현하는 Point 클래스와 이를 상속받아 컬러 점을 표현하는 ColorPoint 클래스를 만들자.
class Point{
int x,y; //한 점을 구성하는 x,y 좌표
public void set(int x, int y) { //멤버변수와 매개변수의 이름이 같아 this 사용
this.x = x;
this.y = y;
}
public void showPoint() { //점의 좌표 출력
System.out.println("(" + x + "," + y + ")");
}
}
//Point를 상속받은 ColorPoint 선언
class ColorPoint extends Point {
private String color; //점의 색
public void setColor(String color) {
this.color = color;
}
// 컬러 점의 좌표 출력
public void showColorPoint() {
System.out.print(color);
showPoint(); //Point 클래스의 showPoint() 호출
}
}
public class ColorPointEx {
public static void main(String[] args) {
// TODO Auto-generated method stub
Point p = new Point(); //Point 객체 생성
p.set(1, 2); //Point 클래스 set() 호출
p.showPoint();
ColorPoint cp = new ColorPoint(); //ColorPoint 객체 및 참조 변수 cp 로 관리
cp.set(3, 4); //Point의 set() 호출
cp.setColor("red"); //ColorPoint 의 setColor() 호출
cp.showColorPoint(); //컬러와 좌표 출력
}
}
//result
//(1,2)
//red(3,4)


자바의 접근 지정자 4가지 : public, private, protected, default
부모 클래스의 private 멤버
부모 클래스의 default 멤버
부모 클래스의 public 멤버
부모 클래스의 protected 멤버


class A {
public A() {
System.out.println("생성자A");
}
public A(int x) { ... }
}
class B extends A {
public B() {
//super();
System.out.println("생성자B");
}
}
class C extends B {
public C() { //
//super(); 부모 클래스 기본 생성자 호출! (없으면 컴파일러가 자동 추가)
System.out.println("생성자C");
}
}
public class ConstructorEx {
public static void main(String[] args) {
// TODO Auto-generated method stub
C c;
c = new C(); //생성자 호출 1번
}
}
//result
//생성자A
//생성자B
//생성자C 
슈퍼 클래스의 기본 생성자가 자동 선택
자식 클래스의 기본 생성자에 대해서 부모 클래스의 기본 생성자와 자동으로 짝 지어짐.
슈퍼 클래스의 기본 생성자가 없어 오류 난 경우
컴파일러에 의해 클래스 B 에 super() 가 자동 추가되어, 부모 클래스 A의 기본 생성자 A() 를 찾아가는데, 부모 클래스에는 기본 생성자에 대한 정의가 없음
서브 클래스에 매개변수를 가진 생성자
서브 클래스의 생성자가 슈퍼 클래스의 생성자를 선택하지 않은 경우
- super(); 코드가 없으면 맨 위에 자동 추가
실행 결과
생성자A
매개변수생성자B

class Point {
private int x, y; //한 점을 구성하는 x,y 좌표
public Point() {
this.x = this.y = 0;
}
public Point(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 ColorPoint(int x, int y, String color) {
super(x,y); //Point 의 생성자 Point(x,y) 가 호출하여, x=5, y=6 전달
this.color = color;
}
public void showColorPoint() {
System.out.print(color);
showPoint();
}
}
public class SuperEx {
public static void main(String[] args) {
// TODO Auto-generated method stub
ColorPoint cp = new ColorPoint(5, 6, "blue"); //ColorPoint(int x, int y, String color) 생성자가 자동 호출
//x=5, y=6, color="blue" 전달
cp.showColorPoint(); //Point 클래스의 showPoint() 호출
}
}
//result
//blue(5,6)생물을 넣는 박스에 코끼리나 사람을 넣고 박스 앞에 생물을 가리키는 팻말을 사
용해도 무방하다. 왜냐하면, 사람은 생물을 상속 받았기 때문이다.
자식 클래스의 객체는
업캐스팅이란?
class Person { ... }
class Student extends Person { ... }
Student s = new Student();
Person p = s; //업캐스팅. 자동 타입 변환 (사람 s 은 생물 p 이다)업캐스팅된 레퍼런스
업캐스팅 사레
class Person {
String name;
String id;
public Person(String name) {
this.name = name;
}
}
class Student extends Person {
String grade;
String department;
public Student(String name) {
super(name);
}
}
public class UpcastingEx {
public static void main(String[] args) {
Person p;
Student s = new Student("Lee Hi");
// id 는 자동으로 null 로 초기화(객체에서만)
p = s; //업캐스팅 발생 (사람 s 를 생물 p 로 변환)
//같은 데이터 타입이 아니여서 p 가 s 의 해시코드를 관리할수없어야 하는데
//업캐스팅을 하므로써 상위 영역의 데이터 정보(s 객체의 메모리 중 부모 필드 메소드)만 관리할 수 있도록
System.out.println(p.name); //오류 없음
//레퍼런스 s 를 이용하면 6개의 멤버에 모두 접근이 가능하지만
//레퍼런스 p 를 이용하여서는 Student 객체의 멤버중 오직 Person의 멤버만 접근 가능하다.
p.grade = "A"; //컴파일 오류
p.department = "Com"; //컴파일 오류
}
}
//result
//Lee Hi
업캐스팅
- 참조 변수는 같은 객체 타입의 참조값(해쉬코드)만 할당 받아야함
- 그런데, 상속 관계에서는
- '부모 클래스의 참조 변수'(s) 가 '자식 인스턴의 참조값'(p) 을 할당 가능
- 부모 클래스와 관련된 메모리가 상단(up)에 존재. 해당 영역만 사용
다운캐스팅
부모 클래스 레퍼런스를 자식 클래스 레퍼런스에 대입
업캐스팅된 것을 다시 원래대로 돌리는 것
명시적으로 타입 지정
상위영역만 사용하도록 업캐스팅이 발생한 것을
p 는 업캐스팅으로 상위영역만 사용가능하다
전체를 관리할 수 있는 참조변수 s 를 선언하여 p 를 전달하는데, p 는 상위 영역만 제공하기 때문에 (student)p 로 다운캐스팅해주므로써 s 가 상위하위 영역 모두 사용할수있게 된다.
객체레퍼런스 instanceof 클래스타입상속 관계에 있는 옆의 클래스 사례에서

다음과 같은 업캐스팅이 가능하므로
Person p = new Person();
Person p = new Student(); //업캐스팅
Person p = new Researcher(); //업캐스팅
Person p = new Professor(); //업캐스팅
print(p); 를 호출하면, print() 메소드에서 person 이 어떤 객체를 가리키는지 알 수 없음
void print(Person) {
//person 이 가리키는 객체가 Person 타입일 수도 있고
//Student, Researcher, 혹은 Professor 타입일 수도 있다.
}
Person jee = new Student(); //업캐스팅
Person kim = new Professor(); //업캐스팅
Person lee = new Researcher(); //업캐스팅
if(jee instanceof Person) //jee 는 Person 타입이므로 true
if(jee instanceof Student) //jee 는 Student 타입이므로 true
if(kim instanceof Student) //kim 은 Person 타입이 아니므로 false
if(kim instanceof Professor) //kim 은 Person 타입이므로 true
if(kim instanceof Researcher) //Professor 객체는 Researcher 타입이기도 하므로 true
if(lee instanceof Professor) //lee 는 Professor 타입이 아니므로 false
if(3 instanceof int) //문법 오류. instanceof 는 객체에 대한 레퍼런스만 사용
//정수는 기본 데이터 타입. 클래스 타입 아님
if("java" instanceof String) //true
: instanceof 해석 : Jee 라고 참조변수가 클래스 데이터 타입 Person 과 관련이 있는지를 물어보는것
instanceof 연산자를 이용하여 상속 관게에 따라 레퍼런스가 가리키는 객체의 타입을 알아본다.

실행결과는?
class Person {}
class Student extends Person {}
class Researcher extends Person {}
class Professor extends Researcher {}
public class InstanceOfEx {
static void print(Person p){ //인자를 받아 참조변수 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()); //참조변수 p 가 Student 를 관리
System.out.print("new Researcher() ->\t");
print(new Researcher()); //참조변수 p 가 Researcher 를 관리
System.out.print("new Professor() ->\t");
print(new Professor()); //참조변수 p 가 Professor 를 관리
}
}
//result
//new Student() -> Person Student
//new Researcher() -> Person Researcher
//new Professor() -> Person Researcher Professor
//new Professor() 객체는 Person 타입이기도 하고, Researcher. Professor 타입이기도 하다.
부모 클래스의 메소드를 자식 클래스에서 재정의 하는것
"메소드 무시하기", 덮어쓰기 로 변역되기도 함 재정의!
동적 바인딩 발생 조건 : [1] upcasting [2] 오버라이딩 메소드 (거의 upcasting 상황에서 발생한다.)



class Shape { //부모 클래스
public Shape next; //shape 을 관리할 수 있는 참조변수 next
public Shape() {next = null;} //생성자
public void draw() { //메소드
System.out.println("Shape");
}
}
class Line extends Shape {
public void draw() { //부모의 draw() 를 재정의 하는 메소드 오버라이딩
System.out.println("Shape");
}
}
class Rect extends Shape {
public void draw() { //draw() 를 재정의 하는 메소드 오버라이딩
System.out.println("Rect");
}
}
class Circle extends Shape {
public void draw() { //draw() 를 재정의 하는 메소드 오버라이딩
System.out.println("Circle");
}
}
public class MethodOverridingEx {
static void patin(Shape p) {
//p가 가리키는 객체 내에 오버라이딩된 draw() 호츌
p.draw();
}
public static void main(String[] args) {
Line line = new Line();
paint(line); //Shape p = line; 업캐스팅
paint(new Shape()); //Shape p = new Shape();
paint(new Line()); //Shape p = new Line(); 업캐스팅
paint(new Rect()); //Shape p = new Rect(); 업캐스팅
paint(new Circle()); //Shape p = new Circle(); 업캐스팅
}
}
//result
//Line //업캐스팅 후, 오버로딩 Line::draw()
//Shape //부모 클래스의 포인터가 같은 데이터 타입을 관리, draw()
//Line //업캐스팅 후, 오버로딩 Line::draw()
//Rect //업캐스팅 후, 오버로딩 Rect::draw()
//Circle //업캐스팅 후, 오버로딩 Circle::draw()

public class UsingOverride {
public static void main(String[] args) {
Shape start, last, obj
//링크드 리스트로 도형 생성하여 연결
start = new Line(); //start 는 Line 생성, 기본 데이터 타입 호출 -> 부모의 기본 생성자를 호출하는 super() 자동 생성 -> next = null 로
// 업캐스팅이 발생되었고 부모 영역만 접근이 가능하다.
last = start; //처음과 마지막을 가리키는 start 와 last 참조복사
obj = new Rect(); //Rect() 호출 -> 자동 생성된 suepr() 에 의해 부모 생성자를 호출하여 next = null 로 초기화 하여 obj 라는 참조로 관리
last.next = obj; //obj 라는 참조값을 last 로 관리하는 next 에게 제공하여 업캐스팅
//따라서 두개의 인스턴스가 연결이 (start 와 obj)되었다
last = obj;
obj = new Circle(); //업캐스팅 발생
last.next = obj; //두번쨰와 세번째 연결 obj 로 관리하는 참조값을 last 가 관리하는 next 에 제공하여 연결
last = obj; //last 에게 실제 마지막 위치를 가리키는 obj 참조값을 제공
//모든 도형 출력(메소드 호출)
Shape p = start; // 기존의 참조를 활용할 수 있지만 개별적으로 접근하기 위해 새로운 참조 p 를 하나 생성, 여기서도 업캐스팅 발생
while(p != null) { //계속 null 아닐동안 while 문 내부 실행
p.draw(); // 재정의된 draw() 메소드 호출, 실행할때 연계가 되는 동적 바인딩 발생
p = p.next; //다음으로 넘어가기 위해 p로 관리하는 next 참조값을 기존값을 삭제 시키고 새로 업데이드, 다음 메모리 영역에 접근이 가능함.
//그 다음 다시 조건식으로 돌아가 while 문 작성.
}
}
}
//result
//Line
//Rect
//Line
//Circle

서로 다른 데이터 타입을 링크드 리스트로 연결할떄, 서로 다른 데이터 타입이 10개라면 10개의 종류에 해당하는 참조변수가 있어야함
하지만 이를 해결하기 위해 업캐스팅을 이용해서 상위 상속받는 부모로 연결할 수 있다.
이후 오버라이딩


class ShapeEx {
protected String name;
public void paint() {
draw();
}
public void draw() {
System.out.println(name);
}
}
public class CircleEx extends ShapeEx {
protected String name; //부모의 name 과 다른것
@Override
public void draw() {
name = "Circle";
//super.name = "Shape"; 그렇다면 부모 영역에 소속되어있는 name 을 접근하여 그정보를 shape 으로 업데이트 시키고
//super.draw(); super 에 있는 draw() 를 지정해서 사용하겠다하면 이 코드가 오버라이딩의 코드라고 하더라도 오버라이딩은 되었으나 그것을 무시하게 됨.
System.out.println(name);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ShapeEx b = new CircleEx(); //b 는 상위영역만 접근할 수 있다
b.paint(); //상위영역의 paint 가 호출되어 그다음 paint 내부 draw() 가 호출됨 (우선순위 자식)
//
}
}
//result
그냥 : Circle
super 키워 추가
Shape
Circle
둘 비교 꼭.
예를 들어서 상위 하위 영역을 관리하는 참조변수 p 가 있다면 p.name 을 호출한다면 우선순위에 의해 자식 클래스의 필드, 메소드가 먼저 출력됨
class Weapon {
protected int fire() {
return 1; //무기는 기본적으로 한 명만 살상
}
}
class Cannon extends Weapon {
@override
protected int fire() { //오버라이딩
return 10;
}
}
public class Overriding {
public static void main(String[] args) {
Weapon weapon;
weapon = new Weapon();
System.out.println("The basic-weapon striking power:" + weapon.fire());
weapon = new Cannon(); //업캐스팅
System.out.println("The cannon's striking power:" + weapon.fire());
//오버라이딩 된 fire() 호출됨
}
}
//result
//The basic-weapon striking power: 1
//The cannon's striking power: 10
