Skip to content

객체지향, 예외처리 노트 #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions Ch 11 객체지향.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
# Ch. 11 객체지향

# 생성자

내가 코드 안 치면 비어있는 디폴트 생성자 만들어줌

내가 생성자 만들면 디폴트 생성자 만들어지지 않음

객체 변수에 값을 무조건 설정해야만 객체가 생성될 수 있게 강제하는 방법으로 생성자를 쓸 수 있다.

생성자는 클래스명과 메소드명이 같으며 리턴타입을 쓰지 않는다.

생성자도 오버로딩이 가능하다.

# 상속

단일 상속만 가능

`extends` 키워드를 사용

# 오버로딩

한 클래스에서 매개변수가 다른, 같은 이름의 메소드 여러 개를 정의할 수 있는 것을 말한다.

매개변수의 개수나 타입이 다르면 서로 다른 메소드로 본다. 하지만, 리턴타입만 다른 경우는 모호하기 때문에 허용되지 않는다.

같은 기능을 하는 메소드를 하나의 이름으로 지정해 가독성을 높이는 장점이 있다.

```java
public class OverloadingTest {
public static void main(String[] args) {
Calculator calc = new Calculator();

**System.out.println(calc.add(1, 2));
System.out.println(calc.add(1, 2, 3));**
}
}

class Calculator {
public int add(int a, int b){
return a + b;
}
public int add(int a, int b, int c){
return a + b + c;
}
}
```

# 오버라이딩

부모 클래스에서 상속받은 메소드의 내용을 자식 클래스의 상황에 맞게 변경하는 것으로, 메소드 이름, 매개변수, 리턴타입이 모두 같아야 오버라이딩된다. 오버라이딩 메소드는 오버리든 메소드 리턴타입의 서브타입을 리턴해도 된다.

오버라이딩할 때는 `@Override` 애노테이션을 쓸 수 있다. 컴파일러가 정말 오버라이드를 하는지 확인하고 그렇지 않다면 에러를 던진다.

오버라이딩 메소드는 오버리든 메소드의 접근제어자를 더 넓게 설정할 수는 있어도, 더 좁게 설정할 수는 없다.

예를 들어 오버리든 메소드가 `default` 접근제어를 한다면, 오버라이딩 메소드는 더 넓은 `default`, `protected`, `public`으로 설정 가능하다. 하지만 `private`으로 설정할 수는 없다.

오버라이딩 메소드는 오버리든 메소드가 throw하는 exception보다 작은 범위의 exception만 throw할 수 있다.

```java
public class OverridingTest {
public static void main(String args[]){
Person person = new Person();
Child child = new Child();
Senior senior = new Senior();

person.cry();
child.cry();
senior.cry();
}
}

class Person {
void cry() {
System.out.println("흑흑");
}
}

class Child extends Person {
@Override
protected void cry() {
System.out.println("응애");
}
}

class Senior extends Person {
public void cry() {
System.out.println("훌쩍훌쩍");
}
}
```

## static 메소드 오버라이딩

static 메소드도 같은 메소드 이름, 매개변수, 리턴타입의 메소드를 서브클래스에 적어줄 수 있다. 단, 이 경우는 오버라이딩의 방식이 아닌 숨기는 방식으로 작동한다. 무슨 말인지 예시를 통해 설명한다.

### 예시

```java
public class StaticHideTest {
public static void main(String[] args){
Cat myCat = new Cat();
Animal myAnimal = myCat;
myCat.testClassMethod(); // The static method in Cat
myAnimal.testClassMethod(); // The static method in Animal

myCat.testInstanceMethod(); // The instance method in Cat
myAnimal.testInstanceMethod(); // The instance method in Cat
}
}

class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
public void testInstanceMethod() {
System.out.println("The instance method in Animal");
}
}

class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public void testInstanceMethod() {
System.out.println("The instance method in Cat");
}
}
```

사실 같은 객체를 가리키는 myCat과 myAnimal에서 각각 static 메소드를 호출하면, 각자 다른 함수를 호출하는 것을 볼 수 있다. myCat은 Cat 클래스의 static 메소드를 호출하고, myAnimal은 Animal 클래스의 static 메소드를 호출한다.

반면 myCat과 myAnimal에서 인스턴스 메소드를 호출하면, Cat 객체이므로 Cat 클래스의 인스턴스 메소드가 호출되는 것을 볼 수 있다.

### 오버라이딩으로 static 여부가 바뀔 수는 없다

static 메소드를 인스턴스 메소드로 오버라이드할 수 없다.

인스턴스 메소드를 static 메소드로 오버라이드할 수 없다.

# 인터페이스

클래스와 유사한데, 요구하는 메소드를 반드시 구현해야 함. (클래스는 오버라이드하는 것이 선택)

인터페이스에는 보통 메소드 몸통을 정의하지 않음

```java
interface Predator {
String getFood();
}
```

인터페이스를 구현하는 클래스들이 정의함. 정의하지 않으면 컴파일 에러

`class` 키워드 자리에 `interface` 키워드를 사용

`extends` 키워드 자리에 `implements` 키워드를 사용

한 클래스는 하나의 클래스만 extend할 수 있는 반면, 여러 개의 인터페이스를 implement할 수 있음

인터페이스는 클래스처럼 자료형처럼 사용할 수 있음

```java
class ZooKeeper {
void feed(Tiger tiger) {
System.out.println("feed apple");
}

void feed(Lion lion) {
System.out.println("feed banana");
}
}
```

```java
class ZooKeeper {
void feed(Predator predator) {
System.out.println("feed apple");
}
}
```

## 디폴트 메소드

디폴트 메소드로 메소드 몸통을 구현한 인터페이스 메소드를 만들 수도 있음. 클래스의 인스턴스 메소드와 매우 유사

```java
interface Predator {
**default** void printFood() {
System.out.printf("my food is %s\n", getFood());
}
}
```

## 스태틱 메소드

클래스의 스태틱 메소드와 매우 유사

```java
interface Predator {
int LEG_COUNT = 4; // 인터페이스 상수

static int speed() {
return LEG_COUNT * 30;
}
}
```

인터페이스 상수는 자동으로 `public static final`이 적용된다.

```java
Predator.speed(); // 120
Predator.LEG_COUNT; // 4
```
126 changes: 126 additions & 0 deletions Ch 12 예외처리.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Ch. 12 예외처리

자바에서는 예외처리와 관련해 `try... catch, finally, throw` 구문을 사용한다.

# 예외는 언제 발생하는가

예외는 크게 프로그램 작성 순간에 예측가능한 예외인 Exception, 발생할 수 있고 안할 수도 있는 Runtime Exception으로 구분할 수 있다.

이와 관련한 클래스로 Exception과 RuntimeException이 있다. 구분과 완전히 일치하지는 않는게 Exception은 모든 예외의 부모 클래스이며 RuntimeException도 Exception을 상속받는다.

# 예외 처리하기

다음과 같이 생긴 try, catch문을 사용해 예외를 처리한다.

```java
try {
...
} catch(예외1) {
...
} catch(예외2) {
...
}
```

try 문 안에 예외가 발생할 수 있는 문장을 넣는다.

try 문 안에서 예외가 발생하면 예외 종류에 해당하는 catch문이 수행된다. 여러 catch문에 해당되어도 가장 위에 것만 실행된다. 예외 발생 문장 뒤에 있는 문장들은 무시된다.

try 문 안에서 예외가 발생하지 않으면 어떤 catch문도 수행되지 않는다.

## 예시

```java
int c;
try {
c = 4 / 0;
} catch(ArithmeticException e) {
c = -1; // 예외가 발생하여 이 문장이 수행된다.
}
```

## finally

예외 발생 여부와 상관없이 마지막에 반드시 실행되어야 하는 문장은 finally에 넣는다.

# 예외 정의하고 발생시키기

```java
**class FoolException extends RuntimeException {
}**

class FoolException extends RuntimeException {
}

public class Sample {
public void sayNick(String nick) {
if("fool".equals(nick)) {
**throw new FoolException();**
}
System.out.println("당신의 별명은 "+nick+" 입니다.");
}

public static void main(String[] args) {
Sample sample = new Sample();
sample.sayNick("fool");
sample.sayNick("genious");
}
}
```

# 예외 던지기(미루기)

```java
class FoolException extends Exception {
}
```

Runtime이 아닌 Exception을 정의했다.

```java
public class Sample {
public void sayNick(String nick) {
try {
if("fool".equals(nick)) {
throw new FoolException();
}
System.out.println("당신의 별명은 "+nick+" 입니다.");
}catch(FoolException e) {
System.err.println("FoolException이 발생했습니다.");
}
}

public static void main(String[] args) {
Sample sample = new Sample();
sample.sayNick("fool");
sample.sayNick("genious");
}
}
```

반드시 예외처리를 해야하기 때문에 해주었다. FoolException이 발생한 곳에서 예외처리를 하는 것이 아니라 sayNick을 호출한 곳에서 예외처리 하도록 예외처리를 던지는(미루는) 방법이 있다.

```java
public class Sample {
public void sayNick(String nick) throws FoolException {
~try {~ // try .. catch 문을 삭제할수 있다.
if("fool".equals(nick)) {
throw new FoolException();
}
System.out.println("당신의 별명은 "+nick+" 입니다.");
}~catch(FoolException e) {
System.err.println("FoolException이 발생했습니다.");
}~
}

public static void main(String[] args) {
Sample sample = new Sample();
**try { // 이제 sayNick을 호출하는 main에서 예외처리 해주어야 한다**
sample.sayNick("fool");
sample.sayNick("genious");
**} catch (FoolException e) {
System.err.println("FoolException이 발생했습니다.");
}**
}
}
```