[Java] OOP, 오버라이딩, abstract, Interface, template pattern, Exception

JH·2023년 3월 23일

Java

목록 보기
4/21

1. TIL

A. 오버라이딩 (Overriding)

  • 부모클래스로부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것을 오버라이딩이라고 함
  • 자식 객체가 부모클래스의 필드에 있는 값을 직접 사용할 수 있음

1. 오버라이딩의 조건

1. 선언부가 같아야 한다.(이름, 매개변수, 리턴타입)

2. 접근제어자를 좁은 범위로 변경할 수 없다.

  • 조상의 메서드가 protected라면, 범위가 같거나 넓은 protected나 public으로 만 변경할 수 있다.

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
	}		
}

2. InstanceOf

참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용

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); // 에러
	}
}

3. Equals Override

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
	}
}


B. abstract (추상)

추상클래스 : 추상메소드를 포함하고 있는 클래스
추상메소드 : 선언부만 있고 구현부가 없는 메소드

  • 클래스가 설계도라면 추상클래스는 미완성 설계도

  • 완성된 설계도가 아니므로 객체(인스턴스)를 생성할 수 없음

  • 추상클래스를 상속받는 자식클래스는 추상메소드의 구현부를 완성해야함

Computer (추상클래스)

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() {};
}

ComputerTest (main)

package test05.abstractex;

public class ComputerTest {

	public static void main(String[] args) {
		
//		Computer computer = new Computer(); // 에러 : 추상 클래스이므로 객체 생성안됨
		// Desktop 객체 : Desktop은 추상클래스가 아니므로 객체 생성 가능
		Desktop desktop = new Desktop();
	}
}

Desktop (자식클래스)

package test05.abstractex;

public class Desktop extends Computer{

	// 상속을 받을 때 부모 클래스의 추상 메소드를 Overriding 시켜야 함
	@Override
	void turnOn() {}

	@Override
	void turnOff() {}
}


C. Interface

  • 일종의 추상클래스, 추상클래스보다 추상화 정도가 높음

  • 미리 정해진 규칙에 맞게 구현하도록 표준을 제시하는 데 사용됨

  • 추상메서드와 상수만을 멤버로 가짐

  • 인스턴스를 생성할 수 없음

  • abstract 생략 가능, 기본적으로 추상 메소드로 인식함

  • 인터페이스는 다중 상속이 가능

  • 클래스와 인터페이스를 동시에 사용 가능

  • 다른 두 인터페이스에서 메소드 이름이 같으면 구별 안됨, 오버라이딩된 자식 메소드가 선택됨

1. 인터페이스의 장점

  • 개발시간을 단축시킬 수 있음

  • 표준화가 가능함

  • 서로 관계없는 클래스들에게 관계를 맺어줌

  • 독립적인 프로그래밍이 가능함


Interface

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;
	}
}

main

package test06interfaceex;

public class CalculatorTest {

	public static void main(String[] args) {
    	// 객체아님, Calculator타입
		Calculator calculator = new Calculator();
		System.out.println(calculator.add(1, 2)); // 3
	}
}


D. template pattern

  • final 키워드를 사용해서 메소드를 오버라이딩 할 수 없게 하는 것이 특징
  • 여러 자식클래스가 변경 우려가 없는 하나의 메소드를 사용하므로 재사용성이 좋음

Car (추상클래스)

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();
	}
}

자식클래스 a

package test07template;

public class ManualCar extends Car{

	@Override
	public void drive() {
		System.out.println("사람이 운전합니다.");
	}
    
	@Override
	public void stop() {
	System.out.println("사람이 브레이크를 밟아 정지합니다.");
	}
}

자식클래스 b

package test07template;

public class AICar extends Car{

	@Override
	public void drive() {
		System.out.println("AI가 자율주행 합니다.");
	}

	@Override
	public void stop() {
		System.out.println("AI가 스스로 정지합니다.");
	}
}

main

package step07template;

public class CarTest {

	public static void main(String[] args) {
		ManualCar mCar = new ManualCar();
		AICar aiCar = new AICar();
		
        // 템플릿 패턴 활용
		mCar.run(); // 시동을 켭니다.
					// 사람이 운전합니다.
					// 사람이 브레이크를 밟아 정지합니다.
					// 시동을 끕니다.
		aiCar.run(); // 생략
	}
}


E. Exception (예외)

1. 예외 : 개발자가 처리할 수 있는 에러

  • runtimeException : 실행할 때 예외 처리됨

  • compileException : 컴파일 할 때 예외 처리됨

  • Exception 이라는 부모클래스가 존재함

자주 보는 예외

  • NullPointException : 값이 비어있음

  • NumberFormatException : 기본타입으로 변경할 수 없음

  • ArithmeticException : 수학적 연산이 안됨

  • ClassCastException : 형변환이 안됨

2. try-catch-finally

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 블럭 제일 마지막에 사용한다.
		}
		// 각각 처리하는 걸 권장함
	}
}

3. 사용자 정의 예외

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);
	}
}


2. 에러

금일 에러는 없었음, 대부분의 예외는 import를 생략한 경우 였음


3. 보완 해야 할 것

추상 클래스, 추상 메소드, 인터페이스, 템플릿패턴 비슷한 유형 같으면서 다른 내용들이라 헷갈린다.

이해가 되긴 하지만 어떠한 상황에서 사용하면 좋을지 고민이 된다.


4. 느낀점

Java의 3특징인 캡슐화, 단일 상속, 다형성중에
캡슐화, 단일 상속을 조금씩 활용하는 것 같다.

OOP, 추상, 템플릿, 예외까지 오늘 참 많은 것을 보았다.

예외까지 상속이 되는 것이 정말 지독했다.

profile
잘해볼게요

0개의 댓글