Day28 Java프로그래밍 기초(추상클래스, 인터페이스)
1. 추상클래스
1.1 추상클래스의 필요성
- 비슷한 기능을 하는 두개의 클래스를 공통의 메서드로 관리하기 위한 클래스이다.
- 두개의 정렬 메서드를 확인 해보자
- 2개의 메서드는 기능은 같지만, sorter.run()과 sorter.start()의 메서드명과 매개변수가 다르다.
- 같은 기능을 하지만 경우에 따라 2개를 각각 호출해야한다.
1 2 3 4 5 6 7
static void display(BubbleSort sorter, int[] values) { sorter.run(values); } static void display(QuickSort sorter, int[] values) { sorter.start(values, 0, values.length - 1); }
1.2 추상클래스의 개념
- 그렇기 때문에 추상클래스를 통해 공통의 분모를 수행하는 추상클래스를 생성한다.
- 추상클래스를 직접적으로 사용하지는 않지만, 같은 메소드와 같은 매개변수로 넘겨 줄수 있다.
public abstract class Sorter { public void sort(int[] values) {}; }
public class QuickSort extends Sorter {
1 2 3 4 5
@Override public void sort(int[] values) { start(values, 0, values.length - 1); } //후략// }
public class BubbleSort extends Sorter {
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@Override public void sort(int[] values) { int size = values.length; for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - i - 1; j++) { if (values[j] > values[j + 1]) { //System.out.printf("%d <==> %d\n", values[j], values[j + 1]); int temp = values[j]; values[j] = values[j + 1]; values[j + 1] = temp; } } } } }
- 여기에 다형성 개념을 대입하면 부모클래스의 변수명으로 자식클래스 타입을 할당할 수 있다.
- 또한 사용자는 Soter sort = new Soter(); 처럼 직접적인 사용을 할 수 없다.
Sorter sort = new BubbleSort(); display(sort, values); // OK!
Sorter sort2 = new QuickSort(); display(sor2, values); // OK!
1.3 추상클래스의 한계
- 추상클래스를 선언하였지만, 자식클래스에서 추상클래스의 메서드를 사용 안할 수도 있다.
- 하지만 추상클래스의 메소드를 사용 안하는 경우도 있다.
public class MergeSort extends Sorter {
1 2 3
void merge(int arr[], int l, int m, int r) { // 생략// } }
1.4 추상메서드의 활용
- 추상클래스를 사용 안하면, 상속을 받는 의미가 없다.
- 따라서 추상클래스의 메소드를 강제적을 사용하게 하는 방법이 필요하다.
- 추상클래스의 메소드를 강제적으로 사용하게 하는 것이 바로 추상메서드 이다.
public abstract class Sorter {
1 2 3 4 5
// 메서드를 추상 메서드로 선언하는 순간 // => 모든 서브 클래스는 반드시 이 메서드를 구현해야 한다. // => 구현하지 않으면 추상 클래스가 될 수 밖에 없다. // => 서브 클래스에게 구현을 강제하는 효과가 있다. public abstract void sort(int[] values); }
1.5 인터페이스의 등장
- 이처럼 추상클래스를 가지고 메소드사용을 강제하는데 제약이 있어, 인터페이스를 사용하게 된다.
- 추상메서드만 있을 경우, 객체 사용규칙을 정의하는 인터페이스로 전환 가능하다.
- 추상클래스 안에 일반 메서드가 있다면, 인터페이스로 전환이 불가능하다.
public interface Sorter {
1 2 3 4
// 인터페이스는 호출 규칙을 정의하는 것이기 때문에 // 모든 메서드는 기본이 public 이고, abstract 이다. // => 다음과 같이 메서드 선언에 public 과 abstract를 생략해도 된다. void sort(int[] values); }
2. 캡슐화
1.1 캡슐화의 필요성
- 클래스의 필드 값에 직접적인 접근을 하면 해당 필드값을 참조하는 결과값도 영향을 받는다
- 필드에 직접적인 접근 보다 set과 get 메서드들을 통해 접근하면,
- 변경에 따른 추가적인 필드 변경 메서드를 추가할 수 있다.
1.2 접근제어자
1
2
3
4
5
6
- private : 클래스에 소속된 같은 멤버만 접근 가능
- (default) : 같은 패키지에 소속된 멤버만 접근 가능
- protected : 같은 패키지에 소속되거나 자손 클래스의 멤버만 접근 가능
- public : 모두 접근 가능
*자식 클래스에서 상속 받아 만든 변수가 아니면 부모클래스로 생성해도 protected 접근불가
1.3 싱글톤 패턴
클래스의 생성자의 접근을 제한하며 static 메서드를 통해 하나의 인스턴스만 생성
public class Car{ //생성자를 접근제한 private Car();
1 2 3 4 5 6 7 8 9 10 11 12
//하나의 값(전역변수)만을 가지는 인스턴스 선언 private static Car instance; //인스턴스의 고유성 여부를 확인 public static Car getInstance(){ if(instance == null){ //private은 같은 class내에서 접근 가능 instance = new Car(); } //고유한 인스턴스 생성 return instance; } }
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.