클래스, ,변수, 메서드의 선언부에 사용되어 부가적인 의미를 부여한다.
제어자는 크게 접근제어자와 그 외의 제어자로 나뉜다.
하나의 대상에 여러 개의 제어자를 조합해서 사용할 수 있으나, 접근제어자는 단 하나만 사용가능.
static이 사용될 수 있는 곳 - 멤버변수, 메서드, 초기화 블럭
public class StaticTest {
public static int width = 200;
public static int height = 120;
static{ //클래스의 초기화 블럭
// static변수의 복잡한 초기화 수행
}
public static int max(int a, int b){
return a > b ? a : b;
}
}
fianl이 사용될 수 있는 곳 - 클래스, 메서드, 멤버변수, 지역변수
final이 붙은 변수는 상수이므로 보통은 선언과 초기화를 동시에 하지만,
인스턴스마다 고정값을 갖는 인스턴스 변수의 경우 생성자에서 초기화한다.
(카드의 무늬와 숫자는 한번 결정되면 바뀌지 않아야하는 경우)
abstrace가 사용될 수 있는 곳 - 클래스, 메서드
abstrace class AbstactTest { //추상클래스
abstract void move(); //추상메서드
}
멤버 또는 클래스에 사용되어, 외부로부터 접근을 제어한다.
접근제어자가 사용될 수 있는 곳- 클래스, 멤버변수, 메서드, 생성자
- private : 같은 크래스 내에서만 접근이 가능하다.
- default : 같은 패키지내에서만 접근이 가능하다.
- protected : 같은 패키지 내에서, 그리고 다른패키지의 자손클래스에서 접근이 가능하다.
- public : 접근 제한이 없다(open)
외부로부터 데이터를 보호하기 위해서
외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서
class Time {
private int hour;
private int minute;
private int second;
Time(int hour, int minute, int second) {
this.hour = hour;
this.minute = minute;
this.second = second;
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
if(hour < 0 || hour >23) return;
this.hour = hour;
}
//getter,setter 중간 생략
@Override
public String toString() {
return hour + ":" + minute + ":" +second;
}
}
public class TimeTest {
public static void main(String[] args) {
Time t = new Time(12,35,30);
//System.out.println(t.toString());
System.out.println(t);
//t.hour =13; //Error!
//현재시간보다 1시간 후로 변경한다.
t.setHour(t.getHour()+1);
System.out.println(t);
}
}
일반적으로 생성자의 접근제어자는 클래스의 접근 제어자와 일치한다.
생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.
final class Singleton {
private static Singleton s = new Singleton();
//getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static 이어야 한다.
private Singleton(){}
public static Singleton getInstance(){
if(s==null){
s = new Singleton();
}
return s;
}
}
class SingletonTest{
public static void main(String[] args) {
Singleton s = new Singleton(); //에러!
Singleton s1 = Singleton.getInstance();
}
}
"여러가지 형태를 가질 수 있는 능력"
"하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것"
즉, 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것이 다형성.
"조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있지만,
반대로 자손타입의 참조변수로 조항타입의 인스턴스를 참조할 수는 없다."
서로 상속관계에 있는 타입간의 형변환만 가능하다.
자손 타입에서 조상타입으로 형변환하는 경우,형변환 생략가능(Down-casting)
public class Car {
public String color;
public int door;
public void drive(){ //운전하는 기능
System.out.println("drive, Brrrrr~");
}
public void stop(){ //멈추는 기능
System.out.println("stop");
}
}
class FireEngine extends Car{ //소방차
public void water(){ //물뿌리는기능
System.out.println("water");
}
}
class Ambulance extends Car{ //구급차
public void siren(){ //사이렌을 울리는 기능
System.out.println("siren~");
}
}
public class CarTest {
public static void main(String[] args) {
Car c =null; //초기화;
FireEngine f = new FireEngine();
FireEngine f1 = null;
f.water();
c = f; //c = (car)f; 조상 <- 자손
//c.water();
f1 = (FireEngine) c; //자손 <- 조상
f1.water();
}
}
참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용
이항연산자이며 피연산자는 참조형 변수와 타입. 연산결과는 true or false.
instanceof의 연산결과가 true이면, 해당 타입으로 형변환이 가능하다.
public class InstanceofTest {
public static void main(String[] args) {
FireEngine fe = new FireEngine();
if(fe instanceof FireEngine){
System.out.println("This is a FireEngine instance");
}
if(fe instanceof Car){
System.out.println("This is a Car instance");
}
if(fe instanceof Object){
System.out.println("This is an Object instance");
}
}
}
참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.