지금까지 사용한 변수에 대해 알아보고 클래스의 상속과 다형성에 대해 알아보도록 하자
상속을 알아야 기능을 상속 받아 사용 할 때 저장공간과 코드를 줄일 수 있고 필요 시 재정의하여 사용 할 수 있으니 꼭 알아야 파트이다.
stack을 이용하여 코드를 작성해보자
public class VariableTest{
static int data = 0; //static 변수로 초기화
void f(){
System.out.println(++data);
} //f()메소드 생성
void f2(){
data = 20;
} // f2()메소드 생성
}
public class VariableTest2 {
public static void main(String[] args) {
//객체화
VariableTest vt = new VariableTest();
vt.f();
vt.f();
vt.f2();
vt.f();
vt = new VariableTest(); //전역변수는 new를 만나면 초기화 된다.
vt.f();
}
}
변수를 알아야되는 이유
상속에 들어가기 전 변수에 대해 알아본 이유는 이 변수의 종류별로 작동하는 원리와 사용방법을 알아야 상속기능을 사용하였을 때 new를 만나 다시 초기화되는 변수인지 아니면 지역변수로 극히 일부로 사용되는 변수인지 이해해야 메소드를 활용하거나 재정의 할때 헷갈리지 않을 수 있다.
상속(inheritance)
부모가 자식에게 재산을 상속하듯 부모클래스가 자식클래스에게 기능을 상속하는 것을 말한다.
기존에 사용중인 클래스의 필드를 다른 클래스에서 계속 사용하고 싶으면 상속 기능 받는다.
그렇게 되면 부모 클래스의 필드를 마치 자신의 것처럼 사용 할 수 있다.
주의사항
- 다중 상속은 불가능하다.
- 자식은 하나의 부모만 상속 받을 수 있다.
A : 부모클래스, 상위클래스, 슈퍼클래스, 기반클래스
B : 자식클래스, 하위클래스, 서브클래스, 파생클래스
상속을 사용할때는 Class 자식 extends 부모 라고 작성해야한다.
//A:부모 클래스, B: 자식 클래스
Class A{
A 필드
}
Class B extends A{
A 필드
B 필드
}
super(); 는 부모클래스의 객체를 초기화하면 자동적으로 생성되는 것으로 자식 클래스에서 부모 클래스의 객체를 그대로 사용하고 싶을때 부모클래스의 객체를 그대로 자식 클래스로 가져온뒤 super(-,-,-);에 초기화 할 값들을 적으면 부모클래스에서 객체가 초기화 된다.
부모 클래스의 변수들을 자식 클래스에서 상속받을 때 그 변수들을 멤버 변수라고 한다.
각 멤버 변수의 접근 권한에 대해 알아보자
부모 클래스로부터 상속받은 멤버 변수의 접근 권한이 private일때
1. 부모 클래스의 생성자를 호출해서 초기화 시킬 수 있다. ex) super(매개변수)
2. 부모 클래스에 setter메소드를 통해 초기화 시킬 수 있다.
3. 변수에 저장된 값은 getter메소드를 통해 가져온다.
부모 클래스로부터 상속받은 멤버 변수의 접근 권한이 protected일때
1. 자식 클래스에서 접근이 가능하기 때문에 this를 사용해서 초기화 한다.
2. 자식 클래스에서 접근이 가능하므로 getter메소드를 사용하지 않고 변수명으로 값에 직접 접근하면 된다.
자식 클래스의 생성자가 실행되기 전에 부모 클래스의 생성자가 먼저 실행된다. 따라서 실행할 부모 크래스의 생성자를 지정하지 않으면 부모 클래스의 기본 생성자가 자동으로 실행된다.
자동으로 입력되는 super()는 지워도 남았다.
접근권한 중 final로 설정하면 가져올 수는 있지만 값을 변경할 수 없다.
class A {
int data = 0; //사용하지 않으나 자동 생성하기 위해 만듦
public A(){
System.out.println("부모 클래스 생성자")
}
void show(){
System.out.println("A클래스")
}
class B extends A {
//show 메소드 가져오기(자동으로 override로 만들어짐)
@Override
void show() {
System.out.println("B클래스");
}
public class InhTest {
public static void main(String[] args) {
B instance = new B(); //기본 생성자가 들어있다.
instance.show();
}
}
결과 : "부모 클래스 생성자", "B클래스"
여기서 알 수 있는 내용은 자식 크래스를 사용 할때 부모의 기본 생성자는 따라 온다는 것이고 부모클래스의 메소드를 자식클래스에서 재정의하여 본인 것 처럼 사용 할 수 있다는 것이다.
public class Car{
final int wheel = 4;
public String brand;
protected String color;
private int price;
public Car(){
System.out.println("부모 클래스의 기본 생성자");
}
//alt+shift+s > o 자동생성, super 지우기
public Car(String brand, String color, int price) {
this.brand = brand;
this.color = color;
this.price = price;
}
void engineStart(){
System.out.println("열쇠로 시동 킴");
}
void engineStop(){
System.out.println("열쇠로 시동 끔");
}
//price는 private이니 getter,setter로 가져오자
//alt+shift+s > r
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
public class SuperCar extends Car{
//SuperCar 클래스 만의 변수
String mode;
public SuperCar(){
System.out.println("자식 클래스의 기본 생성자");
}
//자식 생성자를 자동으로 만들고 부모의 super를 이용한다. 부모의 멤버변수를 활용하기 위해
public SuperCar(String brand, String color, int price, String mode){
super(brand, color, price) //부모의 객체(멤버변수)를 가져옴, 심지어 private도 가능
this.mode = mode; //얘는 자동으로 만들어짐
}
//부모의 메소드를 가져와 재정의 해보자
@Override
void engineStart() {
System.out.println("음성으로 시동 킴");
}
@Override
void engineStop() {
System.out.println("음성으로 시동 끔");
}
toString은 toString을 리턴하고 있으며 해당 변수의 주소값을 보여준다. 이 리턴 값을 자식 클래스의 기본값을 보여주는 메소드로 재정의하여 다음 클래스의 메인메소드에서 사용 할 것이다. toString을 재정의 해보자
...생략
@Override
void engineStop() {
System.out.println("음성으로 시동 끔");
}
//price는 private로 super를 활용하여 초기화할 수는 있지만 값을 가져오는 것은 get을 사용한다.
@Override
public String toString() {
return "브랜드 : " + brand + "\n색상 : " + color + "\n가격 : " + getPrice();
}
public class CarTest {
public static void main(String[] args) {
SuperCar ferrari = new SuperCar("ferrari", "Red", 45000, "sport");
System.out.println(ferrari.toString());
System.out.println("모드 : " + ferrari.mode); //toString 재정의 안해서 따로 사용함.
ferrari.engineStart();
ferrari.engineStop();
}
}
다형성(polymorphism)이란?
다형성이란 하나의 메소드가 서로 다른 클래스에서 다양하게 실행되는 것을 말한다.
다형성을 구현하기 위해서는 다형성을 구현할 메소드를 포함할 클래스에게 부모 클래스가 상속해 줘야 한다. 부모클래스와 자식클래스에 같은 이름의 메소드가 있어야 하고, 자식 클래스에서는 재정의 해야한다.
다형성의 종류에는 Overloading, Override 이 있다.
오버로딩(Overloading)
같은 이름의 메소드지만 매개변수의 갯수 혹은 타입이 다르면 선언이 가능.
같은 클래스 내에서 같은 이름의 메소드를 오버로딩하면 사용가능하다.//오버로딩 void add(int num1, int num2){ System.out.println("두 정수의 합"); System.out.println(num1+num2); } //매개변수의 변화를 줘 같은 이름의 메소드를 사용함. void add(int num1, int num2, int num3) { System.out.println("세 정수의 곱과 더하기"); System.out.println(num1*num2+num3); }
오버라이드(Override)
부모클래스에서 정의된 메소드를 매개변수에 상관없이 override를 하면 자식클래스에서 같은 이름과 같은 매개변수의 메소드의 내용을 바꿀 수 있다.
//부모클래스 void engineStart(){ System.out.println("열쇠로 시동 킴"); } //자식클래스 @Override void engineStart() { System.out.println("음성으로 시동 킴"); }