1. 생성자
- 개념 : 어떤 동작을 실행하기 전에 준비하는 초기화의 기능
class Calculator4 {
int left, right;
// 생성자(constructor) : 클래스가 실행되면 자동으로 생성자를 최우선으로 실행, 없으면 자동으로 만듦
public Calculator4(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() {
System.out.println(this.left + this.right);
}
public void avg() { // 평균 메소드 정의
System.out.println((this.left + this.right) / 2);
}
}
public class _12_Constructor {
public static void main(String[] args) {
// new 뒤의 Calculator4는 생성자를 의미
Calculator4 c1 = new Calculator4(10, 20);
c1.sum(); // 30
c1.avg(); // 15
Calculator4 c2 = new Calculator4(20, 40);
c2.sum(); // 60
c2.avg(); // 30
}
}
※ 생성자는 직접 명시하지 않으면 자동으로 생성하며 직접 명시하면 자동으로 최우선으로 작동함
※ 반드시 해야할 일을 놓치지 않도록 할 경우 사용
2. 상속 (Inheritance)
1) 개념
- 재활용성 : 객체의 필드(변수)와 메소드를 다른 객체가 물려받을 수 있는 기능
- 예제
class Calculator5 { // Calculator 클래스 정의, 설계
int left, right;
public void setOprends(int left, int right) {
this.left = left; // this. 객체 속성값 입력 시 사용
this.right = right;
}
public void sum() { // 덧셈 메소드 정의, static 이 없음 > 객체 선언이 필요함
System.out.println(this.left + this.right); // static 은 각 정의들이 같은 메모리를 공유하여 객체 선언 필요 없음
}
public void avg() { // 평균 메소드 정의
System.out.println((this.left + this.right) / 2);
}
}
// 새로운 하위 클래스를 정의하고 기존의 클래스를 확장(또는 상속)한다
class SubstractionableCalculator extends Calculator5 {
public void substract() {
System.out.println(this.left - this.right);
}
}
public class _01_Inheritance1 { // public class 는 파일명과 같아야 함. 즉, 대표 클래스
public static void main(String[] args) {
// 인스턴스 생성은 하위 클래스를 통해서 하지만 부모 클래스 기능은 그대로 상속함
SubstractionableCalculator c1 = new SubstractionableCalculator();
c1.setOprends(10, 20);
c1.sum();
c1.avg();
c1.substract();
}
}
- Calculator5 : 부모 클래스(상위 클래스)
- SubstractionableCalculator : 자식 클래스(하위 클래스)
- extends를 통해 선언
- 객체에 메소드를 추가하기 어려운 경우
객체를 직접 만들지 않아서 원소스를 업데이트하면 추가한 메소드가 사라지기도 함
객체가 다양한 곳에서 활용되는데 추가할 기능이 필요가 없을 경우 등
2) 다중 상속
- 기존 클래스를 확장 후 그 하위 클래스를 다시 클래스로 확장
class MultiplicationableCalculator extends Calculator5 {
public void multiplication () {
System.out.println(this.left * this.right);
}
}
class DivisionableCalculator extends MultiplicationableCalculator {
public void division () {
System.out.println(this.left / this.right);
}
}
public class _02_MultipleInheritance {
public static void main(String[] args) {
DivisionableCalculator c1 = new DivisionableCalculator();
c1.setOprends(10, 20);
c1.sum();
c1.avg();
c1.multiplication();
c1.division();
}
}
3. 기본 생성자 (Default Constructor)
1) 기본 생성자의 성질
- 매개변수가 있는 생성자를 선언하고 메인영역에서 매개변수가 없는 인스턴스를 생성하면 에러가 발생함
- 클래스를 선언하면 자동으로 매개변수가 없는 '기본 생성자'를 생성하고, 인스턴스는 그 '기본 생성자'를 호출하기 때문
- 매개변수가 있는 생성자를 선언하면 기본 생성자를 생성하지 않음
- 해결책 : 매개변수가 없는 생성자를 먼저 선언 후 매개변수 생성자를 만들면 해결 가능
2) 기본 생성자 문제 해결
class Calculator6 {
int left, right;
// public Calculator6() {} // 부모클래스 기본생성자를 먼저 설정해줘야함
public Calculator6(int left, int right) {
this.left = left;
this.right = right;
}
public void setOprends(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() {
System.out.println(this.left + this.right);
}
public void avg() { // 평균 메소드 정의
System.out.println((this.left + this.right) / 2);
}
}
// 새로운 하위 클래스를 정의
class SubstractionableCalculator2 extends Calculator6 { // 상위 클래스의 기본생성자가 없으면 에러 발생
// public SubstractionableCalculator2(int left, int right) { // 상위와 하위 클래스모두 생성자가 같다면?
// // this.left = left; // 상위 클래스 생성자와 같음, 너무 길다면?
// // this. right = right;
// super(left, right); // 위와 같을 때 부모클래스 생성자를 참조함
// // 하위클래스의 초기화 코드는 super 에 선행할 수 없음
// }
public void substract() {
System.out.println(this.left - this.right);
}
}
public class _03_ConstructorAndInheritance {
public static void main(String[] args) {
SubstractionableCalculator2 c1 = new SubstractionableCalculator2();
c1.setOprends(10, 20);
c1.sum();
c1.avg();
c1.substract();
}
}
- 해결방법 : 상위 클래스의 '기본 생성자'를 설정
class Calculator6 {
int left, right;
public Calculator6() {} // 부모클래스 기본생성자를 먼저 설정해줘야함
public Calculator6(int left, int right) {
this.left = left;
this.right = right;
}
public void setOprends(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() {
System.out.println(this.left + this.right);
}
public void avg() { // 평균 메소드 정의
System.out.println((this.left + this.right) / 2);
}
}
// 새로운 하위 클래스를 정의
class SubstractionableCalculator2 extends Calculator6 { // 상위 클래스의 기본생성자가 없으면 에러 발생
// public SubstractionableCalculator2(int left, int right) { // 상위와 하위 클래스모두 생성자가 같다면?
// // this.left = left; // 상위 클래스 생성자와 같음, 너무 길다면?
// // this. right = right;
// super(left, right); // 위와 같을 때 부모클래스 생성자를 참조함
// // 하위클래스의 초기화 코드는 super 에 선행할 수 없음
// }
public void substract() {
System.out.println(this.left - this.right);
}
}
- 상위 클래스와 하위 클래스에서 정의된 생성자가 같은 경우 -> super 사용
class SubstractionableCalculator2 extends Calculator6 { // 상위 클래스의 기본생성자가 없으면 에러 발생
public SubstractionableCalculator2(int left, int right) { // 상위와 하위 클래스모두 생성자가 같다면?
// this.left = left; // 상위 클래스 생성자와 같음, 너무 길다면?
// this. right = right;
super(left, right); // 위와 같을 때 부모클래스 생성자를 참조함
// 하위클래스의 초기화 코드는 super 에 선행할 수 없음
}
public void substract() {
System.out.println(this.left - this.right);
}
}
※ 문제 이유 : 상위 클래스의 매개변수가 있는 생성자를 선언하고 매개변수가 없는 하위 클래스 인스턴스를 생성하면 문제 발생
> 하위 클래스 생성자 호출 이전에 상위 클래스의 '기본 생성자'를 호출하도록 되어있기 때문
> 그러나 매개변수가 정의된 생성자가 있으면 '기본 생성자' 자동 생성을 막음
※ 하위 클래스의 생성자가 상위 클래스의 '기본 생성자'를 호출하면 인스턴스의 매개변수가 없어도 실행 가능한가?
> 불가능, 이미 하위 클래스는 매개변수를 받겠다는 생성자를 선언 했기 때문
> 해결 방법 : 하위 클래스의 '기본 생성자'를 선언하면 가능
class SubstractionableCalculator2 extends Calculator6 { // 상위 클래스의 기본생성자가 없으면 에러 발생
public SubstractionableCalculator2() {} // 기본 생성자 선언
public SubstractionableCalculator2(int left, int right) { // 상위와 하위 클래스모두 생성자가 같다면?
// this.left = left; // 상위 클래스 생성자와 같음, 너무 길다면?
// this. right = right;
super(left, right); // 위와 같을 때 부모클래스 생성자를 참조함
// 하위클래스의 초기화 코드는 super 에 선행할 수 없음
}
public void substract() {
System.out.println(this.left - this.right);
}
}
public class _03_ConstructorAndInheritance {
public static void main(String[] args) {
SubstractionableCalculator2 c1 = new SubstractionableCalculator2();
c1.setOprends(10, 20);
c1.sum();
c1.avg();
c1.substract();
}
}
4. Overrriding
1) 개념
- 상위 클래스가 가진 메소드를 하위 클래스에서 재정의하여 기능을 변경하는 방법의 명칭
- 상위 클래스의 메소드는 무시되고 하위 클래스의 재정의 된 메소드가 우선순위로 동작
class Calculator7 {
int left, right;
public void setOprends(int left, int right) {
this.left = left;
this.right = right;
}
public void sum() { // 오버라이딩 할 상위 클래스 메소드
System.out.println(this.left + this.right);
}
public void avg() {
System.out.println((this.left + this.right) / 2);
}
}
// 새로운 하위 클래스를 정의
class SubstractionableCalculator3 extends Calculator7 {
public void sum() { // 오버라이딩 된 메소드
System.out.println("실행 결과는 " + (this.left + this.right) + "입니다.");
}
public void substract() {
System.out.println(this.left - this.right);
}
}
public class _04_Overriding {
public static void main(String[] args) {
SubstractionableCalculator3 c1 = new SubstractionableCalculator3();
c1.setOprends(10, 20);
c1.sum(); // 실행 결과는 30입니다.
c1.avg(); // 15
c1.substract(); // -10
}
}
2) 오버라이딩의 제약사항
- 메소드의 이름
- 메소드의 매개변수의 숫자와 데이터 타입 그리고 순서
- 메소드의 리턴 타입
- 예시(이름은 같으나 데이터타입(int), 리턴타입 불일치)
public void avg() { // 상위 클래스 메소드
System.out.println((this.left + this.right) / 2);
}
// 새로운 하위 클래스를 정의
class SubstractionableCalculator3 extends Calculator7 {
public void sum() {
System.out.println("실행 결과는 " + (this.left + this.right) + "입니다.");
}
public int avg() { // 오류
return(this.left + this.right) / 2;
}
public void substract() {
System.out.println(this.left - this.right);
}
}
※ 메소드의 형태를 정의하는 사항들을 메소드의 '서명(Signature)'이라고 하며 상기 예제는 서명이 달라서 발생한 문제
※ 해결 방법은 상의 클래스의 코드를 변경하여 문제를 우회
※ 상위 클래스의 메소드가 이미 가지고 있는 로직을 하위에서 다시한번 정의하지 않기 위해서는 'super' 키워드 사용
public int avg() { // 타입과 리턴타입 오류, 상위 클래스 변경 필요
return(this.left + this.right) / 2;
// return super.avg(); // super 사용하면 메소드를 똑같이 다시 쓸 필요 없음, 여기에 다른 기능을 더 추가도 가능
}
5. Overloading
- 오버로딩을 통한 3개의 값 계산기 예제
기존
int left, right;
public void setOprands(int left, int right) {
this.left = left;
this.right = right;
}
수정
int left, right;
int third = 0;
public void setOprands(int left, int right) {
// System.out.println("setOprands(int left, int right)"); // 중복 피하기 1
this.left = left;
this.right = right;
}
public void setOprands(int left, int right, int third) {
// this.setOprands(left, right); // 중복 피하기 2
// System.out.println("setOprands(int left, int right, int third)"); // 중복 피하기3
this.left = left;
this.right = right;
this.third = third;
}
public void sum() { // 오버라이딩 할 상위 클래스 메소드
System.out.println(this.left + this.right + this.third);
}
2) 제약사항
- 리턴타입이 같아야함
- 매개변수의 형태는 상관 없음
- 매개변수의 이름은 문제 없음
public class _05_Overloading {
void A() {
System.out.println("void A()");
}
void A(int arg1) { // 문제가 없는 이유 : 매개변수
System.out.println("void A(int arg1)");
}
void A(String arg1) {
System.out.println("void A(String arg1)");
}
// int A() { // 첫 메소드와 문제 발생, 이미 정의됨, 리턴값으로 반환해야 함
// System.out.println("void A()");
// }
public static void main(String[] args) {
_05_Overloading ol = new _05_Overloading();
ol.A();
ol.A(1);
ol.A("coding everybody");
}
}
3) Overriding vs. Overloading
- Overriding : 상위 클래스의 서명이 같은 경우 새롭게 정의(동작방법 변경)
- Overloading : 메소드의 이름이 같지만 상위 클래스와 다른 매개변수를 가지는 메소드를 정의
public class Overloding2 extends _05_Overloading {
void A(String arg1, String arg2) { // Overloading
System.out.println("sub class : void A()");
}
void A() { // Overriding
System.out.println("sub class : void A()");
}
}
'Development > JAVA' 카테고리의 다른 글
(Java) Chapter13. Object (0) | 2023.01.23 |
---|---|
(Java) Chapter12. 예외 (0) | 2023.01.23 |
(Java) Chapter11. 접근 제어자 (0) | 2023.01.17 |
(Java) Chapter10. API (0) | 2023.01.10 |
(Java) Chapter7. 객체 지향 프로그래밍 (0) | 2023.01.08 |