본문 바로가기

Study/Java

객체지향 프로그래밍 6장(16강 ~ 19강)

728x90

오버로딩(overloading)이란?

- 한 클래스 안에 같은 이름의 메서드 여러 개 정의하는 것

우리가 평소에 쓰던 println

우리가 평소에 쓰던 println
println(1234);
println("ABC");
오버로딩이라는 기능이 있어서
매개변수를 참조하여
해당되는 메서드를 호출한다.

 

오버로딩이 성립하기 위한 조건 3가지

- 메서드 이름이 같아야 한다.

// 오버로딩 아님, 메서드 중복정의
int add(int a, int b) { return a+b; } 
int add(int x, int y) { return x+y; }

- 매개변수의 개수 또는 타입이 달라야 한다.

- 반환 타입은 영향없다.

//오버로딩x 반환타입은 영향없다.
//결론은 이것도 중복정의..
int add(int a, int b) { return a+b; }
long add(int a, int b) { return (long)(a+b); }

 

오버로딩의 올바른 예

long add(int a, long b) { return a+b; }
long add(long a, int b) { return a+b; }

- 메서드 이름이 같고 매개변수의 개수 또는 타입이 다르다.

 

add(3, 3L); 메서드를 호출한다면?

long add(int a, long b) { return a+b; }

 매개변수의 타입이 같은 메서드가 호출된다.

 

근데 add(3, 3); 메서드를 호출한다면 ?

에러가 발생한다.

The method add(int, long) is ambiguous for the type MyMath3

모호하다. 명확하지 않다. 어떤 메서드를 호출해야 되는지 잘 모르겠다.

 

실습 예제.

 - 오버로딩의 올바른 예

 - 매개변수는 다르지만 같은 의미의 기능 수행

 

Q. 그럼 오버로딩은 언제 사용합니까?

A. 하는 작업이 같을때 사용한다.

package com.seulgae.ch06;

class OverloadingTest {
	public static void main(String args[]) {
		MyMath3 mm = new MyMath3();
		// The method add(int, long) is ambiguous for the type MyMath3
		//                                     모호하다, 확실하지 않다.
		
//		int result = mm.add(3, 3);
//		System.out.println("mm.add(3, 3) 결과:" + result);
		System.out.println("mm.add(3, 3) 결과:" + mm.add(3, 3)); // int, int 
		System.out.println("mm.add(3L, 3) 결과: " + mm.add(3L, 3)); // long, int
		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;
	}
}

출력결과

 

생성자(constructor) = iv 초기화 메서드

- 인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드'

 

예를 들어 내가 12시 34분 56초를 iv로 사용한다고 가정하면,

// 1. 객체 생성
Time t = new Time();
             //기본 생성자
// 2. iv 초기화
t.hour = 12;
t.minute = 34;
t.second = 5

이렇게 iv를 초기화 할 수 있다. 좀 더 간단하게 한 줄로 초기화 할 수 있다.

Time t = new Time(12, 34, 56);
              // 생성자 호출, 근데 생성자를 추가해야 이렇게 사용할 수 있다.

 

생성자(constructor)의 규칙

- 이름이 클래스 이름과 같아야 한다.

클래스 이름(타입 변수명, 타입 변수명, ...){
    // 인스턴스 생성 시 수행될 코드,
    // 주로 인스턴스 변수의 초기화 코드를 적는다.
}

- 리턴값이 없다.(void 안붙임)

class Card{
	Card(){ // 매개변수 없는 생성자.
        // 인스턴스 초기화 작업
    }
	Card(String kind, int number) { // 매개변수 있는 생성자
    	// 인스턴스 초기화 작업
    }
}

- 모든 클래스는 반드시 생성자를 가져야 한다.

 

기본 생성자(default constructor)

- 매개변수가 없는 생성자

기본 생성자

- 생성자가 하나도 없을 때만, 컴파일러가 자동 추가

package com.seulgae.ch06;

class Data1 {
	int value;
//	Data1(){}
	// 컴파일러가 자동으로 넣어줌.
}

class Data3 {
	int value;

//	Data3(){} 
	Data3(int x) { // 매개변수가 있는 생성자.
		value = x;
	}
}

class ConstructorTest {
	public static void main(String[] args) {
		Data1 d1 = new Data1();
//		Data3 d2 = new Data3();	  // compile error발생
		Data3 d2 = new Data3(10); // compile error발생
                //The constructor Data_2() is undefined
	}
}

- 클래스를 만들 때 기본 생성자를 넣어주는게 습관이 되어야 된다.

 

Q. 왜요?

A. 에러가 기본 생성자를 안넣어줘서 나오는 에러인데 나중에 코드가 길어지면 다른 에러로 나오기 때문에 오류를 찾기 어렵다.

 

매개변수가 있는 생성자

class Car {
	String color; // 색상
	String gearType; // 변속기 종류 - auto(자동), manual(수동)
	int door; // 문의 개수

	Car() {} // 기본 생성자

	Car(String c, String g, int d) { // 매개변수가 있는 생성자
		color = c;
		gearType = g;
		door = d;
	}
	
}

- 생성자를 만들어두면 

한 문장으로 초기화

- main메서드에서 iv를 초기화 할 때 다음과 같이 한 문장으로 호출하여 초기화 할 수 있다.

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);
	}
}

 

Q. 이 문장은 어떻게 실행되나요?

Car c2 = new Car("white", "auto", 4);

A.

문장 실행되는 과정.

 

생성자 this()

- 생성자에서 다른 생성자 호출할 때 사용

package com.seulgae.ch06;

class Car2 {
	String color; // 색상
	String gearType; // 변속기 종류 - auto(자동), manual(수동)
	int door; // 문의 개수

	Car2() {
		this("white", "auto", 4);
	}

	Car2(String color) {
		this(color, "auto", 4);
	}

	Car2(String color, String gearType, int door) {
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}
}

class CarTest2 {
	public static void main(String[] args) {
		Car2 c1 = new Car2();	
		Car2 c2 = new Car2("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);
	}
}

- 다른 생성자 호출시 첫 줄에서만 사용가능

	Car2() {
   	    // 	door = 5; // 이러면 앙대여
		this("white", "auto", 4);
	}

 

Q. (중간점검)생성자가 하는일이 뭐라고?

A. iv 초기화 한다구

 

참조변수 this

- 인스턴스 자신을 가리키는 참조변수

- 인스턴스 메서드(생성자 포함)에서 사용가능

- 지역변수(lv)와 인스턴스 변수(iv)를 구별할 때 사용

지역변수(lv)와 인스턴스 변수(iv)를 구별

 

참조변수 this ≠ 생성자 this()

this 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.
모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재한다.
this(), this(매개변수) 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

 

변수의 초기화

- 지역변수(lv)는 수동 초기화 해야함(사용전에 꼭!!)

- 멤버변수(iv, cv)는 자동 초기화 된다.

i값이 뭔지 모르는데 j에 넣을라고 하니깐 에러가 발생한다.

호출 스택이라는 메모리는 재사용이 빈번하다. 그래서 자주 초기화 되고 사용되기 때문에

지역변수는 꼬오오오오오옥 값을 명시하여 초기화해야 한다.

반면 인스턴스 변수는 선언과 동시에 0으로 초기화되기 때문에 값이 없더라도 에러가 발생하지 않는다.

 

명시적 초기화(=)

class Car{
    int door = 4;            // 기본형(primitive type) 변수의 초기화
    Engine e = new Engine(); // 참조형(reference type) 변수의 초기화
}

 

초기화 블럭

- (iv) 인스턴스 초기화 블럭 : {}

 - 복잡한 초기화 여러문장 넣기.

- (cv) 클래스 초기화 블럭 : static {}

 

생성자

iv 초기화(복잡한 초기화)

 

초기화 방법에는 3가지가 있다.

1. 자동 초기화 : 0

2. 간단 초기화 : = 

3. 복잡 초기화 : {}, static {}(cv), 생성자(iv)

 

예제.

package com.seulgae.ch06;

class BlockTest {

	static {
		System.out.println("static { }");
	}

	{
		System.out.println("{ }");
	}

	public BlockTest() {
		System.out.println("생성자");
	}

	public static void main(String args[]) {
		System.out.println("BlockTest bt = new BlockTest(); ");
		BlockTest bt = new BlockTest();

		System.out.println("BlockTest bt2 = new BlockTest(); ");
		BlockTest bt2 = new BlockTest();
	}
}

출력결과

 

멤버변수의 초기화  - static {}

- 명시적 초기화(=)

- 생성자(iv 초기화)

- 초기화 블럭 - {}, static {}

 

package com.seulgae.ch06;

class StaticBlockTest {
	static int[] arr = new int[10]; //명시적 초기화

 

 

	static {
		for (int i = 0; i < arr.length; i++) {
			// 1과 10사이의 임의의 값을 배열 arr에 저장한다.
			arr[i] = (int) (Math.random() * 10) + 1;
		}
	}

 

 

	public static void main(String args[]) {
		for (int i = 0; i < arr.length; i++)
			System.out.println("arr[" + i + "] :" + arr[i]);
	}
}

 

멤버변수의 초기화

▶ 클래스 변수 초기화 시점(언제?) : 클래스가 처음(메모리에 올라갈 때) 로딩될 때 단 한번

▶ 인스턴스 변수 초기화 시점 : 인스턴스가 생성될 때 마다

 

초기화 순서

1. cv -> iv

2. 자동 -> 간단 -> 복잡

     0           =           static{}

                                생성자

반응형