1. 인터페이스

인터페이스란?

일종의 추상 클래스이다. 오직 추상 메서드와 상수만을 멤버로 가질 수 있으며 추상 클래스보다 추상화 정도가 높다. 추상 클래스가 "미완성 설계도"라면 인터페이슨느 "기본 설계도"이다. 인터페이스도 다른 클래스를 도우는데 목적이 있다.

클래스를 이용한 다중 상속은 어느 클래스에 해당 메서드가 있는지 모호하기 때문에 다중 상속을 지원하지 않는다.

하지만 인터페이스는 다중 상속을 지원하고 다른 클래스를 작성할때 기본 틀이 되며 클래스 사이에서 중간 매개 역할을 하는 일종의 추상 클래스이다.

2. 인터페이스의 선언

인터페이스는 class 대신 interface 키워드를 접근 제어자와 같이 사용한다.

public interface 인터페이스 이름 {
    ...
}

2.1. 인터페이스의 제약 사항

모든 멤버 변수는 public static final 이어야 하며, 생략이 가능하다.

모든 메서드는 public abstract 이어야 하며, 생략이 가능하다. 단 static 과 default 메서드는 제어

생략된 제어자는 컴파일러가 자동으로 추가한다.

3. 인터페이스의 상속 과 구현

3.1. 상속

인터페이스는 인터페이스로 부터만 상속받을 수 있다.

다중 상속, 즉 여러 개의 인터페이스를 상속받을 수 있다.

Object와 같은 최상위 클래스가 없다.

3.2. 구현

인터페이스는 인스턴스를 생성할 수 없다.

인터페이스의 몸통을 구현해주는 클래스가 필요하다.

implements 키워드를 이용하여 인터페이스를 구현한다.

public interface Able {}

public interface Aable extends Able {}
public interface Bable extends Able {}

public class Sample implements Aable, Bable {
    ...
}

Sample 클래스는 Aable, Bable 인터페이스를 구현한다 라고 표현한다.

인터페이스에 메서드 중 일부만 구현 한다면 나머지 메서드는 하위 클래스에서 abstract를 붙여 추상 클래스로 선언한다.

또한 상속과 구현을 동시에 할수 있다.

public interface Able {}
public class Parent {}

public class Child extends Parent implements Able {}

인터페이스 명은 주로 'able'로 끝나도록 작성한다.

인터페이스도 instaceof를 통해 타입을 확인할 수 있다.

if(f instanceof Aable) {}

4. 인터페이스를 이용한 다중 상속

클래스의 다중 상속이 되지 않아 A는 상속 받고 B는 멤버 변수로 사용하는데 이때 인터페이스를 이용하여 다형적 특성을 유지할 수 있다.

public class A {}
public class B {void method() {}}

public interface Bable {
    void method() {}
}

public Sample extends A implements Bable {
    B b = new B(); // 멤버 변수로 B 인스턴스 생성
    
    void method() { // interface 구체화
        b.method(); // B 클래스의 메소드 실행
    }
}

5. 인터페이스를 이용한 다형성

상속 받은 하위 클래스를 인터페이스 타입으로 형 변환이 가능하다.

// 1. 형 변환
Bable b = (Bable) new B();

// 2. 메서드의 매개변수로 인터페이스 사용가능
public void method(Bable b) {} 
method(new B()); // 인자 값으로 B 클래스 사용

// 3. return 타입으로 인터페이스 지정 가능
public Bable method() {}

// 4. Manager 클래스를 통한 다형성
public class ParseManager {
    public static Parseable getParse(String type) {
        if(type.equals("1")) {
            return new Parse1();
        } else {
            return new Parse2();
        }
    }
}

public class Parse1 implements Parseable {}
public class Parse2 implements Parseable {}

public static void main(String[] args) {
    Parseable parser = ParseManager.getParse("2");
}

Manager의 getParse 함수로 Parseable로 구현된 클래스 인스턴스를 받아서 사용할 수 있다.

6. 인터페이스의 장점

  1. 개발 시간을 단축 시킬 수 있다.
    인터페이스와 이를 구현하는 클래스를 동시에 구현 가능하며 인터페이스를 구현하는 클래스의 개발을 기다리지 않아도 된다.
  2. 표준화가 가능하다.
    표준화 된 인터페이스를 개발자들에게 전달함으로써 일관되고 정형화된 개발이 가능하다.
  3. 서로 관계 없는 클래스들에게 관계를 맺어 줄 수 있다.
    관계없는 클래스들에게 공통의 인터페이스를 구현하도록 하여 관계를 맺어 줄 수 있다.
  4. 독립적인 프로그래밍 가능하다.
    클래스와 클래스의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경하면 클래스 간 서로 영향을 미치지 않아 독립적인 프래그래밍이 가능하다.
public class Marig {}
public Tank implements Repairable {}
public Scv implements Repairable {
    public int repair(Repairable r) {
        ...
    }
}

public static void main(String[] args) {
    Scv s = new Scv();
    
    s.repair(new Marin()); // Marin 클래스에 repair가 없어 에러
    s.repair(new Tank()); // 성공
}

위의 예제에서 Repariable에 아무런 멤버가 없지만 기계 유닛에 Repairable을 상속하면서 repair 메서드를 다양한 매개변수로 이용할 수 있다.

만약 4개의 클래스 중 2개의 클래스만 건물이동 메서드를 만들고 싶은 경우 각 클래스에 똑같은 메서드를 넣으면 중복이 생긴다. 그래서 인터페이스를 구현한 새로운 클래스를 각 클래스에서 멤버로 사용할 수 있다.

public class A implements Moveable {
	MoveImpl move = new MoveImpl();
}

public class B implements Moveable {
	MoveImpl move = new MoveImpl();
}

MoveImpl에서 Move메서드를 구현하여 A, B 클래스에서 호출만 하도록 한다.

7. 인터페이스의 이해

인터페이스의 이해 2가지 조건

  1. 클래스를 사용하는 쪽(User)와 제공하는 쪽(Provider)이 있다.
  2. 메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의 선언 부만 알고 내용은 몰라도 된다.

아래의 예제는 좋지 못한 예와 좋은 예이다.

// 좋지 못한 예
public class B {}
public class A {
    public void method(B b) {
        b.method();
    }
}

// 좋은 예
public interface Able {}
public class C implements Able {}
public class B implements Able {}
public class A implements Able {
    public void method(Able a) {
        a.method();
    }
}

public static void main(String[] args) {
    A a = new A();
    
    a.method(new B());
    a.method(new C());
}

좋지 못한 예의 경우 B클래스가 A클래스보다 먼저 작성되어 있어야 하고 B가 C로 변경되면 A도 변경해줘야 하는 단점이 있다.

좋은 예의 경우 A는 Able만 알고 있으면 되고 A의 method가 안에서 어떤 인스턴스의 메서드를 호출하는지 상관이 없는 장점이 있다.

8. default method와 static method

JDK 1.8부터 인터페이스에 default method와 static method를 추가할 수 있게 되었다.

Collection Interface와 Collections 클래스를 예제로 들 수 있으며 인터페이스의 static 메서드의 접근제어자는 항상 public이다.

8.1. default method

인터페이스에 변경이 생기면 인터페이스를 구현하는 모든 클래스에 변경이 생긴다. 그래서 default 메서드가 고안되었다.

default 메서드는 몸통이 있어야 하기 때문에 상속 클래스에서 변경점이 생기지 않는다. 즉, 상위 클래스에 메서드가 추가되는 것과 같다.

defulat메서드가 다른 메서드와 이름 충돌이 있을 수 있어 아래와 같은 해결책이 필요하다.

  1. 여러 인터페이스의 default 메서드 간 충돌
    - 인터페이스를 구현한 클래스에서 메서드를 오버라이딩 해야한다.
    public interface A {
        public int getAge();
    }
    
    public interface B {
        public int getAge();
    }
    
    public class Sample implements A, B {
        public int getAge() {
            ....
        }
    }​

default 메서드와 상위 클래스의 메서드 간 충돌
- 상위 클래스의 메서드가 상속되고 default 메서드는 무시된다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 예외 처리  (0) 2021.08.27
[Java] 내부 클래스  (0) 2021.08.27
[Java] 추상 클래스&추상 메서드  (0) 2021.08.26
[Java] 다형성  (0) 2021.08.25
[Java] 제어자  (0) 2021.08.25

1. 추상 클래스 (Abstract Class)

추상 클래스란?

미완성 설계도와 비슷한 의미로 미완성 메서드(추상 메서드)가 포함되어 있다는 것을 의미한다.

자바에서는 하나 이상의 추상 메서드를 포함하고 있는 클래스를 추상 클래스라고 한다.

이러한 추상 클래스는 객체 지향 프로그래밍에서 중요한 특징인 다형성을 지닌 메서드의 집합을 정의할 수 있게 한다.

추상 클래스에 정의되어 있는 추상 메서드는 추상 클래스를 상속받은 하위 클래스에서 각각의 정의가 필요하여 다양한 메서드가 만들어질 수 있다.

 

* 특징

  • 추상 클래스는 인스턴스를 생성할 수 없으며 반드시 하위 클래스에서 오버라이딩되어야만 사용할 수 있는 클래스이다.
  • 추상 메서드가 없더라도 추상 클래스로 선언할 수 있으며 추상 메서드가 존재한다는 것 외에 일반 클래스랑 동일하다.

1.1. 추상 클래스의 작성

추상 : 낱낱의 구체적 표상이나 개념에서 공통된 성질을 뽑아 이를 일반적인 개념으로 파악하는 정신 작용
추상화 : 클래스 간의 공통점을 찾아내서 공통의 상위를 만드는 작업
구체화 : 상속을 통해 클래스를 구현, 확장하는 작업

공통적인 부분을 뽑아서 추상 클래스로 만들어 상속하기도 한다.

주의할 점은 메서드는 실제 인스턴스의 메서드가 호출되며 Object 클래스로 선언하면 실제 인스턴스의 메서드가 Object에 없어 에러가 발생한다.

public abstract class Sample { // 추상 클래스
	public abstract int getAge() { // 추상 메서드
    	...
    }
}

 

2. 추상 메서드 (Abstract Method)

추상 메서드란?

선언부와 구현부 중 선언 부만 작성한 것을 의미한다. 구현 부인 {}(중괄호)를 작성하지 않고 선언부에서 ;(세미콜론)으로 선언부를 끝낸다.

// 매개변수로 special number를 받아 이름을 반환하는 메서드이다.
public abstract String getName(int sn);

주석을 통해 어떤 기능의 메서드인지 알려 상속받은 클래스에서 기능을 구현하도록 한다.

상속받은 하위 클래스에서 상위 추상 메서드를 모두 구현해야 하지만 구현하지 않은 메서드는 하위 클래스에서도 추상 메서드로 선언한다.

public abstract class Parent {
    public abstract int getAge();
    public abstract String getName();
}


public abstract class Child extends Parent {
    public int getAge() { // 추상메서드 구현
    	return 0;
    }
    
    public abstract String getName(); // 구현하지 않은 추상메서드
}

2.1. 추상 메서드 사용 목적

추상 메서드가 포함되어 있는 클래스를 하위 클래스에서 상속받았을 때 반드시 구현하도록 하기 위함이다.

모듈처럼 중복되는 부분이나 공통으로 미리 만들어 놓은 것을 사용하고, 사용하는 쪽에서 필요한 부분만 재정의하여 사용함으로써 생산성이 향상되고 배포 등이 쉬워진다.

추상 메서드가 포함되어있는 하위 클래스는 반드시 추상 메서드를 구현해야만 인스턴스를 생성할 수 있다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 내부 클래스  (0) 2021.08.27
[Java] 인터페이스  (0) 2021.08.27
[Java] 다형성  (0) 2021.08.25
[Java] 제어자  (0) 2021.08.25
[Java] Package와 import  (0) 2021.08.24

1. 다형성 (polymorphism)

다성형이란?
객체 지향 개념에서 다형성이란 '여러 가지 형태를 가질 수 있는 능력'을 의미한다.
자바에서 한 타입의 참조 변수로 여러 타입의 객체를 참조할 수 있도록 한다.

class Tv {
    int one;
    int two;
}

class CaptionTv extends Tv {
    int three;
}

CaptionTv c = new CaptionTv(); // 1번
Tv c = new CaptionTv(); // 2번

위의 예제에서 1번은 동일한 타입으로 모든 멤버를 사용 가능하고 2번은 CaptionTv에는 Tv가 가지고 있는 모든 멤버를 가지고 있어서 Tv 클래스 타입으로 참조 변수를 사용할 수 있다.
ex) CaptionTv c = new Tv();
하지만 위의 예제처럼 TV 클래스는 CaptionTv 클래스의 멤버를 가지고 있지 않기 때문에 인스턴스가 생성 불가능하다.

 

* 정리

  1. 부모 타입의 참조 변수로 자식 타입의 인스턴스를 참조할 수 있다.
  2. 반대로 자식 타입의 참조변수로 부모 타입의 인스턴스를 참조 할수 없다.

1.1. 참조 변수의 형 변환

참조 변수도 형 변환이 가능하며 상위 타입에서 하위 타입 뿐만 아니라 반대로도 형변환이 가능하며 상속 관계에 있는 모든 타입이 형변환 가능하다.
기본형의 형 변환과 마찬가지로 하위 타입이 상위 타입으로 자동 형변환 된다.

* 생략 여부

  • up-casting : 하위 타입 -> 상위 타입 // 형변환 생략 가능
  • down-casting : 상위 타입 -> 하위 타입 // 형변환 생략 불가

형 변환 시 캐스팅 연산자인 '(클래스)'를 사용한다.
down-casting에서만 캐스팅 연산자를 사용하는 이유는 down-casting 할 때 어떤 타입으로 갈 것인지 명시가 필요하기 때문이다.
형 변환은 인스턴스를 변환하는 것이 아닌 참조 변수를 변환하는 것이다.

Tv tv = (Tv) new CaptionTv();

2. instanceof 연산자

instanceof 연산자란?
참조 변수가 참조하고 있는 인스턴스에 실제 타입을 알아보기 위한 연산자이다.

if(c instanceof Parent) { // true or false
    ...
}

위의 예제는 참조 변수 c가 검사 타입인 Parent 클래스로 형 변환 여부를 체크하는 예제이다.

상위 타입의 참조 변수로 하위 타입의 인스턴스를 생성할 수 있기 때문에 instanceof로 타입 체크를 할 필요가 있다.
어떤 타입에 대한 instanceof연산의 결과가 true라는 것은 검사한 타입으로 형 변환이 가능하다는 뜻이다.

3. 참조 변수와 인스턴스의 연결

메서드의 경우 타입에 상관없이 항상 실제 인스턴스의 메서드(오버라이딩 된 메서드)가 호출된다.
멤버 변수의 경우 상위, 하위 클래스에서 중복으로 정의된 경우 상위 클래스에서는 상위 멤버를 하위 클래스에서 하위 멤버를 사용한다.

4. 매개변수의 다형성

메서드의 매개변수를 상위 클래스로 선언하고 매개변수로 하위 클래스를 받아 사용한다.

class Parent {}
class Child extends Parent {
    method(Parent p) {}
}

Child c = new Child();
c.method(new Child()) {}

5. 여러 종류의 객체를 배열로 다루기

상속 관계또

Product[] p = new Product[3];

p[0] = new Tv();
p[1] = new Computer();
p[2] = new Radio();

Vactor 클래스는 배열의 크기를 동적으로 관리한다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 인터페이스  (0) 2021.08.27
[Java] 추상 클래스&추상 메서드  (0) 2021.08.26
[Java] 제어자  (0) 2021.08.25
[Java] Package와 import  (0) 2021.08.24
[Java] 상속  (0) 2021.08.24

제어자

제어자란?

클래스와 클래스 멤버 선언 시 사용하여 부가적인 의미를 부여하는 키워드이다. 제어자에는 접근 제어자와 기타 제어자로 나뉜다.

1. 제어자의 종류

클래스, 변수, 메서드에 사용되면 접근 제어자는 한 가지만 사용 가능하다.

1.1. 접근 제어자

종류 : public, protected, default, private

1.2. 기타 제어자

종류 : static, final, abstract, native, tansient, synchronized, volatile, strictfp

1.2.1. static - 클래스의, 공통적인

클래스와 관계된 접근 자이며 사용하는 곳은 멤버 변수, 메서드, 초기화 블록이다.

1.2.2. final - 마지막의, 변경될 수 없는

  • 사용하는 곳 : 클래스, 메서드, 멤버 변수, 지역 변수
  • 클래스 : 상속받을 수 없는 클래스
  • 메서드 : 오버 라이딩될 수 없는 클래스
  • 멤버 변수, 지역변수 : 값을 변경할 수 없는 상수

생성자를 이용한 final 멤버 변수의 초기화 선언 시 초기화를 안 하고 생성자에서 단 한 번만 초기화한다. 선언과 동시에 초기화되면 모든 인스턴스는 같은 값을 갖게 되어 생성자에서 매개변수로 받아 초기화해준다.

class Sample {
    final int NUMBER;
    
    Sample(int n) {
        this.NUMBER = n;
    }
}

1.2.3. abstract - 추상의, 미완성의

  • 사용되는 곳 : 클래스, 메서드
  • 클래스 : 클래스 내에 추상 메서드가 선언되어 있음을 의미
  • 메서드 : 선언 부만 작성하고 구현부는 작성하지 않는 추상 메서드임을 알린다.

메서드 선언 부만 작성하고 로직은 구현하지 않는 추상 메서드를 선언하는 데 사용한다.

추상 클래스는 미완성 임으로 인스턴스를 생성할 수 없다.

인스턴스를 생성하지 못하도록 사용하기도 한다.

public abstract class Parent {
    public abstract int get();
    public abstract boolean set();
}

public Child extends Parent {
    public int get() {}
    public boolean set() {}
}

1.3. 접근 제어자 (access modifier)

사용되는 곳 : 클래스, 메서드, 멤버 변수, 생성자

1.3.1. 종류

  • private : 같은 클래스 내에서만 접근 가능
  • default : 같은 패키지 내에서만 접근 가능, 제어자를 지정하지 않으면 접근 제어자가 default임을 뜻
  • protected : 같은 패키지 내에서, 다른 패키지의 하위 클래스에서 접근 가능
  • public  : 접근 제한 없음

1.3.2. 범위 순서

public > protected > default > private

1.3.3. 대상에 따른 접근 제어자

  • 클래스 : public, (default)
  • 메서드, 멤버 변수 : public, protected, default, private
  • 지역 변수 : 없음

1.4. 접근 제어자를 이용한 캡슐화

  1. 외부로부터 데이터를 보호하기 위함
  2. 외부에서 불필요한 내부적으로만 사용되는 부분을 감추기 위함

메서드를 변경했을 때 접근 제어자에 따라 수정, 테스트해야 하는 부분이 달라질 수 있다. 또한 멤버 변수에 잘못된 값을 넣어도 막을 방법이 없어 멤버 변수를 private으로 하고 setter를 이용하여 유효성 검사를 마치고 변수를 변경한다.

public 클래스는 파일에 단 한 개만 존재 가능하고 public 클래스 이름과 파일 이름이 같아야 한다.

public class Sample {
    private int n; // 외부에서 접근 불가
    
    public setN(int n) { // 외부에서 접근 가능하기 때문에 생성자를 통해 내부로 들어와 private n 을 변경
        this.n = n;
    }
}

1.5. 생성자의 접근 제어자 (singleton)

생성자에 private 부여하여 외부에서 인스턴스 생성을 못하도록 막는다. 대신 public으로 인스턴스를 return 해주는 메서드를 제공하여 인스턴스를 받는다.

public class Singleton {
    private static Singleton s = new Singleton();
    
    private singleton() {}
    
    public static Singleton getInstance() {
    	return s;
    }
}


main() {
	Singleton s = Singleton.getInstance();
}

생성자가 private일 경우 상속 클래스로 사용 불가하다. 하위 인스턴스가 생성되면서 상위 인스턴스도 생성되어야 하는데 생성자가 없이 생성이 불가능하다.

1.6. 제어자 (modifier)의 조합

대상 사용가능 제어자
클래스 public, default, protected, private
메서드 모든 접근 제어자, final, abstract, static
멤버 변수 모든 접근 제어자, final, static
지역 변수 final

1.7. 제어자 조합의 주의

  1. 메서드에 static과 abstract를 같이 사용할 수 없다.
    - static은 구현 부분이 있는 메서드에만 사용 가능하다.
  2. 클래스에 final과 abstract를 동시에 사용할 수 없다.
    - final은 확장이 불가고 abstract는 상속을 통해 완성되기 때문에 모순이다.
  3. abstract 메서드에 접근제어자는 private을 사용할 수 없다.
    - abstract는 하위 클래스에서 완성시켜야 하는데 private은 하위 클래스에서 접근이 불가능하다.
  4. 메서드에 final과 priavet을 같이 사용할 필요 없다.
    - 둘 다 같은 의미라 하나만 사용해도 된다.

'개발 언어 > Java' 카테고리의 다른 글

[Java] 추상 클래스&추상 메서드  (0) 2021.08.26
[Java] 다형성  (0) 2021.08.25
[Java] Package와 import  (0) 2021.08.24
[Java] 상속  (0) 2021.08.24
[Java] 변수의 초기화  (0) 2021.08.24

+ Recent posts