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

1. 패키지 (package)

  • 하나의 소스 파일에는 첫 번째 문장으로 단 하나의 패키지 선언만 허용한다.
  • 모든 클래스는 반드시 하나의 패키지에 속해야 한다.
  • 패키지는 점(.)을 구분자로 하여 계층 구조로 구성된다.
  • 패키지는 물리적인 클래스 파일(.class)을 포함하는 하나의 디렉터리이다.
  • 같은 이름의 클래스가 다른 패키지에 있을 수 있다.
// 디렉토리 : com/company/sample
package com.company.sample;

class Sample {}

1.1. 패키지 선언

package com.company.sample; // 패키지 선언
  • 주석과 공백을 제외한 가장 첫 번째 라인에 선언한다.
  • 하나의 소스 파일에 단 한 번만 선언 가능하다.
  • 선언된 패키지안에 해당 클래스가 속해야 한다.
  • 패키지 명은 대소문자 구분이 되지만 클래스와 구분을 하기 위해 소문자로 하는 것을 원칙으로 한다.
  • 자바에서 기본적으로 '이름 없는 패키지(unnamed package)가 있어 패키지를 선언하지 않고도 문제없이 사용할 수 있다.

2. import 문

  • 다른 패키지의 클래스를 사용하려면 패키 지명 + 클래스 이름을 사용해야 한다. 이런 점이 불편하여 import를 통해 미리 선언할 수 있다.
  • 컴파일러는 import문을 보고 각 클래스 명 앞에 패키지 명을 붙인다.
  • 같은 패키지 내의 클래스 들은 import문을 저장하지 않고 패키지 명 생략 가능하다.
package com.company.sample;

import java.util.Scanner; // Sacnner 선언
import java.util.StringTokenizer; // StringTokenizer 선언

class Sample {
    main() {
        // 패키지명 + 클래스 이름
        // 이런 부분이 불편하여 import로 미리 선언
        java.util.Scanner sc = new java.util.Scanner(System.in); 
    }
}

2.1. import 선언문

import java.util.Scanner;
import java.util.*; // 패키지 하위 클래스 전부 미리 선언

'*'는 하위 패키지의 클래스까지 포함하는 것이 아니다.

 

java.lang은 묵시적으로 모든 소스파일에 선언되어 있어 언제든지 사용 가능하다.

2.2. static import 문

static 멤버로 호출할 때 클래스 명을 생략할 수 있다.

import static java.lang.Integer;
import static java.lang.Math.random;
import static java.lang.System.ou;

System.out.println(Math.random());

System.out.println(random()); // 클래스 명 생략

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

[Java] 다형성  (0) 2021.08.25
[Java] 제어자  (0) 2021.08.25
[Java] 상속  (0) 2021.08.24
[Java] 변수의 초기화  (0) 2021.08.24
[Java] 생성자  (0) 2021.08.24

+ Recent posts