JAVA
자바 기초 : 상속
- -
핵심개념
- 상속 : 객체지향프로그래밍에서 부모클래스의 멤버를 자식클래스에게 물려주는 것. 중복되는 코드를 줄여주며 유지 보수시간을 최소화한다는 장점이 있다.

- 클래스 상속 : 자식클래스 선언 시 어떤 부모 클래스를 상속받을 지 선택한뒤 extends 뒤에 부모클래스를 기술한다.
ex) class 자식클래스 extends 부모클래스 {
//필드
//생성자
//메소드
} - 상속의 특징
1. 한개의 부모클래스만 상속받을 수 있다.
2. 부모클래스에서 private접근 제한을 갖는 필드와 메소드는 상속대상에서 제외된다.
3. 부모와 자식 클래스가 다르 패키지에 존재할 경우 default접근 제한을 갖는 필드와 메소드 역시 상속대상에서 제외된다.
public class CellPhone {
//필드 String model; String color; //생성자 //메소드 void powerOn() {System.out.println("전원을 켭니다.");} void powerOff() {System.out.println("전원을 끕니다.");} void bell() {System.out.println("벨이 울립니다.");} void sendVoice(String message) {System.out.println("본인 : " + message);} void receiveVoice(String message) {System.out.println("상대방 : " + message);} void hangUp() {System.out.println("전화를 끊습니다.");} } ------------------------------------------------------------------------------------------------------------------ public class DmbCellPhone extends CellPhone {
//필드 int channel; //생성자 DmbCellPhone(String model, String color, int channel){ this.model = model; this.color = color; this.channel = channel; } // 메소드 void turnOnDmb() { System.out.println("채널 : " + channel + "번 DMB 방송 수신을 시작합니다."); } void changeChannelDmb(int channel) { this.channel = channel; System.out.println("채널 : " + channel + "번으로 바꿉니다."); } void turnOffDmb() { System.out.println("DMB 방송 수신을 멈춥니다."); } } ------------------------------------------------------------------------------------------------------------------ public class DmbCellPhoneEx {
public static void main(String[] args) { //DmbCellPhone 객체 생성 DmbCellPhone dmbCellPhone = new DmbCellPhone("자바폰", "화이트", 10); //CellPhone 클래스로부터 상속받은 필드 System.out.println("모델 : " + dmbCellPhone.model); System.out.println("색상 : " + dmbCellPhone.color); //DmbCellPhone 클래스의 필드 System.out.println("채널 : " + dmbCellPhone.channel); //CellPhone 클래스로부터 상속받은 메소드 호출 dmbCellPhone.powerOn(); dmbCellPhone.bell(); dmbCellPhone.sendVoice("여보세요"); dmbCellPhone.receiveVoice("안녕하세요. 저는 김땡땡입니다."); dmbCellPhone.sendVoice("전화 잘못걸었습니다."); dmbCellPhone.hangUp(); //DmbCellPhone 클래스의 메소드 호출 dmbCellPhone.turnOnDmb(); dmbCellPhone.changeChannelDmb(10); dmbCellPhone.turnOffDmb(); } } 모델 : 자바폰
색상 : 화이트 채널 : 10 전원을 켭니다. 벨이 울립니다. 본인 : 여보세요 상대방 : 안녕하세요. 저는 김땡땡입니다. 본인 : 전화 잘못걸었습니다. 전화를 끊습니다. 채널 : 10번 DMB 방송 수신을 시작합니다. 채널 : 10번으로 바꿉니다. DMB 방송 수신을 멈춥니다. |
- 부모 생성자 호출 : 부모객체가 먼저 생성되고 그 다음 자식 객체가 생성된다. 모든 객체는 클래스의 생성자를 호출해야만 생성된다. 부모생성자도 마찬가지인데, 부모 생성자는 자식 생성자의 맨 첫 줄에서 호출된다.
ex)명시적으로 부모 생성자를 호출하지 않은 경우
DmbCellPhone dmbCellPhone = new DmbCellPhone();
-----------------------------------
public DmbCellPhone(){
super(); //부모의 기본 생성자를 호출. 직접 코딩하지 않아도 컴파일러가 자동으로 넣어준다.
------------------------------------
public CellPhone() { //기본생성자
}
//호출은 자식생성자가 먼저 되었지만, 종료는 부모생성자가 먼저 끝나고 자식 생성자가 종료되므로 부모객체가 먼저 생성되고 자식 객체가 생성된다고 볼 수 있다.
ex)명시적으로 부모 생성자를 호출하려는 경우
자식클래스(매개변수선언,...){
super(매개값,...); //매개값의 타입과 일치하는 부모 생상자를 호출. 없다면 컴파일 에러발생
}
public class People {
public String name; public String ssn; //생성자(name과 ssn을 매개값으로 받아 객체 생성 public People(String name, String ssn) { this.name = name; this.ssn = ssn; } } --------------------------------------------------------------------------- public class Student extends People {
//기본생성자 //public Student() { super(); } public int studentNo; //자식클래스 생성 시 부모 클래시의 매개변수를 받아야함 //super()로 People 클래스의 생성자 호출 public Student(String name, String ssn, int studentNo) { super(name, ssn); this.studentNo = studentNo; } } --------------------------------------------------------------------------- public class StudentEx {
public static void main(String[] args) { Student student = new Student("김땡떙", "121212-9879879", 1); System.out.println("이름 : " + student.name); System.out.println("주민번호 : " + student.ssn); System.out.println("학생번호 : " + student.studentNo); } } 이름 : 김땡떙
주민번호 : 121212-9879879 학생번호 : 1 |
- 메소드 재정의 : 자식클래스에서 부모 클래스의 메소드를 재정의 하는 것. 부모클래스의 메소드가 자식클래스에서 사용하기에 부적합 한 경우 상속된 일부 메소드를 자식 클래스에서 다시 수정하여 사용한다. 메소드가 재정의될 경우 부모 객체 메소드가 숨겨지며, 자식 객체에서 메소드를 호춣면 재정의된 자식 메소드가 호출된다.
- 메소드 재정의 방법 : 메소드를 재정의할 때 다음과 같은 규칙에 주의해서 작성.
1. 부모 메소드와 동일한 시그니처(리턴타입, 메소드 이름, 매개변수목록)을 가져야한다.
2. 접근 제한을 더 강하게(좁게) 재정의할 수 없다.
ex)부모가 public일 경우 자식이 default 또는 private로 할 수 없다.
3. 새로운 예외를 throw할 수 없다.
public class Calculator {
double areaCircle(double r) { System.out.println("Calculator 객체의 areaCircle() 실행"); return 3.14159*r*r; } } ----------------------------------------------------------------------------- public class Computer extends Calculator {
@Override//생략해도되지만, 붙여주면 재정의 여부를 컴파일러가 확인하기 때문에 실수를 줄인다. double areaCircle(double r) { System.out.println("Computer객체의 areaCircle() 실행"); return Math.PI*r*r; //Calculator에서는 파이를 3.14159로 계산하엿지만, 좀 더 정밀한 처리를 위해 Math.PI 상수로 재정의 //Math는 자바 표준 API이다. } } ----------------------------------------------------------------------------- public class ComputerEx {
public static void main(String[] args) { int r = 10; Calculator calculator = new Calculator(); System.out.println("원면적 : " + calculator.areaCircle(r)); System.out.println(); Computer computer = new Computer(); System.out.println("원면적 : " + computer.areaCircle(r)); } } Calculator 객체의 areaCircle() 실행
원면적 : 314.159 Computer객체의 areaCircle() 실행 원면적 : 314.1592653589793 |
- 부모 메소드 호출 : 자식 클래스 내부에서 재정의된 부모 클래스의 메소드를 호출해야하는 경우 명시적으로 super 키워드를 붙여 부모 메소드를 호출 할 수 있다.
ex) super.부모메소드();
public class Airplane {
public void land() { System.out.println("착륙합니다."); } public void fly() { System.out.println("일반 비행합니다."); } public void takeOff() { System.out.println("이륙합니다."); } } ------------------------------------------------------------ public class SupersonicAirplane extends Airplane {
public static final int NORMAL = 1; public static final int SUPERSONIC = 2; public int flyMode = NORMAL; @Override public void fly() { if(flyMode == SUPERSONIC) { System.out.println("초음속 비행합니다."); }else { //Airplane 객체의 fly 메소드 호출 super.fly(); } } } ------------------------------------------------------------ public class SupersonicAirplaneEx {
public static void main(String[] args) { SupersonicAirplane sa = new SupersonicAirplane(); sa.takeOff(); sa.fly(); sa.flyMode = SupersonicAirplane.SUPERSONIC; sa.fly(); sa.flyMode = SupersonicAirplane.NORMAL; sa.fly(); sa.land(); } } 이륙합니다.
일반 비행합니다. 초음속 비행합니다. 일반 비행합니다. 착륙합니다. |
- final클래스와 final메소드 : final키워드는 해당 선언이 최종상태이며 수정될 수 없음을 의미한다. 필드를 선언할 때 final을 작성하면 초기값 설정 후 더이상 값을 변경할 수 없다는 것을 의미한다. 반면 클래스 및 메소드 선언 시 final키워드를 사용하면 상속과 관련된 의미를 지닌다. 클래스에서의 final은 상속할 수 없다는 의미를 메소드에서의 final은 재정의 할 수 없다는 의미를 가진다.
- 상속할 수 없는 final 클래스 : 최종적인 클래스이므로 상속할 수 없다. 즉, 부모클래스가 될 수 없어 자식클래스를 만들 수 없다는 것이다.
ex) public final class String {...}
--------------------------------------------
public final class NewString extends String {...} (x) - 재정의할 수 없는 final 메소드 : 최종적인 메소드이므로 재정의할 수 없다. 즉, 부모클래스에서 선언된 final메소드는 자식클래스에서 재정의 할 수 없다는 것이다.
public class Car {
//필드 public int speed; //메소드 public void speedUp() { speed +=1; } //final 메소드 public final void stop() { System.out.println("차를 멈춤"); speed = 0; } } ------------------------------------------------- public class SportsCar extends Car {
@Override public void speedUp() { speed += 10; } /*재정의할 수 없다. public void stop() { System.out.println("스포츠카를 멈춤"); speed = 0; }*/ } |
- 상속에서의 protected 접근제한자 : 같은 패키지에서는 default와 같이 접근제한이 없지만, 다른 패키지에서는 자식 클래스만 접근이 가능하다.
package ch07.sec01.ex07.pack1;
public class A { //protected : 같은 패키지 또는 자식클래스에서 사용가능 protected String field; //필드 protected A() { //생성자 } protected void method() { //메소드 } } ----------------------------------------------------------------------- package ch07.sec01.ex07.pack1;
//A와 같은 패키지 public class B { public void method() { A a = new A(); a.field = "Value"; a.method(); } } ----------------------------------------------------------------------- package ch07.sec01.ex07.pack2;
import ch07.sec01.ex07.pack1.A; //A와 다른패키지이므로 자식클래스만 사용가능 public class C extends A{ public C() { super(); this.field = "Value"; this.method(); } } package ch07.sec01.ex07.pack2;
//다른패키지, 자식패키지x이므로 사용 불가 public class D { public void method() { /*A a = new A(); a.field = "Value"; a.method();*/ } } |
*Tip : Override할 메소드를 입력 후 ctrl + space를 하면 쉽게 메소드 재정의 가능
Contents
소중한 공감 감사합니다