1. 선언부가 같아야 한다.(이름, 매개변수, 리턴타입)
2. 접근제어자를 좁은 범위로 변경할 수 없다.
3. 조상클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
예시
package test02.oop;
// 생성자 생략
class Parent3 extends Object{
String name;
// 어노테이션 (Annotation) : 오버라이딩을 컴파일러가 체크함
@Override
public String toString() {
return name ;
}
}
class Child3 extends Parent3{
String nickName;
@Override
public String toString() {
// name : 상속 받아서 사용 가능
return name + " " +nickName;
}
}
public class Ex03Child {
public static void main(String[] args) {
Parent3 p3 = new Parent3();
p3.name = "java";
System.out.println(p3); // java
Child3 c3 = new Child3();
c3.name = "it";
c3.nickName = "dev";
System.out.println(c3); // it , dev
}
}
참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용
package test03.oop;
class A {}
class B extends A {}
class C extends A {}
public class InstanceOf {
public static void main(String[] args) {
// 부모 A 타입의 B, C 객체
A b = new B();
A c = new C();
// Syntax : 객체 instanceOf 타입
System.out.println(b instanceof A); // true
System.out.println(b instanceof B); // true
System.out.println(b instanceof C); // false
System.out.println(c instanceof A); // true
System.out.println(c instanceof B); // false
System.out.println(c instanceof C); // true
B b2 = new B();
System.out.println(b2 instanceof A); // true
System.out.println(b2 instanceof B); // true
// System.out.println(b2 instanceof C); // 에러
}
}
package test04.override;
// 1. instanceof로 일단 타입 변환이 되는지 확인
// 2. 조건에 부합하면 파라미터로 받은 객체를 Person 타입으로 형변환
// 3. if문을 활용하여 조건 만들기
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
// equals 재정의
@Override
public boolean equals(Object o) {
if (o instanceof Person) {
Person p = (Person) o;
if (this.name.equals(p.name) && this.age == p.age) {
return true;
}
}
return false;
}
}
class Person2 {
String name;
int age;
Person2(String name, int age) {
this.name = name;
this.age = age;
}
}
public class EqualsOverride {
public static void main(String[] args) {
Person p = new Person("java", 28);
Person p1 = new Person("java", 28);
Person2 p2 = new Person2("java", 28);
// 같은 타입 && 같은 이름 && 같은 나이 ==> 같은 객체
System.out.println(p.equals(p1)); // true
System.out.println(p1.equals(p2)); // false
}
}
추상클래스 : 추상메소드를 포함하고 있는 클래스
추상메소드 : 선언부만 있고 구현부가 없는 메소드
클래스가 설계도라면 추상클래스는 미완성 설계도
완성된 설계도가 아니므로 객체(인스턴스)를 생성할 수 없음
추상클래스를 상속받는 자식클래스는 추상메소드의 구현부를 완성해야함
package test05.abstractex;
// abstract을 사용
// 추상클래스 : 상속을 강제하고 추상 메소드 사용을 위해 사용
public abstract class Computer {
public void display() {
System.out.println("컴퓨터 화면 출력 기능");
}
abstract void typing();
// 전원 on/off
abstract void turnOn();
abstract void turnOff();
// 테스트 기능
public void test() {};
}
package test05.abstractex;
public class ComputerTest {
public static void main(String[] args) {
// Computer computer = new Computer(); // 에러 : 추상 클래스이므로 객체 생성안됨
// Desktop 객체 : Desktop은 추상클래스가 아니므로 객체 생성 가능
Desktop desktop = new Desktop();
}
}
package test05.abstractex;
public class Desktop extends Computer{
// 상속을 받을 때 부모 클래스의 추상 메소드를 Overriding 시켜야 함
@Override
void turnOn() {}
@Override
void turnOff() {}
}
일종의 추상클래스, 추상클래스보다 추상화 정도가 높음
미리 정해진 규칙에 맞게 구현하도록 표준을 제시하는 데 사용됨
추상메서드와 상수만을 멤버로 가짐
인스턴스를 생성할 수 없음
abstract 생략 가능, 기본적으로 추상 메소드로 인식함
인터페이스는 다중 상속이 가능
클래스와 인터페이스를 동시에 사용 가능
다른 두 인터페이스에서 메소드 이름이 같으면 구별 안됨, 오버라이딩된 자식 메소드가 선택됨
개발시간을 단축시킬 수 있음
표준화가 가능함
서로 관계없는 클래스들에게 관계를 맺어줌
독립적인 프로그래밍이 가능함
package test06interfaceex;
public interface Calculation {
// public static final double PI = 3.14;
double PI =3.14; // 앞에 생략 가능
// 추상 메소드
public int add(int x, int y);
public int sub(int x, int y);
}
package test06interfaceex;
// implements 로 상속
public class Calculator implements Calculation{
@Override
public int add(int x, int y) {
return x + y;
}
@Override
public int sub(int x, int y) {
return x - y;
}
}
package test06interfaceex;
public class CalculatorTest {
public static void main(String[] args) {
// 객체아님, Calculator타입
Calculator calculator = new Calculator();
System.out.println(calculator.add(1, 2)); // 3
}
}
package test07template;
public abstract class Car {
// 공통 메소드
public void turnOn() {
System.out.println("시동을 켭니다.");
}
public void turnOff() {
System.out.println("시동을 끕니다.");
}
// 특정 정의 추상메소드
public abstract void drive();
public abstract void stop();
// 템플릿 패턴 : overriding되면 안되므로 final을 사용함
final public void run() {
turnOn();
drive();
stop();
turnOff();
}
}
package test07template;
public class ManualCar extends Car{
@Override
public void drive() {
System.out.println("사람이 운전합니다.");
}
@Override
public void stop() {
System.out.println("사람이 브레이크를 밟아 정지합니다.");
}
}
package test07template;
public class AICar extends Car{
@Override
public void drive() {
System.out.println("AI가 자율주행 합니다.");
}
@Override
public void stop() {
System.out.println("AI가 스스로 정지합니다.");
}
}
package step07template;
public class CarTest {
public static void main(String[] args) {
ManualCar mCar = new ManualCar();
AICar aiCar = new AICar();
// 템플릿 패턴 활용
mCar.run(); // 시동을 켭니다.
// 사람이 운전합니다.
// 사람이 브레이크를 밟아 정지합니다.
// 시동을 끕니다.
aiCar.run(); // 생략
}
}
runtimeException : 실행할 때 예외 처리됨
compileException : 컴파일 할 때 예외 처리됨
Exception 이라는 부모클래스가 존재함
NullPointException : 값이 비어있음
NumberFormatException : 기본타입으로 변경할 수 없음
ArithmeticException : 수학적 연산이 안됨
ClassCastException : 형변환이 안됨
package test01.exception;
class Info {
static {
System.out.println("Info 클래스");
}
}
public class Ex02Exception {
public static void main(String[] args) {
// step01 : 예외 발생 ~ 처리 (기본)
try {
// 패키지의 이름과 클래스 명까지 입력해야 함
Class.forName("test01.exception.Info");
} catch (ClassNotFoundException e) {
// e.printStackTrace() : 개발시에만 사용
e.printStackTrace();
} finally {
// ex : 주로 외부 자원을 반환할 떄 사용
System.out.println("finally block");
}
// step02 : 다중 예외 처리
// Exception이 최상위 타입이므로
// catch Exception e으로 한꺼번에 처리 가능, 권장 X
try {
// NPE
String str1 = null;
System.out.println(str1.length());
// NumberFormatException
String str2 = "three";
Integer.parseInt(str2);
// 같은 예외 해결 코드 일 때
} catch (NullPointerException | NumberFormatException e){
e.printStackTrace();
System.out.println("같은 예외 해결 코드");
} catch (Exception e) {
// 최상위에 Exception이 있으면 아래 자식 Exception을 사용할 수 없음
// Exception은 catch 블럭 제일 마지막에 사용한다.
}
// 각각 처리하는 걸 권장함
}
}
package test01.exception;
import exception.NotAdminException;
// 예외는 메소드에서 직접 또는 던져서 처리함
public class Login {
// 맨 뒤에 throws를 사용하여 예외를 던져줌
public static void checkAdmin(String id) throws NotAdminException{
if("admin".equals(id)) {
System.out.println("관리자 로그인 성공");
} else {
//예외 발생 문법
throw new NotAdminException("관리자 로그인 실패");
}
}
// main 에서 예외 처리
public static void main(String[] args) {
String id = "admin";
try {
checkAdmin(id);
} catch (NotAdminException e) {
System.out.println(e.getMessage());
}
}
}
package exception;
// 예외 클래스로 만들기 : Ex 상속
public class NotAdminException extends Exception{
// 사용자 정의 생성자
public NotAdminException (String msg) {
super(msg);
}
}
금일 에러는 없었음, 대부분의 예외는 import를 생략한 경우 였음
추상 클래스, 추상 메소드, 인터페이스, 템플릿패턴 비슷한 유형 같으면서 다른 내용들이라 헷갈린다.
이해가 되긴 하지만 어떠한 상황에서 사용하면 좋을지 고민이 된다.
Java의 3특징인 캡슐화, 단일 상속, 다형성중에
캡슐화, 단일 상속을 조금씩 활용하는 것 같다.
OOP, 추상, 템플릿, 예외까지 오늘 참 많은 것을 보았다.
예외까지 상속이 되는 것이 정말 지독했다.