JAVA
-
- 상속
- 재활용 + 알파
-
상속의 기본적인 특성
public class Man { public String name; public void tellYourName(){ System.out.println("My name is "+name); } } class BusinessMan extends Man{ public String company; public String position; public void tellyourInfo(){ System.out.println("My company is "+ company); System.out.println("My position is "+ position); tellYourName(); //Man 클래스의 메서드 } }
Man : 상위 클래스(super class) or 기초클래스
BusinessMan : 하위 클래스(sub class) or 유도 클래스(derived class)
-
상속과 생성자
public class Man { private String name; public Man(String name){ this.name = name; } public void tellYourName(){ System.out.println("My name is "+name); } } class BusinessMan extends Man{ private String company; private String position; public BusinessMan(String name, String company, String position){ super(name); //상위 클래스의 생성자 호출 this.company = company; this.position = position; } public void tellyourInfo(){ System.out.println("My company is "+ company); System.out.println("My position is "+ position); tellYourName(); } }
하위 클래스의 생성자에서는 제일 먼저 상위 클래스의 생성자를 호출해야 한다. 하지만 상위 클래스의 생성자가 디폴트인 경우는 super();문이 자동으로 하위 클래스의 생성자에 삽입되기 때문에 컴파일은 정상적으로 이뤄진다.
-
상속과 접근제어 지시자
지시자 클래스 내부 동일 패키지 상속받은 클래스 이외의 영역 private o x x x default o o x x protected o o o x public o o o o -
static 변수(메소드)의 상속과 생성자의 상속에 대한 논의
static 변수는 생성되는 인스턴스마다 독립적으로 존재하는 멤버가 아니고, 생성되는 인스턴스가 함께 공유하는 변수 및 메소드이다.
class Adder{ public static int val = 0; public void add(int num){ val+=num; } } class AdderFriend extends Adder{ public void friendAdd(int num){ val+=num; } public void showVal(){ System.out.println(val); } } public class StaticInheritance{ public static void main(String[] args){ Adder ad = new Adder(); AdderFriend af = new AdderFriend(); ad.add(1); af.friendAdd(3); AdderFriend.val+=5; af.showVal(); } }
상위 클래스에 정의된 static 변수는 하위 클래스에서도 이름만으로 접근이 가능하다. 그게 아니라면 클래스의 이름으로 접근할 수 있다.
-
- 생성자도 상속이 되나요?
- 안됩니다. 하지만 AAA(int n) { num = n;} 은 AAA를 상속받는 생성자에서 BBB(int n) {num = n;}인 것과 같다.
-
- 상속을 위한 기본 조건 IS-A 관계
- 무선 전화기는 전화기이다. 처럼 ~IS A. 여기서 A가 상위 클래스 ~가 하위 클래스가 된다.
-
- HAS-A 관계도 상속의 조건은 되지만 복합 관계로 이를 대신하는 것이 일반적이다.
- Gun 클래스를 Police가 상속받을 수도 있지만 Police의 멤버변수로 Gun을 가지고 있는 관계가 유연성이 좋다.
-
하위 클래스에서 메소드를 다시 정의하면?
class Speaker { private int volumeRate; public void showCurrentState(){ System.out.println("볼륨 크기: "+ volumeRate); } public void setVolume(int vol){ volumeRate=vol; } } class BaseEnSpeaker extends Speaker{ private int baseRate; public void showCurrentState(){ super.showCurrentState(); //필수 아님. 상위의 같은 이름 메소드를 부르기 위함 System.out.println("베이스 크리 : "+baseRate); } public void setBaseRate(int base){ baseRate= base; } } class Overriding{ public static void main(String[] args){ BaseEnSpeaker bs = new BaseEnSpeaker(); bs.setVolume(10); bs.setBaseRate(20); bs.showCurrentState(); } }
-
- 상위 클래스의 참조변수로도 하위 클래스의 인스턴스를 얼마든지 참조 가능
- 중 저음 보강 스피커(BaseEnSpeaker)는 (일종의)스피커다. (O) -> Speaker sp = new BaseEnSpeaker(); Speaker의 참조변수로 BaseEnSpeaker() 인스턴스를 참조하고 있다.
Speaker bs = new BaseEnSpeaker(); bs.setVolume(10); bs.setBaseRate(20); //컴파일 에러!
-
문제: 해당 상황에서 오버라이딩 된 메소드를 호출하면 누가 호출되는
package i_didnt_study_java; class AAA { public void rideMethod(){ System.out.println("AAA's Method"); } public void loadMethod(){ System.out.println("void Method"); } } class BBB extends AAA { public void rideMethod(){ System.out.println("BBB's Method"); } public void loadMethod(int num){ System.out.println("int Method"); } } class CCC extends BBB { public void rideMethod(){ System.out.println("CCC's Method"); } public void loadMethod(double num){ System.out.println("double Method"); } } class RideAndLoad { public static void main(String[] args){ AAA ref1 = new CCC(); BBB ref2 = new CCC(); CCC ref3 = new CCC(); ref1.rideMethod(); ref2.rideMethod(); ref3.rideMethod(); ref3.loadMethod(); ref3.loadMethod(1); ref3.loadMethod(1.2); } }
참조변수의 자료형에 상관없이 마지막으로 오버라이딩을 한 메소드만 호출된다. loadMethod를 보면 오버로딩의 관계를 구성하는 것을 알 수 있다.
- +이것을 통한 활용+
- 상위 클래스의 참조변수는 하위 클래스의 인스턴스를 참조할 수 있다. 오버라이딩 된 상위 클래스의 메소드는 오버라이딩을 한 하위 클래스의 메소드에 의해 가리워진다. 즉 외부에서는 참조변수를 통해 오버라이딩 된 상위 클래스의 메소드를 호출할 수 없다.
-
하지만 인스턴스 변수는 참조변수의 자료형에 따라 접근이 차이가 있다.
-
참조변수의 인스턴스 참조와 instanceof 연산자
public static void wrapBox(Box box){ if(box instanceof GoldPaperBox){ ((GoldPaperBox)box).goldWrap(); }else if(box instanceof PaperBox){ ((PaperBox)box).paperWrap(); }else{ box.simpleWrap(); } }
:상속을 바탕으로 형변환이 가능한지 묻는 연산자(true와 false 반환)
-
instanceof를 쓰지 않고 해결하는 방법
class Box{ public void simpleWrap(){ System.out.println("simple wrap"); } public void wrap(){} } class PaperBox extends Box{ public void paperWrap(){ System.out.println("paper wrap"); } } class GoldPaperBox extends PaperBox{ public void goldWrap(){ System.out.println("gold wrap"); } public void wrap(){ } } class InstanceOf{ public static void wrapBox(Box box){ Box.wrap(); } public static void main(String[] args){ Box box1 = new Box(); PaperBox box2 = new PaperBox(); GoldPaperBox box3 = new GoldPaperBox(); wrapBox(box1); wrapBox(box2); wrapBox(box3); } }
-
- 모든 클래스가 상속하는 Object 클래스
- class MyClass{ ~~ }는 class MyClass extends Object{ ~~ }와 같다. (다른 클래스 상속시 제외)
Object obj1 = new MyClass(); Object obj2 = new int[5];
+참고: class MyClass extends YourClass라고 해도 YourClass는 Object클래스를 상속받으므로, 간접상속이 이뤄진다. toString()을 오버라이딩함으로 원래의 ‘인스턴스 정보를 문자열로 반환’을 적절히 바꾼다.
-
final class MyClass : 상속을 허용하지 않음. (String 클래스가 대표적인 final선언 클래스)
-
final void yourFunc(int n) : 이 메소드의 오버라이딩을 허용하지 않겠다. (wait, notify, notifyall 메소드가 예)
-
- abstract 클래스
- 상속의 관계를 형성하기 위한 상위 클래스, 인스턴스화 시키기 위해서 정의한 클래스가 아닌 경우
public abstract class Friend { public void showData(){ System.out.println("데이터 보여주기"); } public abstract void showBasicInfo(); }
추상 클래스를 상속하는 하위 클래스에서는 추상 메소드를 오버라이딩해야 한다.