객체지향의 상속
- 부모클래스에 정의된 멤버 변수. 메소드를 자식 클래스가 물려 받음(부모의 생물학적 특성을 물려받는 유전과 유사)
상속의 형식
- 자식 클래스 이름 뒤에 extends를 쓰고 부모 클래스 이름을 적으면 됨
-extends: 확장 또는 파생을 뜻함
상속이 필요한 이유
- 원하는 코드를 가진 클래스가 이미 존재한다면 이 클래스를 상속받아서 이미 존재한느 클래스의 필드와 메소드를 재사용 할 수 있다
- 상속으로 중복 코드를 줄인다
자바 상속의 특징
- 다중 상속을 지원하지 않는다( 하나의 자식 클래스가 둘 이상의 부모클래스를 가질 수가 없음)
- 상속의 횟수에는 제한이 없음
- 상속 계층 구조의 최상위에는 java.long.Object 클래스가 있다. (올라가다가 부모 클래스의 최상위가 없으면 이렇다는 뜻)
class Shape{
int x, y; //여기 x,y를 밑에서 지정
}
class Circle extends Shape{
int radius;
public Circle(int radius) {
this.radius = radius;
x = 0; //자식에서 부모의 변수 지정 가능*****
y = 0;
}
double getArea() {
return 3.14*radius*radius;
}
}
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle(10);
System.out.println(c1.x);
System.out.println(c1.y);
System.out.println(c1.getArea());
}
}
상속과 접근 지정자
- 자식 클래스는 부모 클래스의 public멤버, protected 멤버, default멤버 를 상속 받는다.
-하지만!!! private은 상속되지 않는다.
상속과 생성자
Q) 자식 클래스의 객체가 생성될 때, 자식 클래스의 생성자만 호출될까? 아니면 부모 크랫스의 생성자도 호출 될까? 순서는 어떤 식으로?
A) 부모 클래스도 호출 되면서 순서는 부모 클래스가 먼저
why) 자식 클래스 객체 안에는 부모 클래스에서 상속된 부분이 들어가 있음 따라서 자식 클래스 안의 부모 클래스 부분을 초기화하기 위하여 부모 크래스의 생성자도 호출 된다. (부모클래스의 생성자) -> (자식 클랫의 생성자) 순
명시적인 생성자 호출 - super();
- 자식 클래스 안에서 super()를 호출하면 부모 클래의 생성자가 호출됩니다.
묵시적인 생성자 호출
- 부모클래스의 기본 생성자가 자동으로 호출 되도록 (only 매개함수가 없는 생성자만 있을 때 가능!!)
class Base{
public Base() {
System.out.println("Base");
}
}
class Derived extends Base{
public Derived() {
super(); //위에 부모클래스의 생성자가 매개변수가 없기 때문에 생략 가능
System.out.println("Derived");
}
}
public class Test1 {
public static void main(String[] args) {
Derived d = new Derived();
}
}
class Base{
public Base(int x) { //매개변수가 있는 생성
System.out.println("Base");
}
}
class Derived extends Base{
public Derived() {
super(3); //생략되어서는 안됨
System.out.println("Derived");
}
}
public class Test1 {
public static void main(String[] args) {
Derived d = new Derived();
}
}
class Base{
int x, y;
public Base() { //매개변수가 없는 생성자
x = y = 0;
}
public Base(int x, int y) { //매개변수가 있는 생성자
this.x = x;
this.y = y;
}
}
class Derived extends Base{
int z;
public Derived(int x, int y, int z) {
super(x, y); //Base(int x, int y) > 인수 형태에 딸라 적잘한 생성자로 선택되어짐.
System.out.println("Derived");
}
}
public class Test1 {
public static void main(String[] args) {
Derived d = new Derived(3, 4, 5);
}
}
메소드 오버라이딩(Method Overriding)
- 메소드 오버라이딩은 자식 클래스가 부모 클래스의 메소드를 자신의 필요에 맞추어서 재정의 (틀만 유지하고 내부 구성을 바꿈)
class Shape{
public void draw() { System.out.println("shape");
}
class Cirlce extends Shape{
@Override
public void draw() { System.out.println("circle");
}
class Rectangular extends Shape{
@Override
public void draw() { System.out.println("rect");
}
class Triangle extends Shape{
@Override
public void draw() { System.out.println("traingle");
}
@override: 경고 및 검사 해줌
- 철자를 잘못 쓰는 경우, 컴파일러는 이걸을 새로운 메소드 이름으로 인식한다. 따라서 메소드 오버라이드가 일어나지 않는다.
- 이것을 방지하기 위해 오버랑딩된 메소드 이름 앞에 @override 어노테이션을 붙이는 것이 좋다. 만약 부모 클래스에 그런 이름의 메소드가 없다면 컴파일러가 오류를 발생한다.
키워드 super를 사용하여 부모 클래스 멤버 접근
- 만약 부모 클랫의 메소드를 오버라이딩한 경우 super를 사용하면 부모클래스의 메소드로 호출 할 수 있음
class Shape{
public void draw() { System.out.println("shape");}
}
class Circle extends Shape{
public void draw() {
super.draw();
System.out.println("circle");
}
}
class Rectangular extends Shape{
public void draw() { System.out.println("rect");}
}
class Triangle extends Shape{
public void draw() { System.out.println("traingle");}
}
public class CircleTest {
public static void main(String[] args) {
Circle c1 = new Circle();
c1.draw();
}
}
이때
Overloading vs Overriding 차이
overloading: 같은 이름을 가진 여러개의 메소드를 작성
overriding: 부모클래스의 메소드를 자식 클래스가 다시 정의하는 것을 의미
다형성
- 위에 것들은 모두 다형성과 관련이 있다. "이름을 재사용"한다.
- 오버로딩은 컴파일 시간(실행 전)에서의 다형성을 지원
- 오버라이딩은 실행 시간(실행 이후)에서의 다형성을 지원
- 객체들의 타입이 다르면 동일 메소드가 전다뢰더라도 서로 다른 동작을 하는 것이다.
정적 메소드를 오버라이딩 하게 되면?
A)자식 클래스가 부모 클랫의 정적 메소드와 동일한 정적 메소드를 정의하는 경우, 어떤 참조 변수를 통하여 호출되는지에 따라 달라진다.
자식 클래스의 객체를 만들면 자식 클래스 안의 메소드로 호출되고 부모 클래로 객체를 만들면 정적 메소드이기에 오버라이딩 안되고 부모 클래스의 메소드로 호출된다.
class Animal {
public static void A() {
System.out.println("static method in Animal");
}
}
public class Dog extends Animal {
public static void A() {
System.out.println("static method in Dog");
}
public static void main(String[] args) {
Dog dog = new Dog();
dog.A();
Animal animal = new Animal();
animal.A();
Animal a = dog; //업캐스팅: 자식 객체를 부모 객체로 형변환 하는 것!!!!!!
a.A();
}
}
업캐스팅(상향 형변환)
- 부모클래스 변수로 자식 클래스 객체를 참조
- 자식 객체를 부모 객체로 형변환
- 부모클래스의 멤버에 접근 할 수 있지만 자식 클래스의 멤버는 접근이 불가능 함
class Parent{
int x, y;
void print(){ System.out.println("parent 메소드 호출");}
}
class Child extends Parent{
int width, height;
@Override void print(){ System.out.println("child 메소드 호출");}
}
public class test{
public static void main(String arg[]){
//이게 기본
Parent p1 = new Parent();
//업캐스팅
Parent p2 = new Child(); // 자식 객체를 부모 변수로 가리킴(어찌되었거나 타입이 부모!!)
p2.x = 0;
p2.y = 0; //부모 클랫의 필드와 메소드에 접근하는 것은 가능
//p2.width = 100;
//p2.height = 100; //but 자식 클래스의 필드는 접근 할 수 없음
p2.print(); // 자식의 print 호출
//Child c = new Parent(); //이것은 컴파일 오류; 부모객체는 child의 정보가 없음
//다운캐스팅: 부모 객체를 자식 객체로 형변환
Child c = (Child)p2;
c.print();//메소드 오버라이딩 자식 객체의 print()호출
}
}
instanceof 연산자
- 변수가 가리키는 객체의 실제 타입을 알고 싶으면 instanceof연산자를 사용하면 된다.
public class test{
public static void print(Shape obj){
if (obj instanceof Rectangular)
System.out.println("실제 타입은 rectangular");
if (obj instanceof Triangle)
System.out.println("실제 타입은 triangle");
if (obj instanceof Circle)
System.out.println("실제 타입은 circle");
}
}
종단 클래스와 종단 메소드
- 종단 클래스(final class): 상속을 시킬 수 없는 클래스 (보안 상의 이유로 사용)
final class String{
...
}
'STUDIES > JAVA' 카테고리의 다른 글
Java - 9. 자바 GUI (0) | 2022.11.01 |
---|---|
Java - 8. 자바 API패키지 (0) | 2022.10.25 |
Java - 클래스와 객체 (0) | 2022.10.24 |
Java - 7. 추상 클래스, 인터페이스, 중첩클래스 (0) | 2022.10.24 |