자바(JAVA) - 객체 지향 언어 : 변수와 메서드 - https://tigre911.tistory.com/40
자바(JAVA) - 객체 지향 언어 : 변수와 메서드(2) https://tigre911.tistory.com/41
오버로딩(overloading)
[1] 오버로딩이란?
메서도 같은 클래스 내에서 각기 다른 이름을 가져야 한다.
그러나 자바에서는 같은 이름을 가진 메서드가 있더라고 하더라도 매개변수의 개수, 혹은 타입이 다르다면 같은 이름을 사용해서 메서드를 정의할 수 있다.
이처럼, 한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 '메서드 오버로딩' 또는 '오버로딩'이라고 한다.
[2] 오버로딩의 조건
1. 메서드 이름이 같아야 한다.
2. 매개변수의 개수 또는 타입이 달라야한다.
(주의) 오버로딩된 메서드들은 매개변수에 의해서만 구별될 수 있으므로 반환 타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다.
[3]오버로딩의 장점
메서드의 이름을 절약하여 하나의 이름으로 정의된 메서드들로 오류의 가능성을 줄일 수 있다.(기억하기 쉽다)
[4] 가변인자(varargs)와 오버로딩
기존에는 메서드 매개변수 개수가 고정이였으나 JDK1.5부터 지정 가능하다. 이 기능을 '가변인자' 라고 한다.
가변인자는 '타입... 변수명' 과 같은 형식으로 선언하며, PrintStream 클래스의 printf( )가 대표적인 예이다.
public PrintStream printf(String format, Object... args) {...}
위와 같이 가변인자 외에도 매개변수가 더 있다면, 가변인자를 가장 마지막에 선언해야 한다.
그렇지 않다면 컴파일 에러!(가변인자인지 아닌지 구별할 수 없기 때문)
생성자(Constructor)
[1] 생성자란?
생서자는 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메서드'이다.
인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성시에 실행할 작업을 위해서도 사용된다.
생성자 역시 메서드처럼 클래스 내에 선언되며, 구조도 메서드와 유사하지만 리턴값이 없다.
그렇다고 void를 사용하지는 않고, 아무 것도 적지 않는다.
생성자의 조건
1. 생성자의 이름은 클래스의 이름과 같아야 한다.
2. 생성자는 리턴 값이 없다.
또한, 생성자도 오버로딩이 가능하다.
<생성자 예시>
클래스이름(타입변수명, 타입변수명, ...) {
인스턴스 생성시 수행될 코드,
(주로 인스턴스 변수의 초기화 코드를 적는다.)
}
class Card{
Card(){ //매개변수가 없는 생성자
...
}
Card(String k, int num){ //매개변수가 있는 생성자
...
}
...
}
연산자 new가 인스턴스를 생성하는 것일 뿐 , 생성자가 인스턴스를 생성하는 것이 아니다.
생성자는 단순히 인스턴스 변수들의 초기화에 사용되는 조금 특별한 메서드일 뿐이다.
<Card 클래스의 인스턴스 생성시 수행 과정>
Card c = new Card();
1. 연산자 new에 의해서 메모리(heap)에 Card클래스의 인스턴스가 생성된다.
2. 생성자 Card()가 호출되어 수행된다.
3. 연산자 new의 결과로, 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장된다.
[2] 기본 생성자
모든 클래스에는 반드시 하나 이상의 생성자가 정의되어 있어야 한다.
지금까지 클래스에 생성자를 정의하지 않고도 인스턴스를 생성할 수 있었던 이유는 컴파일러가 제공하는 '기본 생성자(default constructor)' 덕분이었다.
컴파일 할 때, 소스파일(*.java)의 클래스에 생성자가 하나도 정의되지 않은 경우 컴파일러는 자동적으로 생성자를 추가 하여 컴파일 한다.
클래스 이름() { }
[3] 매개변수가 있는 생성자
말그대로 매개변수가 포함되어있는 생성자이다
자동차를 클래스로 정의한 예시를 보자
class Car{
String color;
String gearType;
int door;
Car(){ } //생성자
Car(String c, String g, int d){ //매개변수가 있는 생성자
color = c;
gearType = g;
door = d;
}
}
두가지의 Car() 생성자를 매개변수의 유무를 나누어 생성해보았다.
public class Page294 {
public static void main(String[] args) {
Car car = new Car(); //첫번째 매개변수가 포함되지 않은 생성자
car.color = "white";
car.gearType = "auto";
car.door = 2;
Car c = new Car("white", "auto", 2); //매개변수가 포함된 생성자
}
위의 두 코드의 차이를보면 매개변수가 있는 생성자가 훨씬 간결하고 직관적인것을 확인할 수 있다.
클래스를 작성할 때 다양한 생성자를 제공함으로써 인스턴스 생성 후에 별도로 초기화를 하지 않아도 되도록 하는 것이 바람직하다.
[4] 생성자에서 다른 생성자 호출하기 - this(), this
같은 클래스 멤버들 간에 서로 호출할 수 있는 것 처럼,
생성자 간에도 서로 호출이 가능하다.
단, 조건이 있다.
1. 생성자의 이름으로 클래스이름 대신 this를 사용한다.
2. 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.
<코드예시>
public class Page296 {
public static void main(String[] args) {
Car1 car1 = new Car1();
Car1 car2 = new Car1("blue");
System.out.println(car1.color +"\t"+ car1.gearType +"\t"+ car1.door);
System.out.println(car2.color +"\t"+ car2.gearType +"\t"+ car2.door);
}
}
class Car1{
String color;
String gearType;
int door;
Car1(){
this("white", "auto", 4);
}
Car1(String color){
this(color, "auto", 4);
}
Car1(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
출력결과
white auto 4
blue auto 4
같은 클래스 내의 생성자들은 일반적으로 서로 관계가 깊은 경우가 많다, 이처럼 서로 호출하도록 하여 유기적으로 연결해주면 더 좋은 코드를 얻을 수 있다.
Car1(String color, String gearType, int door){
this.color = color;
this.gearType = gearType;
this.door = door;
}
Car1(String c, String g, int d){ //매개변수가 있는 생성자
color = c;
gearType = g;
door = d;
}
위의 예시두개에서 this를 사용한것과 사용하지 않은것의 차이는
아래 코드는 'color = c;'가 생성자의 매개변수로 선언된 지역변수 c의 값을 인스턴스변수 color에 저장하기 때문에
변수 color와 c는 이름만으로도 구별되어 아무런 문제가 없다.
그러나 위쪽 코드의 경우 생성자의 매개변수로 선언된 변수의 이름이 인스턴스 변수와 같을 경우에는 이름만으로 구별이 되지 않기때문에 인스턴스변수 앞에 'this'를 사용하여 예시처럼 코드를 적으면 된다.
[5] 생성자를 이용한 인스턴스의 복사
현재 사용하고 있는 인스턴스와 같은 상태를 갖는 인스턴스를 하나 더 만들고자 할 때 생성자를 이용할 수 있다.
두 인스턴스가 같은 상태를 갖는다는 것 == 두 인스턴스의 모든 인스턴수 변수(상태)가 동일한 값을 갖고 있다는 것을 뜻한다.
인스턴스를 생성할 때는 다음의 2가지 사항을 결정해야한다.
1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?
2. 생성자 - 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가?
변수의 초기화
[1] 변수의 초기화
변수를 선언하고 처음으로 값을 저장하는 것을 '변수의 초기화'라고 한다.
멤버변수는 초기화를 하지 않아도 자동적으로 변수의 자료형에 맞는 기본값으로 초기화가 이루어지므로 초기화를 하지 않고 사용해도 되지만,
지역변수는 사용하기 전에 반드시 초기화 해야한다.
class InitTest {
int x; //인스턴스변수
int y; //인스턴스변수
void method() {
int i; //지역변수
int j = i; //에러. 지역변수를 초기화하지 않고 사용
}
}
멤버변수(클래스변수와 인스턴스변수)와 배열의 초기화는 선택적 이지만, 지역변수의 초기화는 필수적이다.
<참고>각 타입의 기본값
자료형 | 기본값 |
boolean | false |
char | '\u0000' |
byte, short, int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d 또는 0.0 |
참조형 변수 | null |
멤버변수의 초기화는 지역변수와 달리 여러 가지 방법이 있다.
멤버변수의 초기화 방법
1. 명시적 초기화(explicit initialization)
2. 생성자
3. 초기화 블럭
- 인스턴스 초기화 블럭
- 클래스 초기화 블럭
[2] 명시적 초기화
변수를 선언과 동시에 초기화 하는것을 명시적 초기화 라고한다.
class Car{
int door =4; //기본형 변수의 초기화
Engine e = new Engine(); //참조형 변수의 초기화
}
[3] 초기화 블럭
클래스 초기화 블럭 - 클래스 변수의 복잡한 초기화에 사용된다.
인스턴스 초기화 블럭 - 인스턴스변수의 복잡한 초기화에 사용된다.
클래스 초기화 블럭은 클래스가 메모리에 처음 로딩될 때 한번만 수행되며,
인스턴스 초기화 블럭은 생성자와 같이 인스턴스를 생성할 때마다 수행된다.
그리고 생성자 보다 인스턴스 초기화 블럭이 먼저 수행된다는것을 기억하자!
class BlockTest{
//클래스 초기화 블럭
static {
System.out.println("static { }");
}
//인스턴스 초기화 블럭
{
System.out.println("{ }");
}
public BlockTest() {
System.out.println("생성자");
}
}
public class Page303_BlockTest {
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();
System.out.println("BlockTest bt3 = new BlockTest();");
BlockTest bt3 = new BlockTest();
}
}
<출력결과>
BlockTest bt = new BlockTest();
static { }
{ }
생성자
BlockTest bt2 = new BlockTest();
{ }
생성자
BlockTest bt3 = new BlockTest();
{ }
생성자
[4] 멤버변수의 초기화 시기와 순서
클래스 변수의 초기화 시점 - 클래스가 처음 로딩될 때 단 한번 초기화 된다.
인스턴스 변수의 초기화 시점 - 인스턴스가 생성될 때마다 각 인스턴스 별로 초기화가 이루어진다.
클래스 변수의 초기화순서 - 기본값 → 명시적 초기화 → 클래스 초기화 블럭
인스턴스 변수의 초기화순서 - 기본값 → 명시적 초기화 → 인스턴스 초기화 블럭 → 생성자
'JAVA > 자바의정석' 카테고리의 다른 글
자바(JAVA) : 객체지향 프로그래밍 II (2) - 오버라이딩 (0) | 2022.01.10 |
---|---|
자바(JAVA) : 객체지향 프로그래밍 II (1) - 상속 (0) | 2022.01.10 |
자바(JAVA) - 객체 지향 언어 : 변수와 메서드(2) (0) | 2022.01.07 |
자바(JAVA) - 객체 지향 언어 : 변수와 메서드(1) (0) | 2022.01.07 |
자바(JAVA) - 객체 지향 언어 : 클래스와 객체 (0) | 2022.01.06 |