본문 바로가기
Book

자바의 정석 - 자바 기본기 정리하기 (6)객체지향프로그래밍2

by devLog by Ronnie's 2021. 11. 12.

들어가며


문제 구현에 있어서 자바에 대한 기본기의 부족함을 느껴서 오랜만에 자바의 기본 저서인 자바의 정석을 다시 피게 됐다. 그러면서 정말 신기한 경험을 하게 되었는데 바로 예전에 잘 이해가 안가서 읽고 넘어갔던 내용들이 이제는 내 머릿속에서 자연스럽게 그려지는 경험을 하게 되었다. 그동안에 시간들이 헛되지는 않았나보다.

 

어느 곳에서나 기본기는 중요하듯이 이번 기회를 통해 자바 기본기를 더 단단히 다지고자 챕터별로 글로 정리하면서 다시 한번 암기를 하고 좀 더 디테일하게 알아야 되는 곳은 챕터를 나눠서 자바의정석에 나온 내용 + 보강된 내용을 더해서 정리를 하고자 한다. 

 

정리


상속 extends
기존의 클래스를 재사용하여 새로운 클래스를 작성하 는 것. 상속을 이용하면 적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 매우 용이.
 
포함관계
상속 이외에도 클래스를 재사용하는 또 다른 방법이다. 이 방법은 클래스 간에 포함관계를 맺어 주는 것이다. 클래스 간의 포함관계를 맺어주는 것은 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것이다.
==> 그럼 이때 언제는 상속관계를 맺고 언제는 포함관계를 맺는 것이 좋을까.
1. 상속관계 ~은 ~이다. 스포츠카는 카이다
2. 포함관계 ~은 ~을 가지고 있다. -> 덱은 카드를 가지고 있다.

단일 상속
자바에서는 여러 조상 클래스를 상속받는 다중상속을 허용하지 않는다. 단일 상속이 하나의 조상 클래스만을 가질 수 있기 때문에 다중상속에 비해 불편한 점도 있지만 클래스 간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어 준다는 점에서 다중상속보다 유리하다.

Object클래스 - 모든 클래스의 조상
extends Object를 쓰지 않더라도 컴피일을 하면 컴파일러가 자동적으로 extends Object 코드를 추가하여 상속받도록 한다.
toString()이나 equals() 와 같은 메서드를 따로 정의하지 않고도 사용할 수 있었던 것이 Object 클래스를 상속 받고 있기 때문이었다.

오버라이딩
조상클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다.
오버라이딩을 할때 조건은 메서드의 선언부에 내용이 조상의 것과 완전히 일치해야한다. 다만 접근제어자와 예외는 제한된 조건 하에서만 다르게 변경할 수 있다. 접근제어자의 경우는 조상 클래스의 메서드보다 좁은 범위로 변경할수 없다. (부모 protected면 private 불가능)
예외같은 경우는 조상 클래스의 메서드보다 많은 수의 예외를 선언할수 없다. 

오버로딩vs오버라이딩
오버로딩 - 기존에 없는 새로운 메서드를 정의하는 것 new
오버라이딩 - 상속받은 메서드의 내용을 변경하는 것

참조변수 super
자손 클래스에서 조상 클래스로부터 상속 받은 멤버를 참조하는데 사용되는 참조변수이다. 멤버변수와 지역번수의 이름이 같을때 this를 사용했듯이 상속받은 멤버와 자신의 멤버와 이름이 같을때는 super를 붙여서 구별이 가능하다.

spuer() - 조상의 생성자
this()는 같은 클래스의 다른 생성자를 호출하는데 사용되지만 super()는 조상의 생성자를 호출하는데 사용된다.

패키지
패키지란 클래스의 묶음이다. 패키지에는 클래스 또는 인터페이스를 포함시킬 수 있다. 
같은 이름의 클래스 일지라도 서로 다른 패키지에 존재하는 것은 가능하다. 사실 클래스의 실제 이름은 (풀네임) 패키지명을 포함한 것이다. 
String클래스의 실제 이름은 java.lang.String이다. java.lang패키지에 속한 String 클래스라는 의미이다. 

 


패키지의 선언 
패키지 선언문은 반드시 소스파일에서 주석과 공백을 제외한 첫번째 문장이어야 한다.
하나의 소스파일에 단 한 번만 선언될 수 있다.
패키지명은 대소문자 모두 허용하지만 클래스명과 쉽게 구분하기 위해 소문자로 하는 것을 원칙으로 한다.
모든 클래스는 반드시 하나의 패키지에 포함되어야 한다. 선언을 안해있는 것들은 자바에서 기본적으로 제공하는 '이름 없는 패키지'때문이다. 

import문
다른 패키지의 클래스를 사용하려면 패키지명이 포함된 풀네임을 사용해야된다. 하지만 매번 패키지명을 붙여서 작성하기란 쉽지 않은 일이기때문에 import문으로 선언해주면 패키지명을 생략한 클래스 이름만 써도 된다. 

제어자
제어자는 크게 접근 제어자와 그 외의 제어자로 나눌수 있다.
접근 제어자 public protected default private -> 제어자들 간의 순서는 관계없지만 주로 접근 제어자를 제일 왼쪽에 둔다.
그 외 static final abstract native transient synchronized volatile strictfp

static
'클래스의' 또는 '공통적인'의 의미를 가지고 있다. static이 사용될 수 있는 곳은 멤버변수와 메서드, 초기화 블럭이다. 

멤버변수의 static
- 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 된다.
- 클래스 변수는 인스턴스를 생성하지 않고도 사용 가능하다.
- 클래스가 메모리에 로드될 때 생성된다.

메서드
- 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 된다.
- static 메서드 내에서는 인스턴스 멤버들을 직접 사용할 수 없다.

final
'마지막의' 또는 '변경될수없는'의 의미를 가진다. 거의 모든 대상에 사용 가능하다. 변수에 사용하면 값을 변경할 수 없는 상수가 되며, 메서드에 사용되면 오버라이딩을 할 수 없게 되고 클래스에 사용되면 자신을 확장하는 자손클래스를 정의하지 못하게 된다.

abstract
'추상의' 또는 '미완성' 이라는 의미를 가진다. 메서드이 선언부만 작성하고 실제 수행내용은 구현하지 않는 추상 메서드를 선언하는데 사용된다.
클래스와 메서드에서 사용 가능하다.
클래스를 설계도에 비유한다면 추상 클래스는 미완성 설계도에 비유할 수 있다. 여기서 미완성이라는 것은 멤버의 개수에 관계된 것이 아니라, 단지 미완성 메서드를 포함하고 있다는 의미이다. 미완성 설계도로 완성된 제품을 만들 수 없듯이 추상 클래스로 인스턴스는 생성할 수 없다. 추상 클래스는 상속을 통해서 자손 클래스에 의해서만 완성될 수 있다. 
클래스의 abstract를 보고 이 클래스에는 추상메서드가 있으니 상속을 통해서 구현해주어야 한다는 것을 쉽게 알 수 있다. 추상클래스는 추상 메서드를 포함하고 있다는 것을 제외하고는 일반 클래스와 전혀 다르지 않다. 추상 클래스에도 생성자가 있으며 멤버변수와 메서드도 가질 수 있다.
추상클래스의 추상메서드는 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨둔다. 즉 설계만 해놓고 실제 수행될 내용은 작성하지 않았기 때문에 미완성 메서드인 것이다. 이렇게 미완성 상태로 남겨 놓는 이유는 메서드의 내용이 상속 받는 클래스에 따라 달라질 수 있기 때문에 조상 클래스에서는 선언부만을 작성하고 주석을 덧붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려주고 실제 내용은 상속받는 클래스에서 구현하도록 비워 두는 것이다. 
abstract 리턴타입 메서드이름(); -> 구현부가 없기때문에 {} 없고 대신 문장의 끝을 알리는 ; 을 적어준다. 
추상화는 기존의 클래스의 공통부분을 뽑아내서 조상 클래스는 만드는 것이라 할 수 있다. 상속 계층도를 따라 내려갈수록 클래스는 점점 기능이 추가되어 구체화의 정도가 심해지며 반대로 올라갈수록 클래스는 추상화의 정도가 심해진다고 할 수 있다. 즉 내려갈수록 세분화되며, 올라갈수록 공통요소만 남게 된다.

인터페이스
인터페이스는 일종의 추상클래스이다. 인터페이스는 추상클래스처럼 추상 메서드를 갖지만 추상클래스보다 추상화 정도가 높아서 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있으며, 그외에 다른 어떠한 요소도 허용하지 않는다.

인터페이스의 멤버들 제약사항
- 모든 멤버변수는 public static final 이어야 하며 이를 생략할 수 있다.
- 모든 메서드는 public abstract이어야 하며 이를 생략할수 있다.

인터페이스의 상속
인터페이스는 인터페이스로부터만 상속 받을 수 있으며 클래스와 달리 다중상속을 받는 것이 가능하다. 인터페이스를 상속받을때는 구현한다는 의미의 키워드인 implements를 사용한다. 

인터페이스의 사용이유와 장점
- 개발시간을 단축시킬수 있다. 
- 표준화가 가능하다. -> 인터페이스로 기본 틀을 작성하여 보다 일관되고 졍형화된 개발이 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다. 
- 독립적인 프로그래밍이 가능하다.

디폴트 메서드
원래는 인터페이스에 추상 메서드만 선언 가능했지만 1.8부터 디폴트 메서드와 static 메서드도 추가 할 수 있게 되었다. 인터페이스에 메서드를 추가하는 것은 추상 메서드를 추가한다는 것이고, 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야 되기 때문에 보통 일이 아니다.
하지만 아무리 설계를 잘해도 언젠가 변경은 발생하기 때문에 고심 끝에 나온것이 디폴트 메서드이다. 디폴트 메서드는 추상 메서드의 ㄱ본적이 구현을 제공하는 메서드로 추상 메서드가 아니기 때문에 디폴트 메서드가 추가된다고 해서 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다. 디폴트 메서드는 앞에 default를 붙이며 추상 메서드와 달리 {} 몸통이 있어야 한다. 

접근제어자사용될 수 있는 곳은 클래스, 멤버변수, 메서드, 생성자 이다.
private 같은 클래스 내에서만 접근 가능
default 같은 패키지 내에서만 접근 가능, 접근 제어자가 선언이 안되어 있다면 default 접근제어자 권한을 가진다.
protected 같은 패키지 내에서만, 그리고 다른 패키지의 자손 클래스에서도 접근이 가능 -> 패키지에 관계없이 상속 관계에 있는 자손 클래스에서 접근할 수 있도록 하는 것이 제한 목적이다. 더불어 같은 패키지 내에서도 접근이 가능하다.
public 접근 제한 없음.

캡슐화와 접근 제어자
클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위해서이다. 데이터가 유효한 값을 유지하도록 하거나 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서는 외부로부터의 접근을 제한하는 것이 필요하다. 이러한 과정을 객체지향 개념의 캡슐화에 해당되는 내용이다.

다형성
조상클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조할 수 있도록함.
Tv 조상 CaptionTv 자식
CaptionTv c = new CaptionTv();
Tv t = new CpationTv(); 가능 
범위는 당연 c가 더 넓음 -> 그렇기 때문에 CaptionTv c = new Tv();는 에러이다.

참조변수의 형변환
기본형변수처럼 참조변수도 형변환이 가능하다. 단 서로 상속관계에 있는 클래스 사이에서만 가능하다. 
참조변수를 형변환한다고 기본형변수처럼 저장된 값이 변환되는 것이 아닌 그저 참조변수를 다른 종류의 것으로 바꾸는 것 뿐이다.
조상 타입으로의 형변환은 생략이 가능하다. (멤버의 개수가 줄어들기 때문에 항상 안전하므로) 하지만 조상타입을 자손 타입으로 형변환 하는 경우는 생략이 불가능하다.

instanceof 연산자
주로 조건문에 사용되며 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 사용한다.
instanceof의 왼쪽에는 참조변수를 오른쪽에는 타입이 피연산자로 위치한다. 결과로는 true false 

내부 클래스 inner class
내부 클래스는 클래스 내에 선언된 클래스이다. 이렇게 하는 이유는 간단하다. 두 클래스가 서로 긴밀한 관계에 있기 때문이다.
이렇게 선언하면 두 클래스의 멤버들 간에 서로 쉽게 접근할 수 있다는 장점과 외부에는 불필요한 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다는 장점이 있다. 내부 클래스로 들어간 클래스는 외부클래스를 제외하고는 다른 클래스에서 잘 사용되지 않는 것이어야 한다. 

익명 클래스
다른 내부 클래스들과는 달리 이름이 없다. 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.

댓글