자기가 자기 자신을 호출하는 것 ➡️ 무한반복의 로직
재귀호출은 반복문으로 바꿀 수 있으며 반복문보다 성능이 나쁘다.
이해하기 쉽고, 간결한 코드를 작성할 수 있다. (분할 정복 알고리즘 한정)
분할 정복 알고리즘이란?
하지만 실제로 사용을 잘 하진 않음.
왜냐? 컴퓨터 자원을 많이 잡아먹는다.
팩토리얼(Factorial)
5!
= 5 x 4 x 3 x 2 x 1
f(n)
= n f(n-1) 단, f(1) = 1이다.
예시 코드
// Factorial.java
package chap06;
import java.util.*;
public class Factorial {
public static void main(String[] args) {
System.out.print("임의의 자연수를 입력하세요.");
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
int result;
FactorialObj ex = new FactorialObj();
System.out.println(ex.factorial(num));
}
}
// FactorialObjClass.java
package chap06;
public class FactorialObj {
int factorial(int n) {
int result = 0;
if(n == 1) {
result = 1;
} else {
result = n * factorial(n - 1);
}
return result;
}
}
package chap06;
import java.util.*;
// 사용자에게 하나의 실수를 입력받아 다음의 결과를 출력하는 코드를 작성하세요.
/*
* 단, 객체지향적으로 코드를 작성하세요.
*
* 실행결과
*
* 하나의 실수를 입력하세요 : 3.64
* 버림 : 3
* 반올림 : 4
* 올림 : 4
* */
public class Exam1 {
public static void main(String[] args) {
System.out.print("0부터 100 사이의 실수를 입력해주세요.");
Scanner sc = new Scanner(System.in);
double num = sc.nextDouble();
Exam1Test testInstance = new Exam1Test();
System.out.println("버림 : " + testInstance.numDown(num));
System.out.println("반올림 : " + testInstance.roundUp(num));
System.out.println("올림 : " + testInstance.numUp(num));
}
} // main
package chap06;
import java.util.Scanner;
// 사용자에게 하나의 실수를 입력받아 다음의 결과를 출력하는 코드를 작성하세요.
/*
* 단, 객체지향적으로 코드를 작성하세요.
* */
public class Exam1Test {
int numDown(double num) {
int floorNum = (int)Math.floor(num);
return floorNum;
}
int numUp(double num) {
int ceilNum = (int)Math.ceil(num);
return ceilNum;
}
int roundUp(double num) {
int roundNum = (int)Math.round(num);
return roundNum;
}
} // class
하나의 클래스에 같은 이름의 메서드를 여러 개 정의하는 것을
메서드 오버로딩(=== 오버로딩)
이라고 한다.
다형성polymorph
을 구현하는 방법 중 하나인 오버로딩
객체지향을 개표하는 기능.
메서드의 이름
이 같아야 한다.매개변수 개수
또는 타입
이 달라야 한다.매개변수는 같고
, Return Type
이 다른 경우는 오버로딩이 성립되지 않는다.➡️ 하나의 메서드를 완전 동일하게 만들면 안된다. 그것을 구분하기 위해 매개변수와 Type이 달라야 함.
int add(int a, int b) {return a + b};
int add(int x, int y) {return x + y};
Return Type은 오버로딩의 성립조건이 아니다.
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 x, int y) {return x + y};
오버로딩의 올바른 예시 => 매개변수는 다르지만, 같은 의미의 기능을 수행.
인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드'
Card c = new Card(); // 인스턴스 생성과 동시에 초기화
모든 클래스는 반드시 하나 이상의 생성자를 가진다.
✅ 해당 클래스 생성자가 4개 === 해당 클래스로부터 생성할 수 있는 인스턴스가 4개
package chap06;
public class Car {
String color;
String gearType;
int door;
Car() {
this.color = "black";
this.gearType = "auto";
this.door = 4;
}
Car(String color) {
this.color = color;
this.gearType = "auto";
this.door = 4;
}
Car(String color, String gearType) {
this.color = color;
this.gearType = gearType;
this.door = 4;
}
Car(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
모든 클래스에는 반드시 하나 이상의 생성자가 있어야 한다.
JVM에서 자동적으로 default Constructor 하나를 만들어준다.
클래스이름() {}
Card() {} // 컴파일러에 의해 추가된 Card 클래스의 기본 생성자. 내용 없음
자기 클래스 안에 있는 다른 생성자를 호출하는 문장이다.
this() - 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용. 다른 생성자 호출은 생성자의 첫 문장에서만 가능하다.
this()
를 사용해서 다른 생성자를 끌어다 사용함으로써 중복되는 코드를 제거할 수 있다.
// 예시코드
package chap06;
public class Car2 {
String color;
String gearType;
int door;
Car2() {
this("black", "Auto", 4);
}
Car2(String color) {
this(color, "Auto", 4);
}
Car2(String color, String gearType) {
this(color, gearType, 4);
}
//✅ 위에 this()들은 아래 Car2의 메소드를 호출하고 있음.
Car2(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
}
}
반드시 첫 번째 문장으로
this()
를 시작해야 한다.
그렇지 않으면 구문 오류를 초래한다.왜❓ ➡️ 먼저
this()
로 초기화 하고, 다른 작업을 이어가게 하도록 하기 위해서.Car2() { System.out.println("첫번째"); this("black", "Auto", 4); } // 구문 오류 발생
//Class
package chap06;
public class Car2 {
String color;
String gearType;
int door;
Car2() {
this("black", "Auto", 4);
System.out.println("첫 번째 생성자");
}
Car2(String color) {
this(color, "Auto", 4);
System.out.println("두 번째 생성자");
}
Car2(String color, String gearType) {
this(color, gearType, 4);
System.out.println("세 번째 생성자");
}
Car2(String color, String gearType, int door) {
this.color = color;
this.gearType = gearType;
this.door = door;
System.out.println("네 번째 생성자");
}
}
// main
package chap06;
public class CarTest2 {
public static void main(String[] args) {
Car2 car1, car2, car3, car4;
car1 = new Car2();
car2 = new Car2("White");
car3 = new Car2("White","Manual");
car4 = new Car2("White","Manual",3);
/* 출력값은 네 번째 생성자
첫 번째 생성자
네 번째 생성자
두 번째 생성자
네 번째 생성자
세 번째 생성자
네 번째 생성자 */ // 그 이유는 네 번째 생성자를 this()로 참조하고 있고, 네 번째 생성자로 초기화를 하고 있기 때문이다.
// System.out.println("car1 : " + car1.color + " " + car1.gearType + " " + car1.door);
// System.out.println("car2 : " + car2.color + " " + car2.gearType + " " + car2.door);
// System.out.println("car3 : " + car3.color + " " + car3.gearType + " " + car3.door);
// System.out.println("car4 : " + car4.color + " " + car4.gearType + " " + car4.door);
}
}
인스턴스 자기 자신을 가리키는 키워드이다.
this를 통해 클래스 메소드 및 생성자에서 자기 자신의 데이터를 업데이트하거나 조작할 수 있다.
this.
는 클래스를 기반으로 생성된 인스턴스를 가리키는 참조다.
🔥 주의 : 인스턴스를 가르키는 참조와 인스턴스 자체는 다르다.
인스턴스 변수와 클래스 변수 ➡️ 변수 선언과 초기화를 꼭 분리해야 한다.
{}
이 존재하는데, 해당 블럭에서 초기화를 진행해야 한다.왜? 클래스 변수는 하나만 존재.
클래스로부터 인스턴스는 제약없이 생성 가능.
클래스 변수는 인스턴스 생성 하지 않아도 메모리로 끌어올릴 수 있다.
// main
package chap07;
public class Test4 {
public static void main(String[] args) {
// Class2 class2 = new Class2();
System.out.println("classVar : " + Class2.classVar); // class가 최초로 참조되어져서 메모리에 올라옴. 인스턴스 생성을 하지 않아도 실행되는 이유이다.
Class2.classVar = 1234;
System.out.println("classVar : " + Class2.classVar);
}
}
// class
package chap07;
public class Class2 {
static int classVar; // 0으로 초기화
int instanceVar; // 0으로 초기화
void methodA() {
// int methodVar; // 초기화가 안된 메소드 변수는 사용할 수 없다.
int methodVar = 10; // 메소드 변수는 반드시 초기화해야 사용할 수 있다.
System.out.println("methodVar : " + methodVar);
}
}
...이어서 9일에 내용 업데이트하기