외부에서 제공되는 다양한 데이터들을 이용해 객체를 초기화하기 위해서는 생성자도 다양화될 필요가 있다. Java는 다양한 방법으로 객체를 생성할 수 있도록 지원하는데, 이를 생성자 오버로딩이라고 한다.
아래는 field가 주어지는 여부에 따라 구분된 생성자들이다.
public class Car {
// field
String company;
String model;
String color;
int maxSpeed;
int speed;
// constructor, Overloading
Car() {
}
Car(String company) {
this.company = company;
}
Car(String company, String model) {
this.company = company;
this.model = model;
}
Car(String company, String model, String color) {
this.company = company;
this.model = model;
this.color = color;
}
Car(String company, String model, String color, int maxSpeed) {
this.company = company;
this.model = model;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
생성자 오버로딩이 많아질 경우, 생성자 간의 중복된 코드가 발생하게 된다. this() 메소드는 Class의 다른 생성자를 호출함으로써, 중복된 코드를 간결하게 개선할 수 있다.
public class Car {
// field
String company;
String model;
String color;
int maxSpeed;
int speed;
// constructor, Overloading
// constructor #1
Car() {
this("현대자동차", "그랜저", "회색", 250); // 2번 생성자 호출
}
// constructor #2
Car(String company) {
this(company, "그랜저", "회색", 250); // 3번 생성자 호출
}
// constructor #3
Car(String company, String model) {
this(company, model, "회색", 250); // 4번 생성자 호출
}
// constructor #4
Car(String company, String model, String color) {
this(company, model, color, 250); // 5번 생성자 호출
}
// constructor #5
Car(String company, String model, String color, int maxSpeed) {
this.company = company;
this.model = model;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
일반적으로 메소드의 매개 변수는 그 숫자가 정해져있다. 하지만 특정 상황에서는 메소드의 매개 변수의 수를 알 수 없는 경우도 있다. 예를 들어, 여러 원소를 합산하는 메소드를 선언해야 한다면 몇 개의 변수가 입력될 지 알 수 없다. 이럴 땐, 매개 변수를 배열 타입으로 선언함으로써 해결할 수 있다.
int sum(int[] values){
int result = 0;
for (int i = 0; i < values.length ; i++){
result += values[i];
}
return result;
}
클래스 내에 같은 이름을 가진 메소드를 여러 개 선언하는 것. 메소드 오버로딩은 매개 변수의 ✔타입, ✔개수, ✔순서 중 하나가 달라져야 한다.
예를 들어 다음과 같은 메소드가 있다고 가정하자.
int plus(int x, int y){
int result = x + y;
return result;
}
동일한 로직으로 double의 값을 계산하고 리턴하는 메소드가 필요한 경우 굳이 다른 메소드를 선언할 필요 없이, 같은 이름으로 리턴 타입과 변수 타입만 변경해주면 된다.
double plus(double x, double y){
double result = x + y;
return result;
}
오버로딩된 메소드들은 JVM에 의해서 변수 값의 타입을 보고 적용된다.
위의 plus() 메소드를 다음과 같이 호출하여 사용한다고 가정하자.
int x = 10;
double y = 15.3;
plus(x, y)
int와 double로 매개 변수가 실행되기 때문에 컴파일 에러가 날 것 같지만, 위대한 JVM은 매개 변수의 타입 변환을 통해 오버로딩된 메소드들 중 적용 가능한 메소드가 있는지 검사한다.
때문에 위의 코드는 x를 double로 타입변환을 하고, 이후 double plus() 메소드가 적용된다.
Class 선언 시, 중복되는 코드를 줄이고 유지보수를 간편하게 하기 위해 상속을 선언할 수 있다. 선언 방법은 다음과 같다.
class [자식 Class] extends [부모 Class]{
// field
// constructor
// method
}
public [자식 Class]() {
super();
}
public class People {
public String name;
public String ssn;
public People(String name, String ssn){
this.name = name;
this.ssn = ssn;
}
}
위 People 클래스의 경우, 기본 생성자 없이 변수 2개(name, ssn)를 받아 생성된다. 이런 경우 People을 상속하는 클래스는 동일하게 2개의 변수(name, ssn)를 받을 수 있도록 구성해야 한다. 그 예시는 다음과 같다.
public class Student {
public int studentNum;
public Student(String name, String ssn, int studentNum){
this.name = name;
this.ssn = ssn;
this.studentNum = studentNum;
}
}
상속받은 메소드가 자식 클래스에서 사용하기 힘든 상황이 있을 수 있다. Java는 이런 경우 메소드를 자식 클래스 내에서 간단하게 변경할 수 있는 기능을 제공한다.
public class Calculator {
double area Circle(double r){
return 3.14159 * r * r;
}
}
public class Precise_Calculator extends Calculator{
@Override
double area Circle(double r){
return MATH.PI * r * r; //Math API 사용
}
}
@Override : 컴파일러가 해당 메소드가 정확히 재정의된 것인지 확인
자식 클래스의 내부에서 재정의된 부모 클래스의 메소드를 호출해야 하는 상황이 발생할 수도 있다. 이 때, super 키워드를 이용해 부모 메소드를 호출할 수 있다.
super.[메소드 이름]() // 부모 메소드 호출