제어자(modifier)
클래스와 클래스의 멤버(멤버 변수, 메서드)에 부가적인 의미를 부여
하나의 대상에 여러 제어자를 같이 사용가능(접근 제어자는 하나만) 접근 제어자를 가장 먼저 사용하는 경향이 있음
종류
접근 제어자 : public protected, (default), private => 4개 중 1개만
그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp
static - 클래스의, 공통적인
멤버 변수 : 모든 인스턴스에 공통적으로 사용되는 클래스 변수가 됨, 클래스 변수는 인스턴스를 생성하지 않고도 사용 가능, 클래스가 메모리에 로드될 때 생성
메서드 : 인스턴스를 생성하지 않고도 호출이 가능한 static 메서드가 됨, static메서드 내에서는 인스턴스 멤버들을 직접 사용할 수 없음
final - 마지막의, 변경될 수 없는
클래스 : 변경될 수 없는 클래스, 확장될 수 없는 클래스가 됨. final로 지정된 클래스는 다른 클래스의 부모(조상)이 될 수 없음. 상속계층도에 가장 아래에 있음. String, Math
메서드 : 변경될 수 없는 메서드, final로 지정된 메서드는 오버라이딩을 통해 재정의 불가
멤버변수, 지역변수 : 변수 앞에 final이 붙으면, 값을 변경할 수 없는 상수가 됨
abstract - 추상의, 미완성의
추상 클래스를 상속받아서 완전한 클래스(구상 클래스)를 만든 후 객체 생성 가능
클래스 : 클래스 내에 추상 메서드가 선언되어 있음을 의미. 추상메서드를 가지고 있다면 추상 클래스. 인스턴스 생성불가
메서드 : 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알림
package chapter07;
class ParentS9E1{
private int privateVariable; //같은 클래스
int defaultVariable; //같은 패키지
protected int protectedVariable;//같은 패키지 + 자손(다른 패키지)
public int publicVariable; //접근제한이 없음
public void printMembers() {
System.out.println(privateVariable);
System.out.println(defaultVariable);
System.out.println(protectedVariable);
System.out.println(publicVariable);
}
}
public class Study09Ex1 {
public static void main(String[] args) {
ParentS9E1 parentS9E1 = new ParentS9E1();
// System.out.println(parentS9E1.privateVariable); //에러. 접근 범위가 안맞음
System.out.println(parentS9E1.defaultVariable);
System.out.println(parentS9E1.protectedVariable);
System.out.println(parentS9E1.publicVariable);
}
}
package chapter07;
class ChildS9E1 extends ParentS9E1{
public void printMembers() {
// System.out.println(privateVariable); //에러
System.out.println(defaultVariable);
System.out.println(protectedVariable);
System.out.println(publicVariable);
}
//만약 다른 패키지에 있는 클래스는
// public void printMembers() {
// System.out.println(privateVariable); //에러
// System.out.println(defaultVariable); //에러
// System.out.println(protectedVariable);
// System.out.println(publicVariable);
// }
}
public class Study09Ex2 {
public static void main(String[] args) {
}
}
캡슐화
캡슐화와 접근 제어자
접근 제어자를 사용하는 이유 => 외부로부터 데이터를 보호하기 위해서(Study10Ex1)
외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해(접근 제어자 범위는 좁을 수록 좋음 필요하면 넓히는 것으로 해야함)
package chapter07;
class Time{
//접근 제어자를 private으로 하여 외부에서 직접 접근하지 못하도록 함
private int hour;
private int minute;
private int second;
//메서드를 통해서 iv에 접근. 메서드를 통해 간접 접근 허용
public int getHour() {
return hour;
}
public void setHour(int hour) {
if(isNotValidHour(hour)) {
return;
}
this.hour = hour;
}
//매개변수로 넘겨지 hour가 유효한지 확인해서 알려주는 메서드
private boolean isNotValidHour(int hour) {
return hour < 0 || hour >24;
}
}
public class Study10Ex1 {
public static void main(String[] args) {
Time time = new Time();
// time.hour = -1;
time.setHour(21); //hour의 값을 21로 변경
System.out.println(time.getHour());
time.setHour(100);
System.out.println(time.getHour());
}
}
다형성(polymorphism)
여러 가지 형태를 가질 수 있는 능력
조상 타입 참조 변수로 자손 타입 객체를 다루는 것
객체와 참조변수의 타입이 일치할 때와 일치하지 않을 때 차이?
SmartTV sTV = new SmartTV(); //참조 변수와 인스턴스의 타입이 일치 => 모든 기능 사용 가능
TV tv = new SmartTV(); //조상 타입 참조변수로 자손 타입 인스턴스 참조 => TV 기능만 사용 가능
자손 타입의 참조변수로 조상 타입의 객체를 가리킬 수 없음
TV tv = new SmartTV(); //허용
SmartTV sTV = new TV(); //에러. 허용안됨. 없는 기능을 호출해서 에러가 발생
package chapter07;
class TVS11E1{
boolean power; //전원상태
int channel;
void power() {
power = !power;
}
void channelUp() {
++channel;
}
void channelDown() {
--channel;
}
}
class SmartTVS11E1 extends TVS11E1{
String text; //자막을 보여주기 위한 문자열
void caption() {
//구현부
}
}
public class Study11Ex1 {
public static void main(String[] args) {
//타입이 일치
TVS11E1 tvs11e1 = new TVS11E1();
SmartTVS11E1 smartTVS11E1 = new SmartTVS11E1();
//타입 불일치
TVS11E1 t = new SmartTVS11E1();
}
}
참조변수의 타입은 인스턴스의 타입과 반드시 일치해야하는가? => 보틍은 일치하지만 일치하지 않을 수도 있음(다형성)
참조변수가 조상타입일 때와 자손타입일 때의 차이는? => 참조변수로 사용할 수 있는 멤버의 개수가 달라짐
자손타입의 참조변수로 조상타입의 객체를 가리킬 수 있을까? => ㄴㄴ. 자손 기능이 더 많기 때문에 허용되지 않음
참조변수의 형 변환
기본형 형변환의 경우 값이 바뀌며, 참조변수의 형 변환은 사용할 수 있는 멤버의 갯수를 조절하는 것
조상-자손 관계의 참조변수는 서로 형 변환 가능(Study12Ex1)
package chapter07;
class CarS12E1{
String color;
int door;
void drive() {
System.out.println("운전하는 기능");
}
void stop() {
System.out.println("정지하는 기능");
}
}
// 자식 부모
class FireTruckS12E1 extends CarS12E1{
void water() {
System.out.println("물을 뿌리는 기능");
}
}
class AmbulanceS12E1 extends CarS12E1{
void siren() {
System.out.println("사이렌 울리는 기능");
}
}
public class Study12Ex1 {
public static void main(String[] args) {
FireTruckS12E1 fireTruck = new FireTruckS12E1();
CarS12E1 car = (CarS12E1)fireTruck; //조상(부모) 타입으로 형변환(생략 가능)
FireTruckS12E1 fireTruck2 = (FireTruckS12E1)car; //자손(자식) 타입으로 형변환(생략 불가)
// AmbulanceS12E1 ambulance = (AmbulanceS12E1)fireTruck; //상속관계가 아닌 클래스 간의 형변환 불가
}
}
instanceof 연산자
참조변수의 형변환 가능여부(조상-자손) 확인에 사용. 가능하면 true 반환
형변환 확인 -> 형변환(instanceof 연산자 사용)
형변환 전 반드시 instanceof로 확인해야함
package chapter07;
class CarS13E1{
String color;
String type;
void start() {
System.out.println("시동을 거는 기능");
}
void stop() {
System.out.println("시동을 멈추는 기능");
}
}
class FireEngineS13E1 extends CarS13E1{
void water() {
System.out.println("물을 뿌리는 기능");
}
}
public class Study13Ex1 {
public static void main(String[] args) {
CarS13E1 car = new CarS13E1();
FireEngineS13E1 fe = new FireEngineS13E1();
System.out.println(fe instanceof CarS13E1);
System.out.println(fe instanceof FireEngineS13E1);
}
}
참조변수의 형변환은 왜함? => 참조변수를 변경함으로써 사용할 수 있는 맴버의 개수를 조절하기 위해서
instanceof 연산자는 언제 사용? => 참조변수를 형변환하기 전에 형변환 가능 여부를 확인할 때