과목명 : 객체지향 프로그래밍(Object oriented programming)
수업일자 : 2022년 11월 23일 (수)
1. 제어자(Modifier)
1-1. 제어자의 정의
- 클래스와 클래스의 멤버(변수, 메서드)를 선언할 때 사용되며 이들에 대해 부가적인 의미를 부여해 주는 키워드입니다.
1-2. 제어자의 특징
(1) 크게 접근 제어자(Access modifier), 제어자(Modifier)로 나뉩니다.
(2) 하나의 대상에 여러 개의 제어자를 조합해서 사용 가능하나, 접근 제어자는 단 한 개만 사용할 수 있습니다.
관례적으로 접근 제어자를 맨 앞에, 뒤에 일반적인 제어자를 붙여주는 형식으로 코드를 작성합니다.
1-3. 제어자의 여러 가지 종류
(1) 접근 제어자(Access modifier)
- public, protected, (default), private
(2) 그 외 일반 제어자
- static, final, abstract, native, transient, synchronized, volatile, strictfp
1-4. static
(1) 정의
- 제어자 static은 "공통적인"이라는 뜻을 가지고 있는 제어자입니다.
(2) 사용될 수 있는 곳
- 멤버 변수, 메서드, 초기화 블럭
제어자 | 사용 가능 대상 | 특징 |
static | 멤버 변수 | - 생성된 모든 인스턴스에 공통적으로 사용 가능한 클래스 변수 - 클래스 변수는 객체(클래스의 인스턴스)를 생성하지 않고도 사용 가능 - 클래스가 메모리에 로드될 때 생성 |
메서드 | - 인스턴스를 생성하지 않고도 메서드 호출이 가능한 Static 메서드 - Static 메서드 내부에서는 인스턴스 멤버(인스턴스 변수, 인스턴스 메서드)를 사용할 수 없음 |
class StaticModifierTest {
// 자의 공통적인 특성을 나타내는 길이, 소재(클래스 변수)
static int length = 10;
static String material = "plastic";
// 자의 공통적인 기능 - 길이 측정 (static 메서드)
static void calculateLength(int length) {
System.out.println("해당 사물의 길이는 " + length + "cm입니다.");
}
// 클래스 초기화 블럭 - 클래스 변수의 초기화 수행
static {
// 내용 생략;
}
}
1-5. final
(1) 정의
- 제어자 final은 "마지막의, 변경 불가능한" 이라는 뜻을 가진 제어자입니다.
(2) 사용될 수 있는 곳
- 클래스, 메서드, 멤버변수, 지역변수
제어자 | 사용 가능 대상 | 특징 |
final | 클래스 | - 변경 불가능한 클래스가 되며, 확장 불가능한 클래스가 된다. - 해당 클래스는 다른 클래스의 부모(조상) 클래스가 될 수 없다. |
메서드 | - 변경 불가능한 메서드가 되며, 해당 메서드는 메서드 오버라이딩이 불가능하다. | |
멤버 변수 | - 변수 앞에 final이 붙은 경우 해당 변수는 변경 불가능한 상수값이 된다. | |
지역 변수 |
1-6. abstract
(1) 정의
- 제어자 abstract은 "추상적인, 미완성된" 이라는 뜻을 가진 제어자입니다.
(2) 사용될 수 있는 곳
- 클래스, 메서드
(3) 추상 클래스(Abstract class)
- 하나 이상의 추상 메서드를 가지고 있는 클래스를 의미합니다.
(4) 추상 메서드(Abstract method)
- 아직 완성되지 않은 메서드를 의미하며 선언부는 완성되어 있으나 구현부가 정의되지 않은 메서드입니다.
- 추상 클래스와 추상 메서드는 이후 포스팅에서 자세히 한 번 더 다뤄보도록 하겠습니다.
제어자 | 사용 가능 대상 | 특징 |
abstract | 클래스 | - 클래스 내부에 추상 메서드가 선언되어 있는 클래스임을 나타낸다. (미완성 클래스, 추상 클래스) |
메서드 | - 선언부는 정의되어 있으나 구현부가 정의되지 않은 메서드임을 나타낸다. (미완성 메서드, 추상 메서드) |
// 추상 클래스
abstract class AbstractClassTest {
// 추상 메서드
abstract void abstractMethod();
}
2. 접근 제어자(Access modifier), 캡슐화(Encapsulation)
2-1. 접근 제어자의 정의
- 클래스와 멤버(변수, 메서드)에 사용되며 외부에서 해당 클래스나 메서드에 대해 접근 권한을 설정할 수 있는 제어자를 의미합니다.
2-2. 접근 제어자의 종류
접근 제어자 | 특징 |
private | 같은 클래스 내에서만 접근이 가능하다. |
(default) | 같은 패키지 내에서만 접근이 가능하다. |
protected | 같은 패키지 내부와 다른 패키지의 자식 클래스에서 접근이 가능하다. |
public | 접근 제한이 존재하지 않음 |
2-3. 접근 제어자의 접근 가능 범위
제어자 | 동일 클래스 | 동일 패키지 | 동일 패키지 내부, 다른 패키지의 자식 클래스 |
제한 없음 |
public | O | O | O | O |
protected | O | O | O | X |
(default) | O | O | X | X |
private | O | X | X | X |
2-4. 접근 제어자를 이용한 캡슐화(Encapsulation)
(1) 캡슐화(Encapsulation)
- 객체지향 프로그래밍(Object Oriented Programming, OOP)의 4대 원칙 중 하나로써, 객체의 속성(데이터 필드 - 변수)과 다양한 기능(메서드)을 하나로 묶고 실제 기능들의 구현 방법을 외부로부터 감추는 것을 의미합니다.
- 이러한 특성 때문에 *정보 은닉(Information hiding)의 개념도 포함하고 있습니다.
- * 정보 은닉(Information hiding) : 외부에서 객체의 속성에 대해 접근할 수 없도록 막는 것
(2) 접근 제어자를 사용하는 이유
- 쉽게 말하면 외부로부터 데이터를 보호하기 위해 사용합니다.
- 외부에서는 불필요한 정보(특정 기능에 대한 구현 방법), 내부적으로 특정 기능을 구현하기 위해 사용되는 로직 부분을 감추기 위해 사용합니다.
public class TimeWatch {
// 외부로부터 발생하는 직접적인 데이터 접근을 막는다
private int hour; // 0~24
private int minute; // 0~59
private int second; // 0~59
// 단, 메서드를 통해 직접 접근하는 방법은 허용한다.
/* 시계 특성 상, 임의의 수가 들어오는 건 허용될 수 없으므로
메서드를 통해 직접 값을 넘기도록 하고, 단 원하는 값이 아닐 경우엔
값을 저장할 수 없도록 하고 유효한 값만 저장될 수 있도록 한다 */
public int getHour() { return hour; }
public void setHour(int hour) {
if (hour < 0 || hour > 23)
return;
else
this.hour = hour;
}
}
2-5. 생성자의 접근 제어자
- 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치하는 특성을 가집니다.
- 생성자에 접근 제어자를 사용함으로써, 객체 생성을 방지할 수 있습니다.
class FixedUser {
/* 현재 수용 인원은 100명이고 관리자에 여건에 따라 최대 수용인원을
수정할 수 있음, 외부에선 수용 인원 수정은 불가능하다. */
int USER_NUMBER = 100;
// 외부에서 객체를 생성할 수 없도록 한다.
private FixedUser(int modifyUserNumber) {
USER_NUMBER = modifyUserNumber;
}
}
public class FixedUserNumber {
public static void main(String[] args) {
// 최대 인원을 바꾸고자 객체 생성 시 오류 발생
FixedUser fu = new FixedUser(30); // java: FixedUser(int) has private access in FixedUser
}
}
2-6. 제어자 조합 원칙
사용 가능 대상 | 사용 가능한 제어자 |
클래스 | public, (default), final, abstract |
메서드 | 모든 접근 제어자, final, abstract, static |
멤버 변수 | 모든 접근 제어자, final, static |
지역 변수 | final |
(1) 메서드에 static, abstract를 함께 사용할 수 없습니다.
- 메서드에서 static은 구현부가 존재할 때만 사용 가능하기 때문입니다.
(2) 클래스에 abstract, final을 동시에 사용할 수 없습니다.
- 클래스에 사용되는 final은 더 이상 클래스를 확장할 수 없는 클래스임을 나타내며, 클래스에서 abstract는 상속을 통해 완성되어야 한다는 의미를 가지므로 서로 의미가 모순되기에 동시에 사용할 수 없게 됩니다.
(3) abstract 메서드의 접근 제어자가 private일 수 없습니다.
- abstract 메서드일 땐 자식 클래스에서 구현해야 하는데 접근 제어자가 private이면 자식 클래스에서 부모 클래스에 접근할 수 없기 때문입니다.
(4) 메서드에 private, final을 동시에 사용할 필요는 없습니다.
- 접근 제어자가 private인 메서드는 오버라이딩할 수 없으므로 private, final 둘 중 하나만 사용되어야 합니다.
3. 다형성(Polymorphism)
3-1. 다형성(Polymorphism)의 정의
- 객체지향 프로그래밍(Object Oriented Programming, OOP)의 4대 원칙 중 하나로써 특정 객체가 여러 가지 타입을 가질 수 있는 것을 의미하며, 부모(조상) 클래스 타입의 참조변수로 자식 클래스 타입의 객체를 다룰 수 있는 것을 말합니다.
3-2. 참조 변수의 형 변환 (Type casting of reference variable)
- 생성된 객체에서 사용할 수 있는 멤버(변수, 메서드)의 개수를 조절하기 위해 사용되는 타입 변환입니다.
- 서로 상속 관계(부모 ↔ 자식)에 있는 클래스 사이에서만 형 변환이 가능합니다.
- 사용할 수 있는 멤버의 개수를 조절할 때 사용되나 기존 클래스의 멤버에 대한 정보는 수정할 수 없습니다.
3-3. 업캐스팅(Upcasting), 다운캐스팅(Downcasting)
(1) 업캐스팅(Upcasting)
- 자손 타입에서 부모(조상) 타입으로의 형 변환이며 생략 가능합니다.
(2) 다운캐스팅(Downcasting)
- 부모(조상) 타입에서 자손 타입으로의 형 변환이며 생략 불가능하고, 반드시 형 변환을 명시해야 합니다.
- 아래 예시 코드를 통해 확인해 보겠습니다.
class GeneralCar {
// 공통 속성 - 운전
void drive() { System.out.println("drive!"); }
// 공통 속성 - 정지
void stop() { System.out.println("Stop!"); }
}
// 소방차 클래스 정의
class FireFighterCar extends GeneralCar {
// 소방차의 기능 : 물 뿌리기
void water() { System.out.println("Water!"); }
// 소방차의 기능 : 사이렌 울리기
void siren() { System.out.println("Siren!"); }
}
// 구급차 클래스 정의
class AmbulanceCar extends GeneralCar {
// 구급차의 기능 : 사이렌 울리기
void siren() { System.out.println("Siren!"); }
}
class TypecastingReferenceVariableTest {
public static void main(String[] args) {
GeneralCar gc = null;
FireFighterCar f1 = new FireFighterCar();
FireFighterCar f2 = null;
f1.water(); // Water!
// up-casting으로 형 변환 생략 가능하나 생략하지 않고도 코드 작성이 가능합니다.
gc = (GeneralCar) f1;
// down-casting이므로 형 변환을 생략할 수 없습니다.
f2 = (FireFighterCar) gc;
f2.water(); // Water!
}
}
3-4. instanceof 연산자
- instanceof 연산자는 참조 변수가 실제로 참조하고 있는 객체(클래스의 인스턴스) 타입을 체크하는데 사용되는 연산자입니다.
- 문법 : 참조변수명 instanceof 연산할 클래스명
- 참조 변수의 형 변환 가능 여부를 체크할 때 주로 사용하며 instanceof 연산자의 연산 결과가 true이면 자신 클래스를 제외한 나머지 타입으로 형 변환이 가능합니다. (상속 계층도에서 해당 객체와 부모 ↔ 자식 클래스 관계이기에 가능)
- instanceof 연산자를 사용하여 실제 객체의 타입을 체크할 때, 해당 객체의 부모(또는 최고 조상) 클래스에 대해서도 모두 true를 반환합니다. (상속 계층도를 바탕으로 자신을 포함한 부모(조상) 클래스도 모두 True)
// 위에서 정의한 코드를 바탕으로 새로운 소방차 객체를 생성하였다.
FireFighterCar f1 = new FireFighterCar();
/* 아래 코드는 형 변환 전 해당 타입으로 형 변환이 가능한지 확인하기 위해
instanceof 연산자를 사용하였다. */
/* FireFighter 자신 클래스를 제외하고 나머지는 모두 부모 클래스이므로 형 변환이 가능하기에
True가 반환되었다 */
System.out.println(f1 instanceof Object); // true
System.out.println(f1 instanceof GeneralCar); // true
System.out.println(f1 instanceof FireFighterCar); // true
3-5. 매개변수(Parameter)의 다형성 - 다형성의 장점(1)
- 메서드의 매개변수로 객체 타입을 넘겨준다면, 해당 클래스의 객체뿐만이 아니라 해당 객체의 자식 클래스의 객체도 넘겨줄 수 있습니다.
- 메서드 호출 시, 매개변수로 자신과 같은 객체 타입 또는 해당 객체의 자식 클래스 객체 타입을 넘길 수 있으며 이를 통해 메서드의 호출 결과가 다양해질 수 있습니다.
3-6. 여러 종류의 객체를 배열로 다루는 방법 - 다형성의 장점(2)
- 하나의 배열에 여러 종류의 객체를 저장하여 관리할 수 있습니다.
- 즉, 부모 클래스 타입 배열에 자식 클래스의 인스턴스들을 담아서 관리할 수 있으며 이 부분은 객체지향의 다형성을 이용한 뚜렷한 장점입니다.
- 학부에서 수강했던 전공 수업 내용을 정리하는 포스팅입니다.
- 내용 중에서 오타 또는 잘못된 내용이 있을 시 지적해 주시기 바랍니다.
'전공 수업 > 객체 지향 프로그래밍(Java)' 카테고리의 다른 글
[12주 차] - 클래스 상속, 메서드 오버라이딩, 참조변수 super, 생성자 super(), 패키지와 import문 (0) | 2022.11.20 |
---|---|
[11주 차] - 메서드 오버로딩, 생성자, 참조변수 this, 멤버 변수 초기화 (0) | 2022.11.10 |
[10주 차] - 클래스 변수, 인스턴스 변수, 지역 변수, 클래스 메서드와 인스턴스 메서드 (0) | 2022.11.06 |
[9주 차] - 메서드의 개념, 클래스와 객체 (0) | 2022.11.04 |
[7주 차] - Math.random() 메서드, 제어문(반복문, 조건문)을 사용한 코드 예제 (0) | 2022.10.12 |
댓글