Java 클래스·상속·다형성
쉽게 말하면
Java 코드 문제는 주로 상속과 오버라이딩을 물어요. 자식 객체를 부모 타입 변수에 담아도, 메서드를 부르면 자식이 다시 정의한 메서드가 실행돼요. 하지만 변수(필드)는 변수 타입(부모) 것을 써요. 생성자는 부모 것이 먼저 실행되고 자식 것이 나중에 실행돼요. static이 붙은 변수는 객체가 몇 개든 하나만 있어서 모두가 함께 써요.
시험용 정의
Java는 객체지향 언어로 모든 코드는 클래스 안에 있다. 생성자는 클래스 이름과 같고 반환형이 없으며 객체 생성 때 실행된다. 자식 생성자는 첫 줄에서 super()로 부모 생성자를 먼저 호출한다(생략하면 자동). 접근 제어자: public(어디서나), protected(같은 패키지 + 자식), default(같은 패키지), private(같은 클래스). static 멤버는 클래스에 하나만 있어 모든 객체가 공유하고 클래스 이름으로 부른다. 상속은 extends(클래스는 단일 상속), implements(인터페이스는 여러 개 구현 가능)로 한다. 오버라이딩된 메서드는 부모 타입 변수로 불러도 자식 것이 실행된다(동적 바인딩). 추상 클래스(abstract)는 객체를 만들 수 없고 추상 메서드를 자식이 구현한다. 인터페이스는 추상 메서드와 상수의 모음이다. final 클래스는 상속, final 메서드는 오버라이딩, final 변수는 값 변경이 안 된다.
비유로 이해하기
'운전해!'라고 부르면(메서드 호출) 운전석에 앉은 실제 사람(객체)의 방식대로 운전한다. 명찰(변수 타입)에 '부모'라고 적혀 있어도 운전 실력은 실제 사람 것이다. 하지만 명찰에 적힌 이름(필드)은 명찰을 보고 읽는다.
자세히
먼저 알아 둘 말
| 말 | 뜻 |
|---|---|
| 생성자 | 객체를 만들 때 자동으로 실행되는 초기화 메서드 |
| super | 부모 클래스를 가리킨다. super() 부모 생성자, super.x 부모 필드 |
| this | 현재 객체 자신 |
| static | 객체가 아니라 클래스에 속하는 멤버. 하나만 존재 |
| 업캐스팅 | 자식 객체를 부모 타입 변수에 담는 것 (Parent p = new Child()) |
| 동적 바인딩 | 실행 시점에 실제 객체를 보고 호출할 메서드를 정하는 것 |
예제 1: 상속과 오버라이딩
class Parent {
static int count = 0;
int x = 1;
Parent() { count++; System.out.println("P"); }
void show() { System.out.println("Parent " + x); }
}
class Child extends Parent {
int x = 2;
Child() { super(); System.out.println("C"); }
void show() { System.out.println("Child " + x + " " + super.x); super.show(); }
}
Parent p = new Child(); // P, C (부모 생성자 먼저)
p.show(); // Child 2 1 / Parent 1
System.out.println(p.x + " " + Parent.count); // 1 1
new Child(); // P, C
System.out.println(Parent.count); // 2- p.show()는 실제 객체 Child의 메서드
- p.x는 변수 타입 Parent의 필드 → 1
- count는 static이라 객체 두 개가 함께 쓴다 → 2
예제 2: 오버로딩, 문자열, 예외
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b + 0.5; }
int add(int a, int b, int c) { return a + b + c; }
// add(1, 2) → 3, add(1.0, 2.0) → 3.5, add(1, 2, 3) → 6
String s1 = "java", s2 = "java", s3 = new String("java");
// s1 == s2 → true (같은 상수), s1 == s3 → false (다른 객체), s1.equals(s3) → true
System.out.println("A" + 1 + 2); // A12 (문자열 뒤는 이어 붙이기)
System.out.println(1 + 2 + "A"); // 3A (앞에서부터 계산)
try { System.out.println(10 / 0); }
catch (ArithmeticException e) { System.out.println("E"); }
finally { System.out.println("F"); } // E, F기출에서 더 나온 것
| 말 | 뜻 |
|---|---|
| 가비지 컬렉터 | 참조를 잃어 더 이상 쓰지 않는 객체를 힙에서 자동으로 지우는 모듈 |
| 컴파일 오류 | 문법이 틀리면 실행 전에 컴파일 오류(Unresolved compilation problem)가 난다 |
| 대입 연산자 우선순위 | = 는 우선순위가 가장 낮다 |
| 접근 제어자 | public(어디서나), protected(같은 패키지와 상속받은 클래스), default(같은 패키지), private(같은 클래스 안) |
| 기본 자료형 크기 | byte 1, short 2, int 4, long 8바이트. char는 문자 하나(2바이트), 여러 글자는 String |
| 출력 메서드 | System.out.print(줄 안 바꿈), println(줄 바꿈), printf(형식 지정) |
시험에 이렇게 나와요
- 접근 제어자 → public·protected·default·private (package, internal은 아님)
- 정수형 크기 → byte 1, short 2, int 4, long 8바이트
- 출력 메서드 → System.out.print·println·printf
- 코드 실행 결과 → 상속·오버라이딩·static을 따라가며 값 추적
- char → 문자 하나만 저장 (여러 글자는 String)
확인 문제
Q1. Parent p = new Child();에서 Child가 show()를 오버라이딩했다. p.show()를 실행하면?
- Child의 show()가 실행된다
- 컴파일 오류가 난다
- 둘 다 실행된다
- Parent의 show()가 실행된다
정답 보기
1번 Child의 show()가 실행된다
메서드는 실제 객체(Child)를 따라 동적으로 결정된다(동적 바인딩). 그래서 Child의 show()가 실행된다. 필드 p.x는 변수 타입 Parent의 x를 쓴다.
Q2. System.out.println("A" + 1 + 2 + " " + (1 + 2 + "A"));의 출력은?
- A3 12A
- A3 3A
- A12 3A
- A12 12A
정답 보기
3번 A12 3A
"A" + 1은 "A1", 거기에 2를 붙여 "A12". 괄호 안은 1 + 2 = 3을 먼저 계산해 "3A".
Q3. Java 접근 제어자 중 같은 패키지와 다른 패키지의 자식 클래스까지만 접근을 허용하는 것은?
- protected
- public
- default
- private
정답 보기
1번 protected
protected다. default는 같은 패키지까지, public은 어디서나, private은 그 클래스 안에서만 접근할 수 있다.
Q4. Java에서 클래스가 인터페이스를 구현할 때 쓰는 키워드는?
- super
- extends
- implements
- inherits
정답 보기
3번 implements
클래스 상속은 extends, 인터페이스 구현은 implements.
Q5. 추상 클래스에 대한 설명으로 옳은 것은?
- 추상 클래스는 상속할 수 없다
- 모든 메서드가 반드시 추상 메서드여야 한다
- 추상 메서드는 자식 클래스가 구현한다
- new로 객체를 바로 만들 수 있다
정답 보기
3번 추상 메서드는 자식 클래스가 구현한다
객체 생성 불가, 일반 메서드도 가질 수 있다.
헷갈리기 쉬운 O·X
자식 객체를 만들면 자식 생성자가 먼저 실행되고 부모 생성자가 나중에 실행된다.
정답 보기
X 부모 생성자가 먼저 실행된다.
static 변수는 객체마다 따로 만들어진다.
정답 보기
X 클래스에 하나만 있고 모든 객체가 공유한다.
final로 선언한 메서드는 자식 클래스에서 오버라이딩할 수 없다.
정답 보기
O