1. 인터페이스와 추상 클래스란?
인터페이스란?
추상 클래스란?
- 공통점
- 추상클래스와 인터페이스는 선언부만 있고 구현 내용이 없는 클래스이다.
- 자기 자신이 직접 객체를 생성할 수 없으며, 자식 클래스가 추상클래스를 상속(extends)받거나, 인터페이스를 구현(implements)하여 객체를 생성할 수 있다.
- 선언된 타입과 자식 타입이 같아야 한다.
- 차이점
- 인터페이스
- 상속이 아닌 기능 구현에 사용한다.
- 다중 상속이 가능하다.
- 아주 간단한 설계도로 생각하면 편하고 이때 메소드 바디를 작성하면 안 된다.(선언만 가능)
- implements 구현한다.
- 추상 클래스
- 다중 상속이 불가하다.
- 상속 관계가 필요할 때 사용한다.(그러나 요즘 추세는 인터페이스를 사용하는 것이다. 여러 상속 관계가 얽히면 복잡해지기 때문)
- 인터페이스보다는 더 구체적인 설계도이다.
- extends 확장한다.
- 객체 생성이 불가하다.
- 인터페이스
2. Number class 구현
package number;
public abstract class MyNumber{
abstract MyNumber add(MyNumber myNumber);
abstract MyNumber subtract(MyNumber myNumber);
abstract MyNumber multiply(MyNumber myNumber);
abstract MyNumber divide(MyNumber myNumber);
abstract int toInt();
abstract double toDouble();
}
- 추상 클래스와 인터페이스는 아주 간단한 역할만 한다.
- 이 안에 모든 기능을 넣으려고 할 필요는 없다.
3. Rational class 구현
package number;
import org.jetbrains.annotations.NotNull;
public class MyRationalNumber extends MyNumber{
private int numerator;
private int denominator;
/** 생성자
* 분자(numerator)
* -----------------
* 분모 (denominator)
* **/
public MyRationalNumber() {
this.numerator = 0;
this.denominator = 1;
}
public MyRationalNumber(int num) {
this.numerator = num;
this.denominator = 1;
}
public MyRationalNumber(int num, int deno){
if (deno == 0) {
throw new IllegalArgumentException("분모는 0이 될 수 없습니다.");
} else if (deno < 0) {
numerator = -num;
denominator = -deno;
}
//최대공약수를 구해 약분해준다.
int gcd = getGCD(Math.abs(num), Math.abs(deno));
this.numerator = num/gcd;
this.denominator = deno/gcd;
}
private int getGCD(int num, int deno) {
if (deno == 0){
return num;
}
return getGCD(deno, num%deno);
}
public int getNumerator() {
return this.numerator;
}
public int getDenominator() {
return this.denominator;
}
@Override
public String toString() {
return numerator + "/" + denominator;
}
/** 사칙연산
* 더하기 (유리수끼리 전부 가능)
* 빼기
* 곱하기
* 나누기
* **/
@Override
public MyRationalNumber add(MyNumber myNumber) {
if (!(myNumber instanceof MyRationalNumber)){
// 해당 객체가 유리수가 아닌 경우라면 예외를 던져 처리
throw new IllegalArgumentException("Number is not rational number");
}
return new MyRationalNumber(this.numerator *((MyRationalNumber)myNumber).getDenominator()
+this.denominator*((MyRationalNumber)myNumber).getNumerator(),
this.denominator*((MyRationalNumber)myNumber).getDenominator()
);
}
@Override
public MyRationalNumber subtract(MyNumber myNumber) {
if (!(myNumber instanceof MyRationalNumber)){
throw new IllegalArgumentException("Number is not rational number");
}
return new MyRationalNumber(this.numerator *((MyRationalNumber)myNumber).getDenominator()
-this.denominator*((MyRationalNumber)myNumber).getNumerator(),
this.denominator*((MyRationalNumber)myNumber).getDenominator()
);
}
@Override
public MyRationalNumber multiply(MyNumber myNumber) {
if (!(myNumber instanceof MyRationalNumber)){
throw new IllegalArgumentException("Number is not rational number");
}
return new MyRationalNumber(this.numerator *((MyRationalNumber)myNumber).getDenominator()
, this.denominator * ((MyRationalNumber)myNumber).getDenominator()
);
}
@Override
public MyRationalNumber divide(MyNumber myNumber) {
if (!(myNumber instanceof MyRationalNumber)){
throw new IllegalArgumentException("Number is not rational number");
}
if (((MyRationalNumber)myNumber).getDenominator() == 0){
throw new ArithmeticException("0으로는 나눌 수 없습니다.");
}
return new MyRationalNumber(
this.numerator *((MyRationalNumber)myNumber).getDenominator()
, this.denominator * ((MyRationalNumber)myNumber).getDenominator()
);
}
@Override
int toInt() {
return this.numerator/this.denominator; }
@Override
double toDouble() {
return this.numerator / (double)this.denominator;
}
/**
*
* 해당 사칙연산은 자식의 메소드에 리턴타입이 부모 메서드와 다르게 구성되어있다.
* 이런 경우는 java에서만 허용되는 코드이며,
* 1. 원시타입이 아닐 경우
* 2. 부모(상위) 클래스의 메서드의 반환형으로 오버라이드된 메서드의 반환형이 자동 형변환 가능한 경우
* 위의 두가지에 한해서 상위 클래스와 반환 타입이 다를때도 override가 가능하다.
* 원칙적으로는(오버라이드의 경우) 리턴타입, 메소드 이름, 매개변수가 모두 같아야 한다.
* 오버로딩의 경우엔 반환타입은 상관 없고 매개변수만 신경쓰면 된다.
* **/
}
이 상속 클래스 작성에 주의한(할) 점
- 불필요한 필드 사용 자제 (일회성이 강한 변수의 경우 필드로 만들어 사용하지 말자)
- 예외 처리를 신경써서 진행한다.
- 직접 변수의 값을 변경하기보다는 getter을 사용하자
4. NaturalNumber class & IntegerNumber class 구현
package number;
import org.jetbrains.annotations.NotNull;
public class MyIntegerNumber extends MyRationalNumber{
public MyIntegerNumber() {
super();
}
public MyIntegerNumber(int num) {
super(num);
}
int getValue(){
return this.getNumerator();
}
@Override
public MyIntegerNumber add(@NotNull MyNumber myNumber) {
if (!(myNumber instanceof MyIntegerNumber)){
throw new IllegalArgumentException("정수가 아닙니다.");
}
return new MyIntegerNumber(this.getValue() + ((MyIntegerNumber)myNumber).getValue());
}
@Override
public MyIntegerNumber subtract(@NotNull MyNumber myNumber) {
if (!(myNumber instanceof MyIntegerNumber)){
throw new IllegalArgumentException("정수가 아닙니다.");
}
return new MyIntegerNumber(this.getValue() - ((MyIntegerNumber)myNumber).getValue());
}
@Override
public MyIntegerNumber multiply(@NotNull MyNumber myNumber) {
if (!(myNumber instanceof MyIntegerNumber)){
throw new IllegalArgumentException("정수가 아닙니다.");
}
return new MyIntegerNumber(this.getValue() * ((MyIntegerNumber)myNumber).getValue());
}
@Override
public MyIntegerNumber divide(@NotNull MyNumber myNumber) {
if (!(myNumber instanceof MyIntegerNumber)){
throw new IllegalArgumentException("정수가 아닙니다.");
}
if (((MyIntegerNumber)myNumber).getValue() == 0){
throw new ArithmeticException("0으로는 나누지 못합니다.");
}
return new MyIntegerNumber(this.getValue() / ((MyIntegerNumber)myNumber).getValue());
}
}
package number;
import org.jetbrains.annotations.NotNull;
public class MyNaturalNumber extends MyIntegerNumber{
public MyNaturalNumber() {
super();
}
public MyNaturalNumber(int num) {
super(num);
if (num <= 0) {
throw new IllegalArgumentException("자연수가 아닙니다.");
}
}
public MyNaturalNumber add(@NotNull MyNaturalNumber myNumber) {
if (!(myNumber instanceof MyIntegerNumber)){
throw new IllegalArgumentException("정수가 아닙니다.");
}
return new MyNaturalNumber(this.getValue() + myNumber.getValue());
}
public MyNaturalNumber subtract(@NotNull MyNaturalNumber myNumber) {
return new MyNaturalNumber(this.getValue() - myNumber.getValue());
}
public MyNaturalNumber multiply(@NotNull MyNaturalNumber myNumber) {
return new MyNaturalNumber(this.getValue() * myNumber.getValue());
}
public MyNaturalNumber divide(@NotNull MyNaturalNumber myNumber) {
return new MyNaturalNumber(this.getValue() / myNumber.getValue());
}
}
'Back-End > 백엔드 관련 정리' 카테고리의 다른 글
[백엔드 과정][자바 기초] - 큐 구현하기 (1. ArrayList를 이용한 구현) (0) | 2022.09.06 |
---|---|
[백엔드 과정][자바 기초] - 스택 구현하기 (2.LinkedList를 이용한 구현) (0) | 2022.09.06 |
[백엔드 과정][자바 기초] - 스택 구현하기 (1. ArrayList를 이용한 구현) (0) | 2022.09.06 |
[백엔드 과정][자바 기초] - hashCode와 equals 그리고 TreeSet과 HashSet (0) | 2022.08.31 |
[백엔드 과정][자바 기초] - call - by - value (0) | 2022.08.31 |