Ch.07 객체지향 프로그래밍 II
- 상속(inheritance)
- 상속의 정의와 장점
- 정의: 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것
- 조상 클래스: 부모(parent) 클래스, 상위(super) 클래스, 기반(base) 클래스
- 자손 클래스: 자식(child) 클래스, 하위(sub) 클래스, 파생된(derived) 클래스
- 생성자와 초기화 블럭은 상속되지 않음
- 자손 클래스의 멤버 개수 >= 부모 클래스의 멤버 개수
- 자식클래스 extends 부모클래스 { //자식 클래스의 내용 } //t사용 방법
- 장점
- 코드의 재사용성, 중복을 줄임
- 생산성과 유지보수에 용이
- 정의: 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것
- 클래스간의 관계 – 포함 관계
- 포함(composite): 상속 이외의 클래스를 재사용하는 방법
- 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것
- 클래스간의 관계 결정하기
- 상속 관계: A는 B이다
- 포함 관계: A는 B를 가지고 있다
- 단일상속(single inheritance)
- 하나의 클래스만을 상속받을 수 있다는 의미
- 다중 상속의 단점인 상속받은 클래스들의 멤버간의 중복을 피하기 위해 단일 상속
- Object 클래스 – 모든 클래스의 조상
- 상속 계층도의 최상위 클래스
- 컴파일러가 자동으로 Object 클래스의 상속을 추가
- 모든 인스턴스가 가져야하는 기본적인 메서드 정의되어 있음
- 오버라이딩(overriding)
- 오버라이딩이란
- 조상 클래스로부터 상속받은 메서드를 자손 클래스에 맞게 변경(재정의)하는 것
- @override 애너테이션
- 오버라이딩의 조건
- 성립 조건: 자손 클래스에서 오버라이딩하는 메서드는 조상 클래스의 메서드와
- 이름이 같아야함
- 매개변수가 같아야함
- 반환타입이 같아야함
- 제약 조건: 조상 클래스의 메서드를 자손 클래스에서 오버라이딩할 때
- 접근제어자를 조상 클래스보다 좁게 설정할 수 없음
- 자손 클래스의 예외 개수 <= 조상 클래스의 예외 개수
- 인스턴스 메서드를 static 메서드나 그 반대로 행할 수 없음
- 성립 조건: 자손 클래스에서 오버라이딩하는 메서드는 조상 클래스의 메서드와
- 오버로딩 vs 오버라이딩
- 오버로딩(overloading): 기존에 없던 새로운 메서드를 정의하는 것
- 오버라이딩(overriding): 기존에 존재하던 상속받은 메서드를 재정의하는 것
- super
- 자손 클래스에서 사용하는 것
- 조상 클래스로부터 상속받은 멤버를 참조하는데 사용
- 자손 클래스와 조상 클래스의 멤버의 이름이 같을 경우 구분하기 위해 사용
- super() – 조상 클래스의 생성자 호출
- 자손 클래스에서 사용하는 것
- 조상 클래스의 생성자를 호출할 때 사용
- 생성자의 첫 줄에 호출해야함
- 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수 도 있기 때문에 먼저 초기화되어야함
- this() 또는 super()를 선언하지 않으면 컴파일러가 자동 추가
- Package 와 import
- 패키지(package)
- 의미: 클래스의 묶음, 물리적으로 하나의 디렉토리
- 그룹단위로 묶음으로써 효율적으로 관리 가능
- 하나의 소스파일에는 첫 번째 문장으로 단 하나의 패키지 선언만 허용
- 모든 클래스는 하나의 패키지에 속해야함
- 계층 구조: 점(.)으로 구별
- 패키지의 선언
- package 패키지명; //패키지 선언 방법
- 반드시 주석과 공백을 제외한 첫 째 줄에 위치
- 클래스명과 구분하기 위해 소문자로 정의
- 이름 없는 패키지(unnamed package)
- 패키지를 선언하지 않으면 기본적으로 제공하는 패키지
- Import문
- 다른 패키지의 클래스를 사용할 때 사용
- 사용하고자하는 패키지 정보를 입력해줌
- 컴파일러가 컴파일시에 import문을 통해 소스파일에 사용된 패키지를 알아내고 모든 클래스이름 앞에 패키지명을 붙여줌
- import문의 선언
- 소스파일의 구성
- package문
- import문
- 클래스 선언
- import 패키지명.클래스명; //다른 패키지에 있는 클래스 이용하기 위한 선언 방법
- import 패키지명.*; //다른 패키지 안에 있는 모든 클래스를 사용하겠다는 의미
- 성능차이는 없음
- 소스파일의 구성
- static import문
- static 멤버를 호출할 때 클래스 이름을 생략할 수 있음
- 자주 사용하는 클래스를 import해주면 코드가 간결해짐
- 제어자(modifier)
- 제어자란?
- 클래스, 변수, 메서드의 선언부 앞에 사용됨
- 부가적인 정보를 나타냄
- 종류
- 접근 제어자: public, protected, (default), private
- 그 외: static, final, abstract, synchronized, volatile, ...
- Static – 클래스의, 공통적인
- 의미: 클래스의, 공통적인
- 하나의 변수를 method area에서 모든 인스턴스가 공유고 접근가능함
- Final, 마지막의, 변경될 수 없는
- 의미: 마지막의, 변경될 수 없는
- 사용 가능
- 클래스: 변경될 수 없는 클래스, 확장될 수 없는 클래스가 됨, 다른 클래스의 조상이 될 수 없음
- 메서드: 변경 될 수 없는 메서드, 오버라이딩을 통해 재정의 할 수 없음
- 멤버변수, 지역변수: 값을 변경할 수 없는 상수가 됨
- Abstract – 추상의, 미완성의
- 사용 가능
- 클래스: 클래스 내에 추상 메서드가 선언되어 있음을 알림
- 메서드: 선언부만 작성, 구현부는 작성하지 않음
- 사용 가능
- 접근 제어자(access modifier)
- 종류
- private: 같은 클래스
- default: 같은 패키지
- protected: 같은 패키지 + 다른 패키지의 자손 클래스
- public: 접근 제한 없음
- 사용 이유
- 외부로부터 데이터 보호
- 외부에 불필요한 내부에서만 사용되는 부분을 감추기 위해서
- 종류
- 제어자의 조합
- 주의 사항
- static과 abstract를 같이 사용할 수 없음
- abstract와 final을 같이 사용할 수 없음
- abstract의 접근제어자는 private일 수 없음
- 메서드에 final과 private을 같이 사용할 필요 없음
- 주의 사항
- 다형성(polymorphism)
- 다형성이란
- 객체지향의 개념에서의 의미: 여러 가지 형태를 가질 수 있는 능력
- 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조할 수 있는 능력
- 반대로 자손 클래스 타입의 참조변수로 조상 클래스의 인스턴스를 참조 할 수 없음
- 조상 클래스에는 자손 클래스에서 추가적으로 정의한 멤버 변수를 가지고 있지 않기 때문
- 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라짐
- 참조 변수의 형변환
- 자손 타입 → 조상 타입 (Up-Casting): 형변환 생략 가능
- 자손 타입 ← 조상 타입 (Down-Casting): 형변환 생략 불가
- 상속 관계가 아닌 클래스끼리 형변환 불가능
- instanceOf 연산자
- 객체의 타입 변환 확인 할 때 사용
- true값을 얻는다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 의미
- 형변환 전 타입 체크 instanceOf를 통한 검사가 필수적임
- 참조변수와 인스턴스의 연결
- 조상 클래스와 자손 클래스에 중복으로 정의된 멤버 변수를 사용할 경우
- 부모 클래스의 인스턴스를 사용할 경우에는 부모의 멤버 변수를 사용
- 자손 클래스의 인스턴스를 사용할 경우에는 자손의 멤버 변수를 사용
- 조상 클래스와 자손 클래스에 중복으로 정의된 멤버 변수를 사용할 경우
- 매개변수의 다형성
- 메서드의 매개변수
- 부모 클래스를 타입으로 사용하면 그 부모 클래스를 상속받은 자손 클래스들도 매개값으로 전달 가능함
- 메서드의 매개변수
- 여러 종류의 객체를 배열로 다루기
- 조상 타입의 배열을 만들어서 조상 타입을 구현한 클래스들을 배열로 다룰 수 있음
- 인덱스로 접근하여 조상 타입에 정의된 공통적인 멤버를 사용할 수 있음
- 추상 클래스(abstract class)
- 추상 클래스란
- 미완성 클래스
- 미완성 메서드를 가지고 있다는 의미
- 추상 메서드를 가지고 있지 않아도 abstract을 붙일 수 있음
- abstract class 클래스이름 { //클래스 내용 } //사용 방법
- 추상 메서드(abstract method)
- abstract 리턴타입 메서드이름();
- 선언부만 존재, 몸통{}을 제거
- 추상클래스의 작성
- 추상화: 클래스간의 공통점을 찾아서 뽑아내는 과정
- 구체화: 추상화된 개념을 상속을 통해 클래스를 구현, 확장하는 작업
- 인터페이스(interface)
- 인터페이스란
- 일종의 추상클래스
- 기본 설계도
- 다른 클래스를 작성하는데 도움을 줌
- 인터페이스의 작성
- interface 인터페이스이름 { //인터페이스 클래스 내용 } //인터페이스 생성 방법
- 제약 사항
- 모든 멤버변수는 public static final, 생략 가능
- 모든 메서드는 public abtract, 생략 가능
- static과 디폴트 메서드는 예외
- 인터페이스의 상속
- 다중 상속 가능
- 인터페이스의 구현
- class 클래스이름 implements 인터페이스1, 인터페이스2, ... { //클래스 내용 }
- 일부분만 구현한다면 abstract를 붙여서 추상클래스로 선언
- 인터페이스를 이용한 다중 상속
- 선언부만 선언되어 있으므로 다중 상속을 통해 중복이 일어나도 문제가 일어나지 않음
- 인터페이스를 이용한 다형성
- 입터페이스의 참조 변수로 이 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있음
- 인터페이스 타입으로 형변환도 가능
- 리턴 타입이 인터페이스: 인터페이스를 구현한 클래스를 반환하겠다는 의미
- 인터페이스의 장점
- 개발 시간을 단축시킬 수 있음
- 표준화 가능
- 서로 관계없는 클래스들에게 관계를 맺어줄 수 있음
- 독립적인 프로그래밍이 가능
- 인터페이스의 이해
- User: 클래스를 사용하는 쪽
- Provider: 클래스를 제공하는 쪽
- 메서드를 사용하는(호출) 부분에서는 사용하려는 메서드 선언부만 알면 됨
- 직접적인 관계에서 간접적인 관계로 바뀜
- 디폴트 메서드와 static 메서드
- 인터페이스에 메서드를 추가한다는 것: 인터페이스를 구현한 모든 클래스에 추가해야한다는 것
- 디폴트 메서드: 추상 메서드의 기본적인 구현을 제공하는 메서드
- 추상 메서드가 아니므로 기존에 인터페이스를 구현한 클래스들에서의 변경은 없음
- 접근 제어자: public, 생략 가능
- 충돌 경우
- 여러 인터페이스간의 디폴트 메서드의 충돌: 인터페이스를 구현한 클래스에서 오버라이딩
- 디폴트 메서드와 조상 클래스간의 충돌: 조상 클래스의 메서드 사용
- 내부 클래스(inner class)
- 내부 클래스란
- 사용 용도: AWT, Swing과 같은 GUI
- 클래스 내의 클래스가 선언되는 것을 의미
- 사용 이유: 두 클래스의 관계가 깊기 때문
- 장점
- 내부 클래스에서 외부 클래스의 접근이 용이
- 코드의 복잡성을 줄일 수 있음 (캡슐화)
- 내부 클래스의 종류과 특징
- 종류
- 인스턴스 클래스
- 외부 클래스의 멤버 변수 선언부에 위치
- 외부 클래스의 인스턴스 멤버처럼 사용
- 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적
- static 클래스
- 외부 클래스의 멤버 변수 선언부에 위치
- 외부 클래스의 static 멤버처럼 사용
- 외부 클래스의 static 맴버, static 메서드에서 사용될 목적
- 지역 클래스
- 외부 클래스의 메서드나 초기화블럭 안에 선언
- 선언된 영역 내부에서만 사용 가능
- 익명 클래스
- 클래스의 선언과 동시에 객체의 생성을 동시에 하는 클래스 (일회용)
- 인스턴스 클래스
- 종류
- 내부 클래스의 선언
- 내부클래스의 선언 위치에 따라 유효범위(scope)과 접근성(access)를 가짐
- 내부 클래스의 제어자와 접근성
- 내부 클래스가 외부 클래스의 멤버변수와 같은 성질을 가짐
- 따라서 접근제어자(abstract, final, private, protected)가 가능
- static 내부 클래스만 static 멤버를 가질 수 있음
- final과 static이 붙은 상수는 모든 내부클래스에서 선언 가능
- 외부 클래스의 외부에서 내부 클래스를 접근하는 방법
- Outer.Inner 인스턴스이름 = new Outer().new Inner(); //내부 클래스가 인스턴스 클래스인 경우
- Outer.Inner 인스턴스이름 = new Outer().Inner(); //내부 클래스가 static인 경우
- 익명 클래스(anonymous class)
- 이름이 없음
- new 조상클래스이름() { //멤버 선언 }
- new 인터페이스이름() { //멤버 선언 }
- 생성자를 가질 수 없음
- 하나의 클래스를 상속받거나 구현할 수 있음(다중상속 불가)
'JAVA 기초' 카테고리의 다른 글
[JAVA 기초] JAVA의 정석 - Ch.09 Java.lang 패키지와 유용한 클래스 (정리) (2) | 2025.01.16 |
---|---|
[JAVA 기초] JAVA의 정석 - Ch.08 예외 처리(Exception handling) (정리) (1) | 2025.01.16 |
[JAVA 기초] JAVA의 정석 - Ch.06 객체지향 프로그래밍 I (정리) (1) | 2025.01.15 |
[JAVA 기초] JAVA의 정석 - Ch.05 배열(Array) (정리) (2) | 2025.01.15 |
[JAVA 기초] JAVA의 정석 - Ch.04 조건문과 반복문 (정리) (1) | 2025.01.15 |