diff --git "a/Ch 11 \352\260\235\354\262\264\354\247\200\355\226\245.md" "b/Ch 11 \352\260\235\354\262\264\354\247\200\355\226\245.md" new file mode 100644 index 0000000..878e720 --- /dev/null +++ "b/Ch 11 \352\260\235\354\262\264\354\247\200\355\226\245.md" @@ -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 +``` \ No newline at end of file diff --git "a/Ch 12 \354\230\210\354\231\270\354\262\230\353\246\254.md" "b/Ch 12 \354\230\210\354\231\270\354\262\230\353\246\254.md" new file mode 100644 index 0000000..ad3667c --- /dev/null +++ "b/Ch 12 \354\230\210\354\231\270\354\262\230\353\246\254.md" @@ -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이 발생했습니다."); + }** + } +} +```