728x90

String 클래스

== 와 equals()

  • == : 비교하는 두 대상의 주소값을 비교
  • equals() : 비교하는 두 대상의 값을 비교
public class StringExam {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        String str3 = new String("hello");
        String str4 = new String("hello");

        System.out.println(str1 == str2);      // true
        System.out.println(str1.equals(str2)); // true

        System.out.println(str2 == str3);      // false
        System.out.println(str2.equals(str3)); // true

        System.out.println(str3 == str4);      // false
        System.out.println(str3.equals(str4)); // true
    }
}

추상 클래스

  • abstract 키워드를 사용하여 클래스를 정의한다.
  • 확장 만을 위한 용도로 정의되는 클래스
  • 추상 클래스는 인스턴스가 될 수 없다.
  • 추상 클래스를 상속받는 자손이 인스턴스가 된다.
  • 추상 클래스는 보통 1개 이상의 추상 메소드를 가진다. (없어도 오류 발생은 X)
public abstract class 클래스명 { ... }

추상 메소드

  • 추상 메소드는 메소드에 대한 구현을 가지지 않는다.
  • 추상 클래스의 자식 클래스가 해당 메소드를 구현 하도록 강요하기 위해 존재
  • 추상 메소드는 추상 클래스에만 조재할 수 있다.

✔ 추상 클래스를 사용하는 이유

  1. 공통된 필드와 메서드를 통일할 목적
    • 필드와 메서드 이름을 통일하여 유지보수성을 높이고 통일성을 유지할 수 있다.
  2. 실체 클래스 구현시, 시간절약
    • 강제로 주어지는 필드와 메서드를 가지고 실체 클래스의 성격대로 구현만 하면 된다.
    • 설계 시간이 절약되며, 구현하는데만 집중할 수 있다.
  3. 규격에 맞는 실체 클래스 구현
    • 공통된 속성은 규격에 맞게 구현할 수 있다는 의미
    • → 추상 클래스를 상속받은 실체 클래스들은 반드시 추상 메서드를 재정의해서 실행 내용을 작성해야 하기 때문
    • 그 외의 것은 자유롭게 구현이 가능하다.

중요한 것은, 소스 수정시 다른 소스의 영향도를 적게 가져가면서 변화에는 유연하게 만들기 위해 추상클래스를 사용한다는 점 !

추상클래스의 상속

  • 추상 클래스의 상속에도 extends 키워드 사용
  • 추상 클래스를 상속하는 클래스는 반드시 추상 클래스의 추상 메소드를 구현해야 함
  • 추상 클래스간의 상속에서는 추상클래스를 구현하지 않아도 됨
  • 추상 클래스의 추상 메소드를 상속받아 정의하는 예시
abstract class Shape {
    public abstract double calculateArea();
}

class Triangle extends Shape {
    private double x;
    private double y;

    public Triangle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public double calculateArea() {
        return this.x * this.y / 2;
    }
}

class Rectangle extends Shape {
    private double x;
    private double y;

    public Rectangle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public double calculateArea() {
        return this.x * this.y;
    }
}

public class ShapeDemo {
    public static void main(String[] args) {
        Shape triangle = new Triangle(10, 5);
        System.out.println("삼각형의 너비: " + triangle.calculateArea());

        Shape rectangle = new Rectangle(10, 20);
        System.out.println("사각형의 너비: " + rectangle.calculateArea());
    }
}
  • 추상 클래스의 연속 상속
abstract class Aclass {
	public abstract void Amethod();  // 추상 메소드
}
abstract class Bclass extends Aclass { // 추상 클래스를 상속받은 추상 클래스
	public abstract void Bmethod();
}

public class Cclass extends Bclass {
	public void Amethod() { ... } // 반드시 구현해야 함
	public void Amethod() { ... } // 반드시 구현해야 함
**}**

템플릿 메소드 패턴(Template Method Pattern)

  • 디자인 패턴 중 하나로, 알고리즘의 구조를 메소드에 정의하고,
  • 알고리즘의 일부 단계를 서브클래스에서 구현하도록 하여 알고리즘의 일부 변경을 허용하는 패턴이다.
  • → 공통의 알고리즘 과정이 있지만, 그 과정 중 일부가 클래스마다 다를 때 유용하다.
  • 추상 클래스를 사용하여 템플릿 메소드를 정의하고, 구체적인 작업은 서브클래스에서 오버라이드하여 구현

구조

  • 추상 클래스(Abstract Class)
    • 알고리즘의 단계를 정의하는 템플릿 메소드와 알고리즘의 일부를 구현하는 하나 이상의 추상 메소드로 구성
  • 구체 클래스(Concrete Class)
    • 추상 클래스를 상속받아 추상 메소드를 구현한다. (알고리즘의 일부 단계를 구체화)
abstract class BeverageRecipe {
    public **final** void prepareRecipe() {  // 템플릿 메소드
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    abstract void brew(); // 추상 메소드

    abstract void addCondiments(); // 추상 메소드

    public void boilWater() {
        System.out.println("물을 끓입니다.");
    }

    public void pourInCup() {
        System.out.println("컵에 따릅니다.");
    }
}

class Coffee extends BeverageRecipe {
    @Override
    void brew() {
        System.out.println("필터를 통해 커피를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("설탕과 우유를 추가합니다.");
    }
}

class Tea extends BeverageRecipe {
    @Override
    void brew() {
        System.out.println("차를 우려냅니다.");
    }

    @Override
    void addCondiments() {
        System.out.println("레몬을 추가합니다.");
    }
}

public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        BeverageRecipe tea = new Tea();
        tea.prepareRecipe();

        BeverageRecipe coffee = new Coffee();
        coffee.prepareRecipe();
    }
}

Java Interface

개념

  • 서로 관계가 없는 물체들이 상호 작용을 하기 위해서 사용하는 장치나 시스템
  • 클래스 구조상의 관계와 상관 없이 클래스들에 의해 구현되어질 수 있는 규약

목적

  • 클래스들 사이의 유사한 특성을 부자연스러운 상속 관계를 설정하지 않고 얻어냄

활용

  • 하나 또는 그 이상의 클래스들에서 똑같이 구현되어질 법한 메소드를 선언하는 경우
  • 클래스 자체를 드러내지 않고 객체의 프로그래밍 인터페이스를 제공하는 경우

클래스 vs 인터페이스

  • 완결한 메소드(Concrete method)
    • 메소드의 구현을 포함한 일반적인 메소드를 concrete method라 함
    • 추상 메소드(Abstract Method)의 반대 개념

✔ 인터페이스의 상속

  • 인터페이스는 다중 상속을 지원하지 않는 자바에서 다중 상속의 장점을 활용하기 위해 도입
  • 한 클래스는 하나의 부모 클래스를 가지며 하나 이상의 인터페이스를 구현할 수 있다.
  • 인터페이스 사이에서는 다중 상속이 가능하다.
  • interface 키워드로 선언하고 implements 키워드로 사용
  • 인터페이스를 구현한 클래스에서 추상 메소드를 반드시 정의해야 함
interface Ainter {
    public void aMethod();
    public void same();
}
interface Binter extends Ainter{
    public void bMethod();
}
interface Cinter{
    public void cMethod();
    public void same();
}
interface Dinter extends Cinter, Binter{
    // 인터페이스들 간에는 다중 상속이 가능하다.
    public void dMethod();
}
class DImpl implements Dinter{
    @Override
    public void aMethod() {
        System.out.println("aMethod 구현");
    }
    @Override
    public void bMethod() {

    }
    @Override
    public void same() {

    }
    @Override
    public void cMethod() {
        System.out.println("aMethod 구현");
    }
    @Override
    public void dMethod() {
        System.out.println("aMethod 구현");
    }
}

public class InterfaceDemo{
    public static void main(String[] args) {
        // 인터페이스도 타입이다.
        Ainter ainter = new DImpl();
        Cinter cInter = new DImpl();

        // 자기가 정의한 것만 사용 가능
        ainter.aMethod();
        cInter.cMethod();

        Binter binter = new DImpl();
        Dinter dinter = new DImpl();

        binter.aMethod();
        binter.bMethod();
        binter.same();

        /* 타입이 아는 것 까지만 쓸 수 있고,
         * 외의 것을 쓰고 싶다면 형변환이 필요 */
        ((DImpl)ainter).say();
    }
}

default 메소드

  • 인터페이스가 default 키워드로 선언되면 메소드가 구현될 수 있다.
  • 또한 이를 구현하는 클래스는 default 메소드를 오버라이딩 할 수 있다.
  • 인터페이스가 변경이 되면, 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제가 있다.
  • → 이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현해 놓을 수 있도록 함
interface Calculator {
    public int plus(int i, int j);

    public int multiple(int i, int j);

    default int exec(int i, int j) {  // default로 선언함으로 메소드를 구현할 수 있다.
        return i + j;
    }
}

class MyCalculator implements Calculator {
    @Override
    public int plus(int i, int j) {
        return i + j;
    }

    @Override
    public int multiple(int i, int j) {
        return i * j;
    }
}

public class CalculatorDemo {
    public static void main(String[] args) {
        Calculator cal = new MyCalculator();

        System.out.println(cal.plus(5, 10));
        System.out.println(cal.multiple(5, 10));
        
        int value = cal.exec(5, 10);
        System.out.println(value);
    }
}

인터페이스의 static

변수

  • 인터페이스에서 int a = 10; 과 같이 멤버 변수를 선언하게 되면 static final 로서 선언된다. (생략 가능, 생략 하더라도 static final 로서 선언됨)
  • 즉, 인터페이스에서 변수를 선언하게 되면, 그 변수는 상수가 된다.
  • → 상수로서 변수와 구분을 위해 대문자로 선언하는 것이 관례이다.

static 메소드

  • 인터페이스에 static 메소드를 정의하는 것은, 클래스에 static 을 정의하는 것과 동일하다.
  • 인터페이스에서 메소드 구현이 가능하다.
  • 반드시 클래스 명으로 메소드를 호출해야 한다.
728x90

+ Recent posts