[아이티센 부트캠프] 실습 정리 (abstract & 다형성)

이언덕·2026년 4월 2일

아이티센 부트캠프

목록 보기
19/115
post-thumbnail

문제

먼저 문제 원본은 아래와 같다.




문제에서 실제로 구현해야 하는 조건만 다시 정리하면 이렇다.

  • mobile 패키지에 클래스를 작성한다.
  • Mobile은 abstract class로 만든다.
  • Mobile 클래스에는 mobileName, batterySize, osType 멤버변수가 필요하다.
  • Mobile 클래스에는 기본 생성자와 Mobile(String mobileName, int batterySize, String osType) 생성자가 필요하다.
  • Mobile 클래스에는 operate(int time), charge(int time)를 abstract 메서드로 선언해야 한다.
  • Ltab, Otab 클래스는 Mobile을 상속해야 한다.
  • Ltab, Otab 클래스에도 기본 생성자와 3개의 값을 받는 생성자가 필요하다.
  • Ltab
    • operate(int time) : 1분 사용 시 배터리 10 감소
    • charge(int time) : 1분 충전 시 배터리 10 증가
  • Otab
    • operate(int time) : 1분 사용 시 배터리 12 감소
    • charge(int time) : 1분 충전 시 배터리 8 증가
  • MobileTest에서 Ltab, Otab 객체를 생성한다.
  • 처음 상태를 출력한다.
  • 각 객체를 10분 충전한 뒤 다시 출력한다.
  • 각 객체를 5분 사용한 뒤 다시 출력한다.
  • 출력용 메서드 printMobile(Mobile mobile), printTitle()을 작성한다.



문제 해석

이 문제는 단순히 클래스 3개를 만드는 문제로 끝나지 않는다.
먼저 공통 속성을 가지는 부모 클래스 Mobile을 abstract로 만들고, 그다음 자식 클래스 Ltab, Otab가 이를 상속해서 각자 다른 배터리 계산 방식을 구현해야 한다.

즉 이 실습의 핵심은 공통 정보는 부모 클래스에 두고, 실제 동작 방식은 자식 클래스에서 오버라이딩으로 다르게 구현하는 흐름을 익히는 데 있다.
그리고 마지막에는 MobileTest에서 객체를 생성하고, 충전 전 상태, 충전 후 상태, 사용 후 상태를 순서대로 출력하면서 값이 실제로 어떻게 바뀌는지 확인해야 한다.

처음에는 Mobile, Ltab, Otab의 기본 틀부터 만들고, 생성자로 값이 부모 클래스까지 잘 전달되는지 먼저 확인했다.
그다음 getter를 만들어 기본 정보를 출력해 보고, 이후 setter를 추가해서 배터리 값을 수정할 준비를 했다.
마지막으로 operate()와 charge()를 구현하고, MobileTest에서 충전과 사용 결과를 출력하면서 전체 흐름을 완성했다.


즉 이 실습의 전체 흐름은 아래처럼 정리할 수 있다.

추상 클래스 작성 → 자식 클래스 상속 연결 → 생성자 작성 → getter 생성 및 기본 정보 출력 → setter 추가 → operate() / charge() 구현 → 충전 후 출력 → 사용 후 출력



풀이 순서

  1. Mobile 추상 클래스 기본 틀 작성
  2. Ltab, Otab 클래스 생성 후 Mobile 상속 연결 및 super()로 부모 생성자 호출
  3. getter를 만들고 getter를 호출해서 기본 정보 출력
  4. setter를 만들어서 부모 값을 수정할 준비하기
  5. Ltab, Otab의 operate(), charge() 구현
  6. MobileTest에서 충전 후 출력하고, 사용 후 다시 출력



자세한 풀이

1. Mobile 추상 클래스 기본 틀 작성

이 단계에서는 모든 모바일 기기의 공통 정보를 담는 부모 클래스 Mobile을 먼저 만들었다.
문제에서 Mobile이 abstract class라고 되어 있었기 때문에, 이 클래스는 직접 객체를 만드는 용도가 아니라 자식 클래스가 공통 속성과 공통 구조를 물려받는 부모 역할을 하게 된다.

역할 설명 + 코드

package mobile;

public abstract class Mobile {
	private String mobileName;
	private int batterySize;
	private String osType;
	
	public Mobile() {
		
	}
	
	public Mobile(String mobileName, int batterySize, String osType) {
		this.mobileName = mobileName;
		this.batterySize = batterySize;
		this.osType = osType;
	}

	public abstract void operate(int time);
	
	public abstract void charge(int time);
}

데이터 흐름 예상 + 코드

Ltab lphone = new Ltab("Ltab", 500, "ABC-01");
// 1. Ltab 객체 생성 시작
// 2. Ltab 생성자가 호출될 준비를 함
// 3. Ltab는 Mobile을 상속하고 있으므로 부모 생성자와 연결되어야 함

→ Mobile은 직접 객체를 생성하는 클래스가 아니라, 자식 클래스가 공통 데이터를 저장하고 공통 메서드 구조를 물려받기 위한 부모 클래스 역할을 한다.



2. Ltab, Otab 클래스 생성 후 Mobile 상속 연결 및 super()로 부모 생성자 호출

이 단계에서는 Ltab, Otab 클래스를 만들고 Mobile을 상속하도록 연결했다.
그리고 자식 생성자 안에서 super()를 호출해서, 객체 생성 시 전달한 값을 부모 클래스 Mobile의 멤버변수에 저장하도록 만들었다.

역할 설명 + 코드

Ltab.java
package mobile;

public class Ltab extends Mobile {

	public Ltab() {
		
	}
	
	public Ltab(String mobileName, int batterySize, String osType) {
		super(mobileName, batterySize, osType);
	}
	
	@Override
	public void operate(int time) {
		
	}
	
	@Override
	public void charge(int time) {
		
	}
}

Otab.java
package mobile;

public class Otab extends Mobile {

	public Otab() {
		
	}
	
	public Otab(String mobileName, int batterySize, String osType) {
		super(mobileName, batterySize, osType);
	}
	
	@Override
	public void operate(int time) {
		
	}
	
	@Override
	public void charge(int time) {
		
	}
}

데이터 흐름 + 코드

Ltab lphone = new Ltab("Ltab", 500, "ABC-01");
// 1. new Ltab(...) 실행
// 2. "Ltab", 500, "ABC-01" 값이 Ltab 생성자의 매개변수로 들어감

public Ltab(String mobileName, int batterySize, String osType) {
	super(mobileName, batterySize, osType);
	// 3. 자식 생성자가 받은 값을 부모 생성자에 전달
}

public Mobile(String mobileName, int batterySize, String osType) {
	this.mobileName = mobileName;   // 4. mobileName 저장
	this.batterySize = batterySize; // 5. batterySize 저장
	this.osType = osType;           // 6. osType 저장
}

Otab ophone = new Otab("Otab", 1000, "XYZ-20");
// 1. new Otab(...) 실행
// 2. "Otab", 1000, "XYZ-20" 값이 Otab 생성자의 매개변수로 들어감

public Otab(String mobileName, int batterySize, String osType) {
	super(mobileName, batterySize, osType);
	// 3. 자식 생성자가 받은 값을 부모 생성자에 전달
}

public Mobile(String mobileName, int batterySize, String osType) {
	this.mobileName = mobileName;   // 4. mobileName 저장
	this.batterySize = batterySize; // 5. batterySize 저장
	this.osType = osType;           // 6. osType 저장
}

→ 객체 생성 시 전달한 값은 자식 생성자에서 한 번 받고, super()를 통해 부모 생성자로 넘어가서 최종적으로 부모의 멤버변수에 저장된다.



3. getter를 만들고 기본 정보 출력

이 단계에서는 먼저 Mobile 클래스에 getter를 만들었다.
이유는 객체를 생성하면서 부모 클래스 Mobile에 저장된 mobileName, batterySize, osType 값을 꺼내서 출력해야 했기 때문이다.

그리고 MobileTest에서 printMobile() 메서드를 만들고, 그 안에서 getter를 호출해서 기본 정보를 출력했다.
즉 이 단계는 객체 생성으로 저장된 값을 getter로 꺼내서 출력까지 연결한 단계라고 보면 된다.



여기서 같이 이해해야 하는 부분이 printMobile(Mobile mobile)의 매개변수다.
처음 보면 Ltab 객체와 Otab 객체를 만들었는데 왜 매개변수를 Ltab, Otab로 받지 않고 Mobile mobile로 받는지 헷갈릴 수 있다.

이게 가능한 이유는 Ltab, Otab가 모두 부모 클래스 Mobile을 상속하고 있기 때문이다.
그리고 이렇게 부모 타입인 Mobile 매개변수 하나로 서로 다른 자식 객체를 공통으로 받는 방식은 다형성이라고 볼 수 있다.
즉, 상속으로 부모-자식 관계를 만든 뒤, 그 부모 타입으로 여러 자식 객체를 다루는 구조가 여기서 나타난 것이다.

그래서 printMobile() 메서드는 특정 자식 타입 하나만 받는 것이 아니라, Mobile을 상속한 객체라면 공통으로 받아서 처리할 수 있다.


여기서 Mobile mobile은
앞의 Mobile이 매개변수의 타입이고,
뒤의 mobile은 전달받은 객체를 메서드 안에서 사용할 이름이다.

즉 printMobile(lphone);을 호출하면 lphone 객체가 mobile이라는 이름으로 들어오고,
printMobile(ophone);을 호출하면 ophone 객체가 mobile이라는 이름으로 들어온다.
그래서 메서드 안에서는 전달된 객체를 mobile.getMobileName(), mobile.getBatterySize(), mobile.getOsType()처럼 공통 방식으로 사용할 수 있다.

역할 설명 + 코드

Mobile.java
package mobile;

public abstract class Mobile {
	private String mobileName;
	private int batterySize;
	private String osType;
	
	public Mobile() {
		
	}
	
	public Mobile(String mobileName, int batterySize, String osType) {
		this.mobileName = mobileName;
		this.batterySize = batterySize;
		this.osType = osType;
	}
	
	public String getMobileName() {
		return mobileName;
	}

	public int getBatterySize() {
		return batterySize;
	}
	
	public String getOsType() {
		return osType;
	}

	public abstract void operate(int time);
	
	public abstract void charge(int time);
}
MobileTest.java
package mobile;

public class MobileTest {

	public static void main(String[] args) {
		Ltab lphone = new Ltab("Ltab", 500, "ABC-01");
		Otab ophone = new Otab("Otab", 1000, "XYZ-20");
		
		printTitle();
		printMobile(lphone);
		printMobile(ophone);
	}

	public static void printMobile(Mobile mobile) {
		System.out.println(
			mobile.getMobileName() + "\t\t" +
			mobile.getBatterySize() + "\t\t" +
			mobile.getOsType()
		);
	}
	
	public static void printTitle() {
		System.out.println("Mobile\t\tBattery\t\tOS");
		System.out.println("----------------------------------------");
	}
}

데이터 흐름 + 코드

Ltab lphone = new Ltab("Ltab", 500, "ABC-01");
// 1. Ltab 객체 생성
// 2. "Ltab", 500, "ABC-01" 값이 부모 Mobile에 저장됨

Otab ophone = new Otab("Otab", 1000, "XYZ-20");
// 3. Otab 객체 생성
// 4. "Otab", 1000, "XYZ-20" 값이 부모 Mobile에 저장됨

printMobile(lphone);
// 5. lphone 객체가 printMobile()의 매개변수 mobile로 전달됨
// 6. 여기서 Mobile은 받는 객체의 타입이고, mobile은 메서드 안에서 사용할 변수 이름임
// 7. Ltab은 Mobile의 자식 클래스이므로 부모 타입 매개변수로 전달 가능함

public static void printMobile(Mobile mobile) {
	System.out.println(
		mobile.getMobileName() + "\t\t" +  // 8. 전달받은 객체의 mobileName 값 꺼내기
		mobile.getBatterySize() + "\t\t" + // 9. 전달받은 객체의 batterySize 값 꺼내기
		mobile.getOsType()                 // 10. 전달받은 객체의 osType 값 꺼내기
	);
	// 11. 꺼낸 값들을 한 줄로 출력
}

printMobile(ophone);
// 12. ophone 객체가 printMobile()의 매개변수 mobile로 전달됨
// 13. Otab도 Mobile의 자식 클래스이므로 부모 타입 매개변수로 전달 가능함
// 14. getMobileName(), getBatterySize(), getOsType()가 차례대로 호출됨
// 15. 부모 Mobile에 저장된 값이 출력됨

→ Ltab, Otab 객체를 만들면 전달한 값은 부모 클래스 Mobile에 저장된다.
→ printMobile()을 호출하면 자식 객체가 부모 타입 Mobile 매개변수로 전달된다.
→ 이때 Mobile mobile에서 Mobile은 타입, mobile은 메서드 안에서 사용할 변수 이름이다.
→ 그래서 Ltab 객체가 들어오든 Otab 객체가 들어오든, 메서드 안에서는 모두 mobile이라는 공통 이름으로 다룰 수 있다.
→ 그 안에서 getMobileName(), getBatterySize(), getOsType()를 호출해서 저장된 값을 꺼내고 출력한다.
→ 즉 이 구조는 부모 타입 하나로 여러 자식 객체를 공통 처리하는 다형성 구조를 보여주는 부분이다.
→ 꺼낸 값이 출력되면서 기본 정보가 정상적으로 저장되었는지 확인할 수 있다.



4. setter를 만들어서 부모 값을 수정할 준비하기

이 단계에서는 Mobile 클래스에 setter를 추가했다.
다음 단계에서 Ltab, Otab의 operate()와 charge()를 구현할 때 부모 클래스 안에 있는 batterySize 값을 수정해야 했기 때문이다.

처음에는 자식 클래스에서 batterySize를 직접 바꾸면 될 것 같았지만, 이 값은 부모 클래스 Mobile의 private 멤버변수라서 자식 클래스에서 바로 접근할 수 없었다.
그래서 부모 클래스에 setter를 만들어 두고, 자식 클래스는 그 메서드를 통해 값을 수정하도록 준비했다.

이번 실습에서 가장 많이 헷갈렸던 부분도 여기였다.
getter와 setter를 그냥 외워서 붙이는 게 아니라, 왜 부모 클래스에 있어야 하고 왜 자식 클래스가 그 메서드를 통해 값을 다뤄야 하는지 흐름으로 이해하는 과정이 필요했다.

역할 설명 + 코드

Mobile.java
package mobile;

public abstract class Mobile {
	private String mobileName;
	private int batterySize;
	private String osType;
	
	public Mobile() {
		
	}
	
	public Mobile(String mobileName, int batterySize, String osType) {
		this.mobileName = mobileName;
		this.batterySize = batterySize;
		this.osType = osType;
	}
	
	public String getMobileName() {
		return mobileName;
	}
	
	public int getBatterySize() {
		return batterySize;
	}
	
	public String getOsType() {
		return osType;
	}
	
	public void setMobileName(String mobileName) {
		this.mobileName = mobileName;
	}

	public void setBatterySize(int batterySize) {
		this.batterySize = batterySize;
	}
	
	public void setOsType(String osType) {
		this.osType = osType;
	}

	public abstract void operate(int time);
	
	public abstract void charge(int time);
}

데이터 흐름 + 코드

setBatterySize(600);
// 1. setBatterySize()가 호출됨
// 2. 600 값이 매개변수 batterySize로 들어옴

public void setBatterySize(int batterySize) {
	this.batterySize = batterySize;
	// 3. 전달받은 값을 부모 Mobile의 batterySize에 저장
}

setMobileName("Ltab");
// 1. setMobileName()가 호출됨
// 2. "Ltab" 값이 매개변수 mobileName으로 들어옴

public void setMobileName(String mobileName) {
	this.mobileName = mobileName;
	// 3. 전달받은 값을 부모 Mobile의 mobileName에 저장
}

setOsType("ABC-01");
// 1. setOsType()가 호출됨
// 2. "ABC-01" 값이 매개변수 osType으로 들어옴

public void setOsType(String osType) {
	this.osType = osType;
	// 3. 전달받은 값을 부모 Mobile의 osType에 저장
}

→ 이 단계에서는 자식 클래스가 부모의 멤버변수를 직접 수정하는 것이 아니라,
→ 부모가 제공하는 setter를 통해 값을 수정할 수 있도록 준비한 것이다.
→ 특히 나중에 배터리 값을 바꿀 때는 setBatterySize()가 핵심 역할을 하게 된다.



5. Ltab, Otab의 operate(), charge() 구현

이 단계에서는 Ltab과 Otab의 배터리 계산 기능을 구현했다.
두 클래스 모두 operate()는 사용 시간만큼 배터리를 감소시키고, charge()는 충전 시간만큼 배터리를 증가시키는 구조다.
즉 전체 흐름은 같고, 클래스마다 분당 변화량만 다르게 적용된다.

  • Ltab
    • 사용: 1분당 10 감소
    • 충전: 1분당 10 증가

  • Otab
    • 사용: 1분당 12 감소
    • 충전: 1분당 8 증가

여기서 중요한 점은 두 클래스 모두 부모 클래스 Mobile의 batterySize를 직접 바꾸는 것이 아니라,
먼저 getBatterySize()로 현재 값을 읽고, 계산한 뒤 setBatterySize()로 다시 저장한다는 점이다.

역할 설명 + 코드

Ltab.java
package mobile;

public class Ltab extends Mobile {

	public Ltab() {
		
	}
	
	public Ltab(String mobileName, int batterySize, String osType) {
		super(mobileName, batterySize, osType);
	}
	
	@Override
	public void operate(int time) {
		setBatterySize(getBatterySize() - (time * 10));
	}
	
	@Override
	public void charge(int time) {
		setBatterySize(getBatterySize() + (time * 10));
	}
}
Otab.java
package mobile;

public class Otab extends Mobile {

	public Otab() {
		
	}
	
	public Otab(String mobileName, int batterySize, String osType) {
		super(mobileName, batterySize, osType);
	}
	
	@Override
	public void operate(int time) {
		setBatterySize(getBatterySize() - (time * 12));
	}

	@Override
	public void charge(int time) {
		setBatterySize(getBatterySize() + (time * 8));
	}
}

데이터 흐름 + 코드

lphone.charge(10);
// 1. lphone 객체의 charge(10) 호출

@Override
public void charge(int time) {
	setBatterySize(getBatterySize() + (time * 10));
	// 2. getBatterySize()로 현재 batterySize 값 읽기
	// 3. time * 10 계산하기
	// 4. 현재값 + 계산값 수행하기
	// 5. setBatterySize()로 다시 저장하기
}

// 실제 값 흐름 예시
// 현재 batterySize = 500
// charge(10) 호출
// 10 * 10 = 100
// 500 + 100 = 600
// batterySize가 600으로 저장됨

lphone.operate(5);
// 1. lphone 객체의 operate(5) 호출

@Override
public void operate(int time) {
	setBatterySize(getBatterySize() - (time * 10));
	// 2. getBatterySize()로 현재 batterySize 값 읽기
	// 3. time * 10 계산하기
	// 4. 현재값 - 계산값 수행하기
	// 5. setBatterySize()로 다시 저장하기
}

// 실제 값 흐름 예시
// 현재 batterySize = 600
// operate(5) 호출
// 5 * 10 = 50
// 600 - 50 = 550
// batterySize가 550으로 저장됨

ophone.charge(10);
// 1. ophone 객체의 charge(10) 호출

@Override
public void charge(int time) {
	setBatterySize(getBatterySize() + (time * 8));
	// 2. getBatterySize()로 현재 batterySize 값 읽기
	// 3. time * 8 계산하기
	// 4. 현재값 + 계산값 수행하기
	// 5. setBatterySize()로 다시 저장하기
}

// 실제 값 흐름 예시
// 현재 batterySize = 1000
// charge(10) 호출
// 10 * 8 = 80
// 1000 + 80 = 1080
// batterySize가 1080으로 저장됨

ophone.operate(5);
// 1. ophone 객체의 operate(5) 호출

@Override
public void operate(int time) {
	setBatterySize(getBatterySize() - (time * 12));
	// 2. getBatterySize()로 현재 batterySize 값 읽기
	// 3. time * 12 계산하기
	// 4. 현재값 - 계산값 수행하기
	// 5. setBatterySize()로 다시 저장하기
}

// 실제 값 흐름 예시
// 현재 batterySize = 1080
// operate(5) 호출
// 5 * 12 = 60
// 1080 - 60 = 1020
// batterySize가 1020으로 저장됨

→ Ltab과 Otab는 모두 현재 값 읽기 → 계산하기 → 다시 저장하기 흐름으로 동작한다.
→ 차이는 오직 시간당 변화량만 다르다는 점이다.



6. MobileTest에서 충전 후 출력하고, 사용 후 다시 출력

이 단계에서는 MobileTest에서 charge(10)을 호출한 뒤 결과를 출력하고,
이어서 operate(5)를 호출한 뒤 다시 결과를 출력했다.
즉 이 단계는 지금까지 만든 기능이 실제로 제대로 동작하는지 최종적으로 확인하는 단계다.

역할 설명 + 코드

MobileTest.java
package mobile;

public class MobileTest {

	public static void main(String[] args) {
		Ltab lphone = new Ltab("Ltab", 500, "ABC-01");
		Otab ophone = new Otab("Otab", 1000, "XYZ-20");
		
		printTitle();
		printMobile(lphone);
		printMobile(ophone);
		
		lphone.charge(10);
		ophone.charge(10);
		
		System.out.println();
		System.out.println("[ 10분 충전 ]");
		printTitle();
		printMobile(lphone);
		printMobile(ophone);

		lphone.operate(5);
		ophone.operate(5);

		System.out.println();
		System.out.println("[ 5분 통화 ]");
		printTitle();
		printMobile(lphone);
		printMobile(ophone);
	}

	public static void printMobile(Mobile mobile) {
		System.out.println(
			mobile.getMobileName() + "\t\t" +
			mobile.getBatterySize() + "\t\t" +
			mobile.getOsType()
		);
	}

	public static void printTitle() {
		System.out.println("Mobile\t\tBattery\t\tOS");
		System.out.println("----------------------------------------");
	}
}

데이터 흐름 + 코드

lphone.charge(10);
// 1. Ltab의 charge(10) 호출
// 2. 현재 batterySize 500 읽기
// 3. 10 * 10 = 100 계산
// 4. 500 + 100 = 600 저장

ophone.charge(10);
// 5. Otab의 charge(10) 호출
// 6. 현재 batterySize 1000 읽기
// 7. 10 * 8 = 80 계산
// 8. 1000 + 80 = 1080 저장

printMobile(lphone);
// 9. lphone 객체 전달
// 10. getMobileName(), getBatterySize(), getOsType() 호출
// 11. Ltab, 600, ABC-01 출력

printMobile(ophone);
// 12. ophone 객체 전달
// 13. getMobileName(), getBatterySize(), getOsType() 호출
// 14. Otab, 1080, XYZ-20 출력

lphone.operate(5);
// 15. Ltab의 operate(5) 호출
// 16. 현재 batterySize 600 읽기
// 17. 5 * 10 = 50 계산
// 18. 600 - 50 = 550 저장

ophone.operate(5);
// 19. Otab의 operate(5) 호출
// 20. 현재 batterySize 1080 읽기
// 21. 5 * 12 = 60 계산
// 22. 1080 - 60 = 1020 저장

printMobile(lphone);
// 23. lphone 객체 전달
// 24. getMobileName(), getBatterySize(), getOsType() 호출
// 25. Ltab, 550, ABC-01 출력

printMobile(ophone);
// 26. ophone 객체 전달
// 27. getMobileName(), getBatterySize(), getOsType() 호출
// 28. Otab, 1020, XYZ-20 출력

→ 먼저 charge(10)을 호출해서 충전 후 값을 확인한다.
→ 그다음 operate(5)를 호출해서 사용 후 값을 다시 확인한다.
→ 이렇게 처음 상태, 충전 후 상태, 사용 후 상태가 순서대로 출력되면서 문제에서 요구한 전체 결과를 확인할 수 있다.



최종 코드

Mobile.java

package mobile;

public abstract class Mobile {
	private String mobileName;
	private int batterySize;
	private String osType;
	
	public Mobile() {
		
	}
	
	public Mobile(String mobileName, int batterySize, String osType) {
		this.mobileName = mobileName;
		this.batterySize = batterySize;
		this.osType = osType;
	}
	
	public String getMobileName() {
		return mobileName;
	}
	
	public int getBatterySize() {
		return batterySize;
	}
	
	public String getOsType() {
		return osType;
	}
	
	public void setMobileName(String mobileName) {
		this.mobileName = mobileName;
	}
	
	public void setBatterySize(int batterySize) {
		this.batterySize = batterySize;
	}
	
	public void setOsType(String osType) {
		this.osType = osType;
	}

	public abstract void operate(int time);
	
	public abstract void charge(int time);
}

Ltab.java

package mobile;

public class Ltab extends Mobile {

	public Ltab() {
		
	}
	
	public Ltab(String mobileName, int batterySize, String osType) {
		super(mobileName, batterySize, osType);
	}
	
	@Override
	public void operate(int time) {
		setBatterySize(getBatterySize() - (time * 10));
	}
	
	@Override
	public void charge(int time) {
		setBatterySize(getBatterySize() + (time * 10));
	}
}

Otab.java

package mobile;

public class Otab extends Mobile {

	public Otab() {
		
	}
	
	public Otab(String mobileName, int batterySize, String osType) {
		super(mobileName, batterySize, osType);
	}
	
	@Override
	public void operate(int time) {
		setBatterySize(getBatterySize() - (time * 12));
	}
	
	@Override
	public void charge(int time) {
		setBatterySize(getBatterySize() + (time * 8));
	}
}

MobileTest.java

package mobile;

public class MobileTest {

	public static void main(String[] args) {
		Ltab lphone = new Ltab("Ltab", 500, "ABC-01");
		Otab ophone = new Otab("Otab", 1000, "XYZ-20");
		
		printTitle();
		printMobile(lphone);
		printMobile(ophone);
		
		lphone.charge(10);
		ophone.charge(10);
		
		System.out.println();
		System.out.println("[ 10분 충전 ]");
		printTitle();
		printMobile(lphone);
		printMobile(ophone);
		
		lphone.operate(5);
		ophone.operate(5);
		
		System.out.println();
		System.out.println("[ 5분 통화 ]");
		printTitle();
		printMobile(lphone);
		printMobile(ophone);
	}
	
	public static void printMobile(Mobile mobile) {
		System.out.println(
			mobile.getMobileName() + "\t\t" +
			mobile.getBatterySize() + "\t\t" +
			mobile.getOsType()
		);
	}
	
	public static void printTitle() {
		System.out.println("Mobile\t\tBattery\t\tOS");
		System.out.println("----------------------------------------");
	}
}

실습하면서 확인한 점

  • abstract class는 공통 속성과 공통 구조를 정의하고, 실제 동작은 자식 클래스에서 구현하게 만들 수 있다.
  • 자식 클래스가 부모를 상속해도 부모의 private 멤버변수에는 직접 접근할 수 없다.
  • 그래서 부모 클래스의 값을 읽을 때는 getter, 수정할 때는 setter가 필요하다.
  • 생성자에서 super()를 호출하면 자식이 받은 값을 부모 멤버변수에 전달할 수 있다.
  • Ltab, Otab는 같은 부모를 상속하지만 operate()와 charge()의 계산식은 다르게 구현할 수 있다.
  • printMobile(Mobile mobile)처럼 부모 타입으로 여러 자식 객체를 받아 처리하는 다형성 구조도 확인할 수 있었다.
  • 이번 실습에서는 특히 getter, setter를 왜 써야 하는지 가장 많이 헷갈렸는데, 단순히 외워서 쓰는 것이 아니라 부모의 private 값을 자식이 메서드로 다룬다는 흐름으로 이해하는 것이 중요했다.

0개의 댓글