상속(inheritance)(+메소드Override, Up/Downcasting, instanceof, super,super(), Object, final, enum)

YongJun·2023년 9월 5일

JAVA

목록 보기
13/24
post-thumbnail

상속(inheritance)이란?

  • 상속(inheritance)이란 기존의 클래스에 기능을 추가하거나 재정의하여 새로운 클래스를 정의하는 것을 의미합니다.

  • 상속은 캡슐화, 추상화와 더불어 객체 지향 프로그래밍을 구성하는 중요한 특징 중 하나입니다.

  • 상속을 이용하면 기존에 정의되어 있는 클래스의 모든 필드와 메소드를 물려받아, 새로운 클래스를 생성할 수 있습니다.

  • 기존에 정의되어 있던 클래스를 부모 클래스(parent class) 또는 상위 클래스(super class), 그리고 상속을 통해 새롭게 작성되는 클래스를 자식 클래스(child class) 또는 하위 클래스(sub class)라고 합니다.

  • 생성자와 private 또는 default를 제외한 모든 것을 상속받는다.

  • Sub class로 객체를 생성하면 Super class와 자신의 생성자를 모두 호출한다.

  • 다중상속을 할 수 없다.

상속의 장점

  • 기존에 작성된 클래스를 재활용할 수 있습니다.

  • 자식 클래스 설계 시 중복되는 멤버를 미리 부모 클래스에 작성해 놓으면, 자식 클래스에서는 해당 멤버를 작성하지 않아도 됩니다.

  • 클래스 간의 계층적 관계를 구성함으로써 다형성의 문법적 토대를 마련합니다.

형식

class 자식클래스이름 extend 부모클래스이름 { ... }

메소드 Override

  • Super클래스와 Sub클래스에 똑같은 메소드가 존재
    모든 우선권은 Sub클래스가 갖는다.
  • Super, Sub 클래스의 접근제어자(Modifier)는 틀려도 되지만
    Super보다 Sub클래스의 접근제어자(Modifier)가 더 커야한다.

Up/Downcasting

  • Upcasting : 자식 클래스의 객체가 부모 클래스 타입으로 형변환 되는 것
  • Downcasting : Upcasting된 것을 다시 원상태로 돌리는 것을 말한다. 하위 클래스로의 다운캐스팅을 할때는 타입을 명시적으로 지정해줘야한다는 특징이 있다.

instanceof

  • casting(형 변환)이 되는지 안 되는지를 판별
  • 객체에 원하는 클래스 타입이 메모리 할당되었는지 안 되었는지를 확인

예제

package inheritance;

class AA{
	public int a =3;
	public void disp() {
		this.a += 5;
		System.out.println("AA : "+ a + " ");
	}
}

class BB extends AA{
	//필드는 Override 개념이 없다, 메소드에만 해당한다
	public int a =8;
	
	@Override
	public void disp() {
//		super.disp();
		this.a+=5;
		System.out.println("BB : "+ a + " ");
//		super.disp();
	}
}
public class OverrideMain {

	public static void main(String[] args) {
		BB aa = new BB(); //AA클래스와 BB클래스 메소드,필드 모두 사용 가능(AA클래스의 private 메소드,필드 제외)
		aa.disp(); //BB : 13, 오버라이딩된 자식 메소드 호출
		System.out.println("aa : "+aa.a); //aa : 13
		System.out.println();
		
		/*업캐스팅(부모 = 자식)
		부모 클래스 변수를 가지고 자식 클래스의 객체를 참조하는 경우에는 부모 클래스에서 정의된 부분만 사용할 수 있다.
		자식 클래스(BB) 중에서 부모 클래스(AA)로부터 상속받은 부분(disp())만을 bb를 통해서 사용할 수 있고 나머지는 사용하지 못한다.(부모 클래스(AA)의 메소드 필드 사용)
		 */
		AA bb = new BB();   
		bb.disp(); //BB : 13
		System.out.println("bb : "+bb.a); //bb : 3
		System.out.println();
		
		//다운캐스팅( 자식 = 부모, 부모 객체를 자식 참조 변수로 참조(error) -> 자식 = (자식)부모 )
		BB cc = (BB)bb; //자식 = (자식)부모
		cc.disp();//BB : 18 //위에서 업캐스팅을 통해 객체가 생성되어서 a 값이 13으로 설정된후 다시 BB클래스의 disp()를 호출
		System.out.println("cc : "+cc.a); //cc : 18
		System.out.println();
		
		AA dd = new AA();
		dd.disp(); //AA : 8
		System.out.println("dd : "+dd.a); //dd : 8
		System.out.println();
		
		//instanceof : 객체 타입 확인, 반환값:true,false
		if(dd instanceof AA) System.out.println("ddd"); //ddd

	}

}

super 와 super()

  • super 는 부모클래스의 참조값을 갖고 있다.
  • super() 는 부모클래스의 생성자를 호출 할 수 있다.
  • super() 는 생성자의 첫줄에 써야 한다.

예제

package inheritance;

public class Super extends Object{
	protected double weight, height;
	
	Super(){
		System.out.println("Super의 기본 생성자");
	}
	
	Super(double weight, double height){
		this.weight = weight;
		this.height = height;
	}
	
	public void disp() {
		System.out.println("몸무게 = "+this.weight);
		System.out.println("키 = "+height);
	}
}
package inheritance;

public class ChildMain extends Super {
	private String name;
	private int age;
	
	ChildMain(){
		System.out.println("ChildMain의 기본 생성자");
	}
	ChildMain(String name, int age, double weight, double height){
		super(weight,height); //부모 생성자 호출, super() 는 생성자의 첫줄에 써야 한다
//		super.weight = weight; //this.weight = weight;
//		super.height = height;
		this.name = name;
		this.age = age;
	}
	
	public void disp() {
		System.out.println("이름 = "+name);
		System.out.println("나이 = "+age);
		super.disp(); 
	}
	
	public static void main(String[] args) {
		//Sub class로 객체를 생성하면 Super class와 자신의 생성자를 모두 호출한다.
		ChildMain aa = new ChildMain("홍길동", 25, 73.5, 182.6);
		aa.disp();
		System.out.println("-----------------");
		
		Super bb = new ChildMain("코난", 13, 53.5, 156.6);
		bb.disp(); //Override(부모클래스와 자식클래스에 같은 메소드 존재)
				   //모든 우선권은 자식클래스가 갖는다.

	}

}
/*
이름 = 홍길동
나이 = 25
몸무게 = 73.5
키 = 182.6
-----------------
이름 = 코난
나이 = 13
몸무게 = 53.5
키 = 156.6
*/
package inheritance;

//상속받는 클래스는 상속해주는 클래스의 생성자와 private를 제외한 모든 것을 상속받는다
public class SubMain extends Super{
	private String name;
	private int age;
	
	SubMain(){
		System.out.println("SubMain의 기본 생성자");
	}
	
	SubMain(String name, int age, double weight, double height){
//		this();
		this.name = name;
		this.age = age;
		super.weight = weight; //this.weight = weight;
		super.height = height;
	}
	public void output() {
		System.out.println("이름 = "+name);
		System.out.println("나이 = "+age);
		super.disp(); //this.disp();
        /*
		super.disp() : 항상 부모 클래스의 disp() 메서드를 호출하며, 부모 클래스의 구현을 사용합니다.
		this.disp() : 부모 클래스에서 오버라이딩한 경우에는 자식 클래스의 disp() 메서드를 호출하고, 그렇지 않으면 부모 클래스의 disp() 메서드를 호출합니다.
		 */
	}

	public static void main(String[] args) {
		//Sub class로 객체를 생성하면 Super class와 자신의 생성자를 모두 호출한다.
		SubMain aa = new SubMain("홍길동", 25, 73.5, 182.6); 
		aa.disp(); //부모 메소드 호출
		System.out.println("-----------------");
		aa.output();
		System.out.println("-----------------");
		
		Super bb = new SubMain("코난", 13, 53.5, 156.6);
//		bb.output(); //error(침조변수 bb는 Super클래스를 참조하기 때문이다)
		bb.disp();
	}

}
/*
자식클래스는 메모리 생성할 때 
1.부모 클래스 생성 / new 부모() <- 기본 생성자
2.자식 클래스 생성 / new 자식()
*/
/*
Super의 기본 생성자
몸무게 = 73.5
키 = 182.6
-----------------
이름 = 홍길동
나이 = 25
몸무게 = 73.5
키 = 182.6
-----------------
Super의 기본 생성자
몸무게 = 53.5
키 = 156.6
*/

Object

  • Java의 최상위 클래스
  • Java의 모든 클래스는 Object로 부터 상속받는다
  • extends Object라고 직접 쓰지 않아도 된다
  • Object에서는 == , equals() 가 모두 참조값(reference) 만으로 비교한다.
    단, String만이 equals()가 내용(문자열)을 비교한다.

예제

package inheritance;

class Test extends Object {

}

class Sample extends Object{
	@Override
	public String toString() {
		return getClass()+"@용준"; //getClass() : 객체가 어떤 클래스로 생성되어있는지에 대한 정보를 반환한다.
	}
}

class Exam extends Object{
	private String name = "권용준";
	private int age = 25;
	
	@Override
	public String toString() {
//		return super.toString();
		return name + "\t" + age;
	}
}

public class ObjectMain {

	public static void main(String[] args) {
		Test t = new Test();
		System.out.println("객체 t = "+t);//클래스명@16진수
		System.out.println("객체 t = "+t.toString()); //toString() : 객체의 정보를 String(문자열)형으로 형변환 해준다.
		System.out.println("객체 t = "+t.hashCode()); //hashCode() : 주소의 값을 10진수로 변경
		System.out.println();
		
		Sample s = new Sample();
		System.out.println("객체 s = "+s.toString());
		System.out.println();
		
		Exam e = new Exam();
		System.out.println("객체 e = "+e.toString());
		System.out.println();
		
		String aa = "apple";
		System.out.println("객체 aa = "+aa);
		System.out.println("객체 aa = "+aa.toString()); // toString을 써도 문자열로 출력(주소X)
		System.out.println("객체 t = "+aa.hashCode());
		System.out.println();
		
		String bb = new String("apple");
		String cc = new String("apple");
		System.out.println("bb==cc : "+(bb==cc)); //주소 비교
		System.out.println("bb.equals(cc) : "+bb.equals(cc)); //문자열 비교
		System.out.println();
		
		//Object에서는 == , equals() 가 모두 참조값(reference) 만으로 비교한다.
		//단, String만이 equals()가 내용(문자열)을 비교한다.
		Object dd = new Object();
		Object ee = new Object();
		System.out.println("dd==ee : "+(dd==ee)); //주소 비교
		System.out.println("dd.equals(ee) : "+dd.equals(ee)); //주소 비교
		System.out.println();
		
		Object ff = new String(); //부모클래스가 자식클래스를 참조(부모 = 자식)
		Object gg = new String();
		System.out.println("ff==gg : "+(ff==gg)); //주소 비교
		System.out.println("ff.equals(gg) : "+ff.equals(gg)); //문자열 비교
		System.out.println();
		
	}

}
/*
class Object {
   public String toString() {}      	클래스명@16진수
   public int hashCode() {}      		10진수
   public boolean equals(Object ob){}   참조값 비교
}

class String extends Object
   public String toString() {}      		문자열
   public int hashCode() {}      			10진수 (믿으면 안된다) - 표기할 수 있는 문자열은 무한대이기 때문에 10진수로는 다 표기할 수 없다.
   public boolean equals(Object ob){}   	문자열 비교
}
*/

/*
객체 t = inheritance.Test@5ca881b5
객체 t = inheritance.Test@5ca881b5
객체 t = 1554547125

객체 s = class inheritance.Sample@용준

객체 e = 권용준	25

객체 aa = apple
객체 aa = apple
객체 t = 93029210

bb==cc : false
bb.equals(cc) : true

dd==ee : false
dd.equals(ee) : false

ff==gg : false
ff.equals(gg) : true
*/

final (상수화)

  • final 변수는 값을 변경할 수 없다.
  • final 변수는 반드시 초기값을 주어야 한다.
    final 필드는 생성자에서 초기값을 주어야 한다
    static final 필드는 static 구역에서 초기값을 주어야 한다
  • final 변수는 대문자로만 기술
  • final 메소드는 Override를 할 수 없다.(종단 메소드)
  • final 클래스는 자식클래스를 가질 수 없다.- 상속이 안된다 (종단 클래스)

enum (열거형)

  • 자바의 열거형은 자료형(Data Type)을 의미한다
  • 서로 관련 있는 상수들을 모아 놓은 것
  • enum 상수들은 묵시적으로 static final status형으로 선언된다
  • 먼저 자료형을 선언한 다음에 사용한다
  • 대문자로 사용
  • 열거된 순서에 따라 0부터 시작

예제

package inheritance;

//상수들의 집합체
enum Color{
	RED, GREEN, BLUE
}

class Final{
	public final String FRUIT = "사과";
	
	//클레스의 필드에 초기값 부여(생성자 사용)
	public final String FRUIT2;
	public Final() {
		System.out.println("기본 생성자");
		FRUIT2="딸기";
	}
	
	//static(실행하자마자 메모리에 자동으로 생성이 된다->new X)
	public static final String ANIMAL = "기린";
	
    //static final 필드는 static 구역에서 초기값을 주어야 한다
	//static인 경우 생성자에서 초기화가 안된다(생성자는 new해야 하기 때문)
	public static final String ANIMAL2;
	static {
		System.out.println("static 초기화 영역");
		ANIMAL2="코끼리";
	}
	
//	public static final int RED=0;
//	public static final int GREEN=1;
//	public static final int BLUE=2;
	
	
	
}

public class FinalMain {

	public static void main(String[] args) {
		final int A =10;//상수화(final 변수는 대문자로만 기술)
		//A=20; -error(final은 값을 변경할수 없다)
		System.out.println("A = "+A);
		
		//final 변수는 반드시 초기값을 주어야 한다
		final int B;
		B=30;
		//B=40; -error
		System.out.println("B = "+B);
		
		Final f = new Final();
		System.out.println("FRUIT = "+f.FRUIT);
		
		System.out.println("ANIMAL = "+Final.ANIMAL);
		
		System.out.println("ANIMAL2 = "+Final.ANIMAL2);
		System.out.println();
		
		System.out.println("빨강 = "+Color.RED);
		System.out.println("빨강 = "+Color.RED.ordinal());
		
		for(Color data : Color.values()) {
			System.out.println(data+"\t"+data.ordinal());
		}

	}

}
/*
A = 10
B = 30
static 초기화 영역
기본 생성자
FRUIT = 사과
ANIMAL = 기린
ANIMAL2 = 코끼리

빨강 = RED
빨강 = 0
RED	0
GREEN	1
BLUE	2
*/
profile
개(발자어)린이

0개의 댓글