하나의 클래스 내에서 같은 이름의 메서드를 여러 개 정의하는 것을 '메서드 오버로딩(method overloading)' 또는 간단히 '오버로딩(overloading)'이라고 한다.
- 메서드 이름이 같아야 한다.
- 매개변수의 개수 또는 타입이 달라야 한다.
class OverloadingTest {
public static void main(String[] args) {
Mymath3 mm = new Mymath3();
System.out.println("mm.add(3, 3) 결과 :" + mm.add(3,3));
System.out.println("mm.add(3L, 3) 결과 :" + mm.add(3L,3));
System.out.println("mm.add(3, 3L) 결과 :" + mm.add(3,3L));
System.out.println("mm.add(3L, 3L) 결과 :" + mm.add(3L,3L));
int [] a = {100, 200, 300};
System.out.println("mm.add(a) 결과 : " + mm.add(a));
}
}
class Mymath3 {
int add(int a, int b){
System.out.print("int add(int a, int b) - ");
return a + b;
}
long add(int a, long b){
System.out.print("long add(int a, long b) - ");
return a + b;
}
long add(long a, int b){
System.out.print("long add(long a, int b) - ");
return a + b;
}
long add(long a, long b){
System.out.print("long add(long a, long b) - ");
return a + b;
}
int add(int[] a){ // 배열의 모든 요소의 합을 결과로 돌려준다.
System.out.print("int add(int[] a) - ");
int result = 0;
for(int i = 0; i < a.length; i++){
result += a[i];
}
return result;
}
}
실행결과
int add(int a, int b) - mm.add(3, 3) 결과 :6
long add(long a, int b) - mm.add(3L, 3) 결과 :6
long add(int a, long b) - mm.add(3, 3L) 결과 :6
long add(long a, long b) - mm.add(3L, 3L) 결과 :6
int add(int[] a) - mm.add(a) 결과 : 600
위와 같은 결과가 나오기 위해서 오버로딩을 사용한 것이 보여진다. Mymath3클래스의 add메서드들을 오버로딩해줌으로써 각각 메서드가 받는 매개변수에 따라 그에 따른 반환값과 출력문이 나오도록 했다.
이렇게 오버로딩을 함으로써 하나의 메서드로 여러개의 메서드를 정의할 수 있게 되어 복잡하지 않은 코딩을 할 수 있게 되었다.
생성자는 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메서드' 즉, 메서드명이 클래스명과 동일하며 리턴자료형이 존재하지 않는 메서드라고 생각하면 된다.
- 생성자의 이름은 클래스의 이름과 같아야 한다.
- 생성자는 리턴 값이 없다.
클래스이름(타입 변수명, 타입 변수명, ... ) {
// 인스턴스 생성 시 수행될 코드,
// 주로 인스턴스 변수의 초기화 코드를 적는다.
}
class Card{
Card(){ // 매개변수가 없는 생성자
...
}
Card(String k, int num){ // 매개변수가 있는 생성자
...
}
...
}
여기서 주의할 점은 연산자 new가 인스턴스를 생성하는 것이지 생성자가 인스턴스를 생성하는 것이 아니다라는 것을 알고 가야한다.
Card c = new Card();
- 연산자 new에 의해서 메모리(heap)에 Card클래스의 인스턴스가 생성된다.
- 생성자 Card()가 호출되어 수행된다.
- 연산자 new의 결과로, 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장된다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto(자동), manual(수동)
int door; // 문의 개수
Car() {}
Car(String c, String g, int d){
color = c;
gearType = g;
door = d;
}
}
class CarTest {
public static void main(String[] args) {
Car c1 = new Car();
c1.color = "white";
c1.gearType = "auto";
c1.door = 4;
Car c2 = new Car("white", "auto", 4);
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType + ", door=" + c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType + ", door=" + c2.door);
}
}
같은 클래스의 멤버들 간에 서로 호출할 수 있는 것처럼 생성자간에도 서로 호출이 가능하다.
- 생성자의 이름으로 클래스이름 대신 this를 사용한다.
- 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.
이때 생성자를 작성할 때 첫 줄에서만 호출해야 되는 이유는 생성자 내에서 초기화 작업 도중에 다른 생성자를 호출하게 되면, 호출된 다른 생성자 내에서도 멤버변수들의 값을 초기화를 할 것이므로 다른 생성자를 호출하기 이전의 초기화 작업이 무의미해질 수 있기 때문이다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto (자동), manual (수동)
int door; // 문의 개수
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
Car() {
this("White", "auto", 4);
}
Car(String color) {
this(color, "auto", 4);
}
}
class CarTest2 {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car("Blue");
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType + ", door=" + c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType + ", door=" + c2.door);
}
}
실행결과
c1의 color=White, gearType=auto, door=4
c2의 color=Blue, gearType=auto, door=4
나는 생성자를 쉽게 생각하여 손님들이 받는 상세하게 무슨 재료가 들어간 수프인지 적혀있는 메뉴판으로 생각하며 생성자를 이해하고 있다.
위의 코드를 예로 들어, 제일 첫번째 생성자 Car(String color, String gearType, int door)에서는 색깔과 기어타입, 문의 개수를 미리 주문자의 오더에 따라 바뀔 수가 있지만, 두번째 세번째 생성자 Car에서는 오더가 없거나, 3개중의 1개를 설정하면 나머지에 대해서는 미리 정해져 있는 값을 반환한다.
즉, 생성자를 통해서 변수를 설정하는 것에 대해서 간략하게 변경할 수 있게 된다는 것을 이해해야한다.
this : 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다. 모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재한다.
this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.
class Car {
String color; // 색상
String gearType; // 변속기 종류 - auto (자동), manual (수동)
int door; // 문의 개수
Car(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
Car() {
this("White", "auto", 4);
}
Car(Car c) { // 인스턴스의 복사를 위한 생성자
color = c.color;
gearType = c.gearType;
door = c.door;
} // this(c.color, c.gearType, c.door);
}
class CarTest3 {
public static void main(String[] args) {
Car c1 = new Car();
Car c2 = new Car(c1); // c1의 복사본 c2를 생성한다.
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType + ", door=" + c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType + ", door=" + c2.door);
c1.door = 100;
System.out.println("c1.door=100; 수행 후");
System.out.println("c1의 color=" + c1.color + ", gearType=" + c1.gearType + ", door=" + c1.door);
System.out.println("c2의 color=" + c2.color + ", gearType=" + c2.gearType + ", door=" + c2.door);
}
}
실행결과
c1의 color=White, gearType=auto, door=4
c2의 color=White, gearType=auto, door=4
c1.door=100; 수행 후
c1의 color=White, gearType=auto, door=100
c2의 color=White, gearType=auto, door=4
인스턴스 c2는 c1을 복사하여 생성된 것이므로 서로 같은 상태를 갖지만, 서로 독립적으로 메모리공간에 존재하는 별도의 인스턴스이므로 c1의 값들이 변경되어도 c2는 영향을 받지 않는다.
참고 자바의 정석 p283 ~ 299