자바 기본 개념 정리: 객체지향, 상속, 다형성, 추상화 이해
김영한의 실전 자바 기본편에서 학습한 내용을 정리한 글입니다.
자바에서의 대입?
항상 변수의 값을
복사
해서 대입한다.
기본형(Primitive Type)이면 변수에 들어있는 실제 사용하는 값을 복사
하여 대입하고 참조형(Reference Type)이면 변수에 들어있는 참조값
을 복사하여 대입한다.
참조형이란?
데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입 (객체, 배열)이다.
String은 기본형이 아닌 참조형 클래스!
문자는 기본형이 아니지만 자주 사용하기 때문에 바로 대입하여 사용할 수 있다
기본형과 참조형의 메서드 호출 차이점
메서드로 기본형 데이터 전달 시 값이 복사되어 전달된다. 메서드 내부에서 매개변수의 값을 변경해도 호출자의 변수값에는 영향이 없다.
하지만, 참조형 데이터를 전달하면 참조값이 복사되어 전달되고, 메서드 내부에서 값을 변경하면 호출자의 객체도 변경된다.
객체 지향 프로그래밍?
객체 지향에서는 데이터와 그 데이터에 대한 행동(메서드)가 하나의 객체
안에 포함된다.
생성자 생성 규칙?
생성자의 이름은 클래스 이름과 같아야 하기 때문에 첫 글자도 대문자로 시작한다.
반환 타입은 없고, 나머지는 메서드와 동일한다.
생성자를 사용하면 필수값 입력을 보장할 수 있다. 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않는다.
this()
는 생성자 코드의 첫줄에만 작성할 수 있다.
접근제어자의 종류?
메서드, 변수
- private : 모든 외부 호출을 막는다
- default : 같은 패키지 안에서 호출 허용
- protected : 같은 패키지 안에서 호출 허용 + 패키지 달라도 상속안에서 허용
public : 모든 외부 호출을 허용
- default 접근 제어자는 같은 패키지 안에서 호출을 허용 하는 package-private
클래스 레벨
- 클래스는
public
,default
만 사용할 수 있다. - public 클래스는 반드시 파일명과 이름이 같아야 한다.
- 하나의 자바 파일에 public클래스는 하나만 등장할 수 있다.
- 하나의 자바 파일에 default 접근자 클래스는 여러개 만들 수 있다.
캡슐화
데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근을 제한하는 것이다. 데이터와 기능은 숨겨야한다. 단, 최소한으로 필요한 기능을 노출한다
본인의 데이터는 본인 클래스의 메소드에서 수정하는 것이 가장 좋다.
코드 작성 팁 : if 검증로직을 만족하지 않으면 return하여 else에다가 굳이 실행로직을 작성하지 않는다.
static이란?
- 메서드 영역(Method Area) : 프로그램을 실행하는데 필요한 공통 데이터 관리 (클래스 정보, static 영역, 런타임 상수 풀(리터럴))
- 스택 영역 : 스택 프레임 (지역 변수, 중간 연산 결과, 메서드 호출 정보)
- 힙 영역 : 객체와 배열이 생성되는 영역이며, 참조되지 않은 객체에 대한 GC가 이루어지는 영역
static 변수는 클래스명.변수이름
으로 접근한다. 메서드 영역에 static 영역에 변수가 생성되어 클래스에서 공용으로 사용되고 JVM이 로딩되는 순간 생성되고 종료될때까지 유지된다. 클래스변수, 정적변수, static 변수로 불린다.
static 메서드 내부에서는 인스턴스 변수나 인스턴스 메서드를 사용할 수 없다. 그 이유는 클래스는 이름을 통해 바로 호출가능하기 때문에 인스턴스처럼 참조값의 개념이 없는데, 특정 인스턴스 기능을 사용하기 위해서는 참조값을 알아야 하기 때문이다.
정적 메서드는 객체 생성이 필요없이 메서드의 호출만으로 필요한 기능을 수행할 때 사용한다. (유틸리티성)
static import
정적 메서드를 사용할 때 해당 메서드를 다음과 같이 자주 호출해야 한다면 static import
기능을 고려하자. 유틸리티 클래스의 인스턴스 생성을 막고 싶으면 private으로 생성자를 제어한다. static으로 쓰도록 의도를 둘 수 있다.
상속?
기존 클래스의 속성과 기능을 그대로 물려받는다. extends
키워드를 사용하고 대상은 하나만 선택 할 수 있다. 하나만 선택할 수 있는 부모가 여러개이면서 동일한 멤버변수나 메소드가 있을 경우, 자식은 어떤 부모로부터 데이터 / 메소드를 상속받아야 할지 모르는 다이아몬드 문제가 발생할 수 있기 때문이다.
상속 관계의 객체를 생성하면 그 내부에는 부모와 자식이 모두 생성되고,상속 관계의 객체를 호출할 때, 대상 타입을 정해야 한다. 이때 호출자의 타입을 통해 대상 타입을 찾는다.
현재 타입에서 기능을 찾지 못하면 상위 부모 타입으로 기능을 찾아서 실행한다.기능을 찾지 못하면 컴파일 에러가 발생한다.
부모 타입의 기능을 자식에서 다르게 재정의 하고 싶은 경우 메서드 오버라이딩
을 한다.
메서드 오버라이딩 조건
- 메서드 이름: 메서드 이름이 같아야 한다.
- 메서드 매개변수(파라미터): 매개변수(파라미터) 타입, 순서, 개수가 같아야 한다.
- 반환 타입: 반환 타입이 같아야 한다. 단 반환 타입이 하위 클래스 타입일 수 있다.
- 접근 제어자: 오버라이딩 메서드의 접근 제어자는 상위 클래스의 메서드보다 더 제한적이어서는 안된다. 예를 들 어, 상위 클래스의 메서드가
protected
로 선언되어 있으면 하위 클래스에서 이를public
또는protected
로 오버라이드할 수 있지만,private
또는default
로 오버라이드 할 수 없다. 예외: 오버라이딩 메서드는 상위 클래스의 메서드보다 더 많은 체크 예외를
throws
로 선언할 수 없다. 하지만 더 적거나 같은 수의 예외, 또는 하위 타입의 예외는 선언할 수 있다.static
,final
,private
: 키워드가 붙은 메서드는 오버라이딩 될 수 없다.static
은 클래스 레벨에서 작동하므로 인스턴스 레벨에서 사용하는 오버라이딩이 의미가 없다. 쉽게 이 야기해서 그냥 클래스 이름을 통해 필요한 곳에 직접 접근하면 된다.final
메서드는 재정의를 금지한다.private
메서드는 해당 클래스에서만 접근 가능하기 때문에 하위 클래스에서 보이지 않는다. 따라서 오 버라이딩 할 수 없다.
생성자 오버라이딩: 생성자는 오버라이딩 할 수 없다.
Super?
- super는 부모 클래스를 참조할 수 있다.
- 상속 관계를 사용하면 자식 클래스의 생성자에서 부모 클래스의 생성자를 반드시 호출해야 한다.(규칙)
- 자식 생성자의 첫줄에 super (); 는 생략이 가능하다.
클래스에 fianl
키워드를 붙일 경우 다른 클래스가 해당 클래스를 상속 받을 수 없다. 메소드에 final
키워드를 붙일 경우 오버라이딩 할 수 없다.
다형성
다형적 참조
부모는 자식을 담을 수 있다. Parent poly = new Child()
부모 타입을 사용하는 변수를 자식 타입에 대이바고 싶으면 임시적으로 다운 캐스팅
을 사용하여 타입을 변경한다. Child child = (Child) poly //Parent poly
다운캐스팅 주의점
상위로 올라가는 업캐스팅은 인스턴스 내부에 부모가 모두 생기기 때문에 문제가 발생하지 않지만, 객체를 생성할 때 하위 자식은 생성하지 않기 때문에 하위로 내려가는 다운 캐스팅은 인스턴스 내부에 없는 부분을 호출하는 문제가 발생할 수 있다.
A a = new B()
:A로 업케스팅B b = new B()
:자신과 같은타입C c = new B()
:하위타입은 대입 할수없음, 컴파일오류C c = (C) new B()
:하위타입으로 강제 다운캐스팅,하지만 B인스턴스에 C와 관련된 부분이 없으므로 잘못된 캐스팅이 되기 때문에ClassCastException
런타임 오류 발생
리스트 선언으로 알아보는 다형성
List<Integer> answer = new ArrayList<>();
이 코드에서 사용된 방식은 자바의 “다형성”과 “타입 추론” 기능을 활용한 것이다.
- 다형성(Polymorphism):
- 왼쪽에
List
를 사용함으로써, 이 변수는ArrayList
뿐만 아니라List
인터페이스를 구현하는 어떤 클래스의 인스턴스도 참조 & 코드 유연성 향상 List
는 인터페이스이며,ArrayList
는List
인터페이스를 구현하는 클래스
- 왼쪽에
- 타입 추론(Type Inference):
- 자바 7부터 도입된 다이아몬드 연산자
<>
를 사용하면 오른쪽에 타입을 명시하지 않아도 컴파일러가 왼쪽의 타입을 기반으로 오른쪽 타입을 추론한다.
- 자바 7부터 도입된 다이아몬드 연산자
메서드 오버라이딩
오버라이딩 된 메서드가 항상 우선권을 가진다
추상 클래스
상속을 목적으로 사용되는 인스턴스 생성이 불가한 클래스이다. abstract class AbstractAnimal {...}
추상 메소드
상속 받는 자식 클래스가 반드시 오버라이딩 해야하는 메서드를 뜻한다. 메서드 바디가 존재하지 않는다. public abstract void sound();
추상 메서드하 하나라도 있는 클래스는 추상 클래스로 선언해야한다.
순수 추상 클래스
모든 메서드가 추상 메서드인 추상 클래스를 뜻한다. 다형성을 위한 부모 타입으로써 껍데기 역할만 한다.
인터페이스
순수 추상 클래스를 더 편리하게 사용할 수 있도록 인터페이스라는 키워드를 제공한다. 인터페이스를 상속 받을 때는 extends 대신 implements
키워드를 사용한다.
모든 메서드가 추상 메서드인 경우, 순수 추상 클래스를 만들어도 되고 인터페이스를 만들어도 되지만 인터페이스에서 제공하는 몇 가지 기능때문에 인터페이스를 사용한다.
제약
: 순수 추상 클래스에서는 실행 가능한 메서드를 끼워넣을 가능성이 있다. 인터페이스로 명시하면 모든 메서드는 구현되어야 한다는 제약을 걸 수 있다.다중 구현
: 클래스 상속은 하나의 부모만 가능하지만 인터페이스는 다중 구현이 가능하다. 그 이유는 자식에서 오버라이딩 되는 메소드를 실행하기 때문에 다중 상속의 다이아몬드 문제가 발생하지 않기 때문이다.
OCP
OCP(Open-Closed Principle) 원칙
좋은 객체 지향 설계 원칙 중 하나로 OCP 원칙이라는 것이 있다.
- Open for extension: 새로운 기능의 추가나 변경 사항이 생겼을 때, 기존 코드는 확장할 수 있어야 한다.
- Closed for modification: 기존의 코드는 수정되지 않아야 한다.
인터페이스를 구현해서 새로운 차량 종류를 자유롭게 추가 할 수 있고 기존 코드는 수정이 필요하지 않다.