연습 문제 (6) 답지
각 문제의 풀이. 전)/후)는 코드 수정 형식.
1
1-a)
- a) 런타임 오류 (NullPointerException)
- 참조형 멤버 변수
label은 초기화하지 않으면 기본값이 null getLabelLength()에서this.label.length()로 null을 역참조 → NullPointerException
- 참조형 멤버 변수
- b)
label을 유효한 값으로 초기화 (선언 시 또는 생성자에서)전) private String label; 후) private String label = "";- (고친 경우 출력)
0(""의 길이 )
- (고친 경우 출력)
1-b)
- a) 문제 없음
- c) 출력
10.0int→long→double은 작은 자료형에서 큰 자료형으로의 자동(암시적) 형변환이라 캐스팅이 필요 없음d는double10.0 → 출력은10.0
1-c)
- a) 컴파일 오류
x가final매개변수라 메서드 안에서 다시 대입할 수 없음
- b)
전) x = x + 1; return x; 후) return x + 1; - c) (고친 경우 출력)
6- 5 + 1 = 6
2
- 출력
20Stopwatch(10)→super(10)→seconds=10tick()은super.seconds += 5→ 상속받은(부모의)seconds를 5 증가- 두 번 호출 → 10 → 15 → 20
seconds는protected라 자식에서super.seconds로 접근 가능
3
- 클래스(class): 개체를 만들 때 쓰는 명세서(설계도). 어떤 속성(상태)과 동작을 가질지 정의함. 개체는 반드시 클래스로부터 만들어짐
- 개체(object, 인스턴스): 클래스라는 명세서로부터 실제로 만들어진 실체. 메모리에 올라가며 각자 자신의 상태값을 가짐
- 비유: 클래스는 붕어빵 틀(또는 설계도/레시피), 개체는 그 틀로 찍어낸 붕어빵 하나하나. 틀 하나로 여러 개체를 만들 수 있음
- 클래스로부터 개체를 만드는 행위를 인스턴스화(instantiation) 라고 함
4
- 메모리 구조
- 상속: 자식 개체를 만들면 부모 부분까지 하나의 연속된 메모리 덩어리로 생성됨
- 컴포지션: 부품(멤버) 개체를 각각
new하므로 메모리 덩어리가 여러 개로 흩어져 있음
- 성능 영향
- CPU 캐시는 메모리를 캐시 라인(연속된 블록) 단위로 읽음. 상속 개체는 연속된 한 덩어리라 한 번에 캐시에 올라갈 확률이 높아 유리
- 컴포지션 개체는 부품들이 흩어져 있어 캐시에 올릴 때 메모리(버스)에 여러 번 접근해야 할 수 있어 불리
- 또한 컴포지션은
new/해제 횟수가 많아 메모리 할당·해제 비용도 더 큼
- 결론: 확장성(유연성)은 컴포지션이 좋지만, 성능은 상속이 유리
5
5-a)
- a) 문제 없음
- c) 출력
3Grade.B의point는 3 →getPoint()= 3
5-b)
- a) 컴파일 오류
enum은new로 인스턴스를 만들 수 없음 (정해진 상수만 존재, 생성자는 암시적으로 private)
- b) 미리 정의된 상수를 사용
전) Grade g = new Grade(5); 후) Grade g = Grade.A;- (고친 경우 출력)
4
- (고친 경우 출력)
5-c)
- a) 문제 없음
- c) 출력
excellentg가Grade.A→case A가 실행되고break로 종료- (참고: enum을 switch의 case에 쓸 때는
Grade.A가 아니라A처럼 상수 이름만 적음)
6
- 출력
3w1,w2가 같은Counter개체(shared)의 참조를 받아 보관함 (참조 공유)value기본값 0 →w1.work()(1),w2.work()(2),w2.work()(3)- 셋 다 같은 개체를 증가시키므로
shared.getValue()= 3
7
- 출력
person studentnew Person()처럼 부모 클래스도 독립적으로 인스턴스화 가능 → role=“person”new Student()는 먼저 암시적super()(Person 생성자, role=“person”)가 실행된 뒤 자식 생성자가 role=“student”로 덮어씀role은protected라 자식 생성자에서 접근·수정 가능
8
예시 답안
// Animal.java
package academy.pocu.comp2500;
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void eat() {
System.out.println(this.name + " is eating");
}
}
// Dog.java
package academy.pocu.comp2500;
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
public void bark() {
System.out.println("Bark!");
}
}
// Cat.java
package academy.pocu.comp2500;
public class Cat extends Animal {
public Cat(String name) {
super(name);
}
public void meow() {
System.out.println("Meow!");
}
}- 포인트
- 두 클래스에 중복되던
name,getName(),eat()을 부모Animal로 올림 - 자식은
super(name)으로 부모 생성자를 호출해 이름을 초기화 - 자식 고유 동작(
bark(),meow())만 각자 남김 name은protected로 두면 부모의eat()에서 사용 가능 (private로 두고getName()을 쓰는 것도 가능)
- 두 클래스에 중복되던
9
private 메서드의 용도 (예시)
- private 메서드는 같은 클래스 안에서만 호출할 수 있음
- 여러 public 메서드에 중복되는 내부 로직을 private 메서드로 분리해 중복을 없애고 재사용함
- 외부에 노출할 필요 없는 내부 구현 세부사항을 숨김(캡슐화) → 클래스의 공개 인터페이스를 깔끔하게 유지
10
- 모든 클래스는
Object클래스를 상속함 (컴파일러가extends Object를 암시적으로 붙임). 그래서 모든 개체는getClass(),toString(),equals()같은Object의 메서드를 가짐 - RTTI(run time type identification): 실행 중에 개체의 실제 타입 정보를 알아내는 기능.
getClass()가 대표적이며,getClass().getName()은 패키지를 포함한 클래스 이름을 돌려줘 로그 등에 자주 활용됨 - 단점: 실행 중에 타입 정보를 알아내는 추가 비용이 들어, 성능이나 메모리가 중요한 경우에는 부적합함 (C/C++ 등에서는 RTTI를 지원하지 않거나 잘 쓰지 않음)
11
- 출력
60 20- 중복되던 합 계산을
private메서드sum()으로 분리해getTotal()과getAverage()가 함께 사용 - sum = 10 + 20 + 30 = 60 →
getTotal()= 60 getAverage()= 60 / 3 = 20
- 중복되던 합 계산을