메서드 정의와 시그니처의 이해
자바에서 메서드의 고유성을 결정하는 요소는 메서드 이름과 매개변수 리스트를 합친 '시그니처(Signature)'입니다. 반환값은 시그니처에 포함되지 않으므로, 메서드를 구분할 때 반환 타입만으로는 부족합니다.
- 오버로딩 (Overloading): 하나의 클래스 내에서 동일한 이름을 가지되, 매개변수의 개수나 타입이 서로 다른 메서드를 선언할 수 있습니다. 컴파일러는 호출 시점에 전달된 인자에 가장 적합한 메서드를 자동으로 선택하여 바인딩합니다.
객체 초기화와 생성자(Constructor)
생성자는 인스턴스 메모리를 할당받고 멤버 변수에 초기 값을 설정하는 특수한 메서드입니다.
- 클래스 이름과 완전히 동일해야 합니다.
- 반환 타입을 명시하지 않습니다(void 포함 금지).
- 객체를 생성(new)하는 순간 자동 실행됩니다.
- 사용자가 작성하지 않으면 컴파일러가 기본 무반환 생성자를 제공하지만, 명시적 생성자가 있으면 이 기본 생성자는 사라집니다.
- 매개변수 조합에 따라 여러 개의 생성자를 정의하여 오버로딩이 가능합니다.
this 키워드는 현재 실행 중인 객체 자신을 가리킵니다. 주로 필드와 지역 변수의 충돌을 해결하거나, 같은 클래스 내의 다른 생성자를 호출할 때 (this()) 사용됩니다.
참조 형식 배열과 다차원 구조
배열의 요소 타입에 따라 초기화 상태가 달라집니다. 기본数据类型(primitive type) 배열은 모든 요소가 디폴트 값 (예: 정수는 0) 으로 채워지지만, 참조 형식 (class, interface 등) 배열의 경우 모든 요소가 null로 초기화됩니다.
다차원 배열 역시 각 행 (행 배열) 을 개별적으로 새로운 배열 객체로 생성해야 사용 가능한 '불규칙 배열(Jagged Array)' 형태로 구성할 수 있습니다.
코드 실습: 오버로딩과 참조 배열
package com.oop.core;
/* 메서드 오버로딩 테스트 */
public class OperationTester {
public static void main(String[] args) {
DataHandler handler = new DataHandler();
// 다양한 서명이 있는 메서드 호출
handler.process();
handler.execute("User_01");
handler.register("Admin", 1);
handler.setPriority(10, "High");
}
}
class DataHandler {
void process() {
System.out.println("기본 작업 수행");
}
void execute(String userId) {
System.out.println("사용자 ID 로 작업 시작: " + userId);
}
void register(String name, int grade) {
System.out.println(name + " 등급: " + grade);
}
// 인수 순서가 다르면 오버로딩으로 인정됨
void setPriority(int val, String label) {
System.out.println("우선순위: " + val + " - " + label);
}
}
실전 적용: 좌표 시스템 및 블록 배치
위치 정보를 관리하기 위한 클래스와 이를 그룹화하는 블록 형태의 패턴을 구현해 봅니다.
package com.oop.core;
// 좌표를 나타내는 클래스
public class GridPoint {
int x;
int y;
public GridPoint() {
this(0, 0);
}
public GridPoint(int side) {
this(side, side);
}
public GridPoint(int x, int y) {
this.x = x;
this.y = y;
}
// 위치 변경
public void shift(int dx, int dy) {
this.x += dx;
this.y += dy;
}
@Override
public String toString() {
return "[" + x + "," + y + "]";
}
}
```
package com.oop.core;
// 네 개의 점으로 구성된 특정 모양 (T 자형 대안)
public class ShapeBlockT {
private GridPoint[] vertices;
public ShapeBlockT(int startX, int startY) {
// 4 개의 포인트를 가진 배열 생성
vertices = new GridPoint[4];
vertices[0] = new GridPoint(startX, startY);
vertices[1] = new GridPoint(startX + 1, startY);
vertices[2] = new GridPoint(startX + 2, startY);
vertices[3] = new GridPoint(startX + 1, startY + 1);
}
public void moveDown() {
for(GridPoint pt : vertices) {
pt.shift(0, 1); // y 축 증가
}
}
public void printInfo() {
for(int i = 0; i < vertices.length; i++) {
System.out.println("Vertex " + i + ": " + vertices[i].toString());
}
}
}
public class MainApp {
public static void main(String[] args) {
// 1 차원 참조 배열 활용
GridPoint[] coords = new GridPoint[2];
coords[0] = new GridPoint(10, 20);
coords[1] = new GridPoint(30, 40);
System.out.println("Coords: " + coords[1]);
// 불규칙 2 차원 배열
int[][] jagged = new int[3][];
jagged[0] = new int[]{1, 2};
jagged[1] = new int[]{3, 4, 5};
jagged[2] = new int[]{6};
// ShapeBlock 테스트
ShapeBlockT myT = new ShapeBlockT(5, 5);
System.out.println("--- Initial ---");
myT.printInfo();
myT.moveDown();
System.out.println("--- After Move ---");
myT.printInfo();
}
}
학습 점검
문제 1: 오버로딩 식별
다음 코드가 실행될 때 출력되는 값은 무엇이며 그 이유는 무엇인가요?
class Test {
int calculate(int a, int b) { return a * b; }
String calculate(String s1, String s2) { return s1 + s2; }
}
// 호출: Test t = new Test();
// System.out.println(t.calculate("3", "4"));
정답: 문자열 연결 결과인 "34" 가 출력됩니다.
컴파일러는 인자의 타입이 문자열 (String) 임을 인지하므로, int 가 아닌 String 매개변수를 가진 오버로드된 메서드를 선점합니다.
문제 2: 생성자 규칙 확인
아래 설명 중 옳지 않은 것은 무엇입니까?
- A. 생성자는 반드시 클래스 이름과 같아야 한다.
- B. 생성자에 void 를 명시하면 일반 메서드로 인식된다.
- C. 사용자가 생성자를 하나라도 만들면 기본 무인자 생성자는 자동 생성되지 않는다.
- D. 생성자는 오버로딩이 불가능하다.
정답: D 입니다. 생성자는 매개변수의 조합을 달리하여 여러 개 정의할 수 있으며, 이를 생성자의 오버로딩이라고 부릅니다.