1006 JAVA - 상수, 인터페이스
Contents
상수(Constant)
변하지 않는 데이터 = 변하지 않는 데이터를 저장한 변하지 않는 변수이다.
보통 클래스 내에서 상수를 선언 시 public static final 형태로 선언
1) public
누구나 접근 가능
2) static
클래스 로딩 시 함께 로딩되어 인스턴스 생성과 무관하며, 클래스 하나 당 생성되면서 모든 인스턴스가 공유한다.
=> 클래스명만으로 접근 가능(클래스명.변수명)
3) final
데이터 변경 불가 = 상수
public static final를 쓰는 이유
public에 의해 어디서든 접근이 가능하며 static에 의해 클래스명만으로 인스턴스 생성 없이 접근 가능하며
final에 의해 데이터가 유지되기 때문이다
상수를 활용하지 않는 클래스 (문제)
class CarInfo {
private String company;
private String carModelName;
private int color;
//alt shift s + r (getter/setter)
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getCarModelName() {
return carModelName;
}
public void setCarModelName(String carModelName) {
this.carModelName = carModelName;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
}
특정 클래스 내에서 사용되는 데이터를 상수로 제공하면 문자열의 오타나, 정수형 파라미터 사용 할때의 어려움을 해결 가능
1. 제조사 정보를 문자열로 저장하는 상수 선언
2. 차량 모델 정보를 문자열로 저장하는 상수 선언
3. 차량 색상 정보를 정수로 저장하는 상수 선언
public static final String COMPANY_HYUNDAI = "HYUNDAI";
public static final String COMPANY_KIA = "KIA";
public static final String COMPANY_CHEVROLET = "CHEBROLET";
public static final String CAR_MODEL_NAME_SONATA = "SONATA";
public static final String CAR_MODEL_NAME_K5 = "K5";
public static final String CAR_MODEL_NAME_SPARK = "SPARK";
public static final int COLOR_PERFECT_BLACK = 0x000001;
public static final int COLOR_CREAM_WHITE = 0xffffcc;
public static final int COLOR_BARCELONA_RED = 0xff0000;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getCarModelName() {
return carModelName;
}
public void setCarModelName(String carModelName) {
this.carModelName = carModelName;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
}
CarInfo ci = new CarInfo();
객체에 차량 정보를 저장하는 경우
값을 직접 입력 할 때 문자열 등의 오타로 인한 오류 발생 가능성 있음.
ci.setCompany("hyundai");
ci.setCarModelName("sonata");
ci.setColor(0x000000); // 복잡한 값을 지정하기 어려움
차량 정보를 비교해야하는 경우
=> 문자열의 경우 대소문자에 대한 차이 등으로 잘못된 판별도 가능
if(ci.getCompany() == "hyundaI") {
System.out.println("현대자동차입니다");
}else {
System.out.println("아닙니다");
}
if(ci.getCarModelName()=="SONATA");{
System.out.println("쏘나타입니다");
} {
System.out.println("아닙니다");
}
CarInfoWithConstant ci2 = new CarInfoWithConstant();
Setter 를 호출하여 값을 저장할 때 직접 입력하지 않고 클래스명.상수명을 통해 상수를 불러와서 지정 가능하므로
잘못된 데이터를 저장할 확률이 낮아지게 된다.
ci2.setCompany(CarInfoWithConstant.COMPANY_HYUNDAI);// 제조사
ci2.setCarModelName(CarInfoWithConstant.CAR_MODEL_NAME_SONATA); //모델명
ci2.setColor(CarInfoWithConstant.COLOR_PERFECT_BLACK);
//값 비교할때도 상수명으로 하면 되니까 오류 발생 x
if(ci2.getCompany()==CarInfoWithConstant.COMPANY_HYUNDAI) {
System.out.println("현대 자동차 입니다");
}else {
System.out.println("현대 자동차가 아닙니다.");
}
상수 활용의 예
Calendar 클래스를 사용하여 날짜 정보를 관리할 때
Calendar 클래스의 get() 메서드를 통해 연,월,일 을 가져오는데 항목 지정 시 Calendar 클래스에서 제공하는 상수를 통해 지정
Calendar cal = Calendar.getInstance();
System.out.println("올해는 몇 년도?" + cal.get(Calendar.YEAR));
}
}
class CarInfoWithConstant {
private String company;
private String carModelName;
private int color;
인터페이스 (Interface)
1) 클래스가 아님. 선언 시 class 키워드 사용 x
2) interface를 적어준다
3) 상수, 추상메서드를 가질 수 있다.
추상클래스와 마찬가지로 추상메서드를 포함하므로 객체 생성 불가능
=> 단, 참조변수 타입으로는 사용 가능(=다형성을 활용한 업캐스팅 가능)
MyExInterface mi2 = new MySubClass(); //업캐스팅
업캐스팅 이후로는 참조 영역이 축소되므로, 상속된 메서드만 호출 가능
=> 인터페이스의 추상메서드를 모두 오버라이딩 했기 때문에 인터페이스가 가진 모든 메서드는 호출이 가능.
=> 동적 바인딩 때문
상수도 인터페이스에서 선언했으므로 업캐스팅 후에도 접근 가능
System.out.println(mi2.NUM1);
System.out.println(mi2.NUM2);
서브클래스(구현클래스)에서 인터페이스를 상속받아 구현해야 하는 경우 extends 키워드 대신 implement 키워드를 사용
=> 클래스는 상속받아 확장(extends)의 개념, 하지만 인터페이스는 상속받아 추상메서드를 구현(implement)의 개념이 강함.
클래스는 서브클래스에서 다중 상속이 불가능하지만, 인터페이스는 서브클래스에서 다중 상속(구현)이 가능하다!
=> implements 키워드 뒤에 복수개의 인터페이스 지정 가능
인터페이스끼리 상속받을 경우 implements 가 아닌 extends 로 상속
=>추상메서드는 구현(implement)하지 못하기 때문.
극단적으로 동일한 목적 하에 동일한 기능을 보장하게 하기 위함이고,
자바의 다형성을 이용하여 개발코드 수정을 줄이고 유지보수성을 높이는 것이다.
Interface 정의 기본 문법
[접근제한자] interface 인터페이스명 {
상수
추상메서드
}
interface MyExInterface {
}
인터페이스를 상속받은(=구현하는) 서브클래스(구현클래스) 정의 문법
[접근제한자] class 클래스명 implements 인터페이스명 {}
모든 멤버변수는 public static final 이 붙은 상수로 취급 됨 (생략 가능) final 로 인해 값 변경 불가, static으로 인해 클래스명만으로 접근 가능
public으로 인해 누구나 접근 가능
=> 모든 메서드는 public abstract 이 붙은 추상 메서드로 취급 됨. (public abstract 생략 가능)
=> 메서드 Body를 가질 수 없으며, public으로 인해 누구나 접근 가능.
interface MyExInterface {
//인터페이스 내의 모든 멤버변수는 상수(public static final)이다
public static final int NUM1 = 10; //상수
int NUM2 = 20; // 상수(public static final 생략되어 있음)
인터페이스는 생성자를 가질 수 없다.
public MyExInterface() {}
=> Interfaces cannot have constructors (컴파일 에러 발생)
추상메서드는 body를 가질 수 없다.
public void method2() {}
Abstract methods do not sepcify a body (일반메서드 - 컴파일 에러 발생)
추상 클래스는 인스턴스를 생성할 수 없다.
MyClass mc = new Myclass(); (X)
자체적으로 객체를 생성할 수 없다.
따라서 상속을 통해 자식 클래스에서 인스턴스를 생성해야 한다.
인터페이스도 인스턴스를 생성할 수 없다.
MyExInterface mi = new MyexInterFace(); (X)
public abstract 생략 가능
void method3();
인터페이스를 상속받아 구현하는 서브클래스(구현클래스) MySubClass 정의
=> 서브클래스 정의 시 클래스명 뒤에 implements 키워드를 쓰고 인터페이스명 지정
인터페이스의 장점
인터페이스를 사용하면 다중 상속이 가능할 뿐만 아니라 다음과 같은 장점을 가질 수 있다.
1. 대규모 프로젝트 개발 시 일관되고 정형화된 개발을 위한 표준화가 가능.
2. 클래스의 작성과 인터페이스의 구현을 동시에 진행할 수 있으므로, 개발 시간을 단축.
3. 클래스와 클래스 간의 관계를 인터페이스로 연결하면, 클래스마다 독립적인 프로그래밍이 가능.
문제
다이아몬드 상속에서의 문제점(이슈)
번식() 메서드를 갖는 슈퍼클래스 동물 클래스를 정의하고 고래와 상어 클래스에서 동물클래스를 상속 받기
메서드를 호출했을 때, 고래상어가 상어와 고래 둘 다 상속했을 때 문제가 생긴다
어느 객체의 번식 메서드(고래냐? 상어냐?)를 호출해야 하는지 혼동을 주기 때문에 다중 상속 금지한다
=> 인터페이스(다중상속) 처리로 해결...
문제
전투 기능을 갖는 Fightable 인터페이스 => fight() 메서드
변신 기능을 갖는 Trnasformable 인터페이스 => transform() 메서드
=> transform() 메서드 (리턴값 없음, 파라미터(int mode))
=> 상수 값 (MODE_CAR = 1, MODE_AIRPLANE = 2, MODE_NORMAL = 3)
Robot 인터페이스 정의
=> Fightable 인터페이스, Transformable 인터페이스 상속
=> 말하기 기능 (speak())
Robot인터페이스를 구현하는 BumbleBee 클래스 정의
=> Fight() 메서드 호출 시 "로켓 발사!" 출력
=> transform() 메서드 호출 시 mode 값에 따라 다른 형태로 변신
MODE_NORMAL 일 경우 "기본 모드(로봇)로 변신" 출력
MODE_CAR 일 경우 "자동차로 변신" 출력
MODE_AIRPLANE 일 경우 "비행기로 변신" 출력
=> speak() 메서드 호출 시 "라디오로 말하기!" 출력
package interface_;
public class Test2 {
public static void main(String[] args) {
BumbleBee bee = new BumbleBee();
bee.fight();
bee.speak();
bee.transform(BumbleBee.MODE_NORMAL);
bee.transform(BumbleBee.MODE_CAR);
bee.transform(BumbleBee.MODE_AIRPLANE);
}
}
interface Fightable {
public abstract void fight();
}
interface Transformable {
public static final int MODE_CAR = 1;
public static final int MODE_AIRPLANE = 2;
public static final int MODE_NORMAL = 3;
public abstract void transform(int mode);
}
interface Robot extends Fightable, Transformable {
public abstract void speak();
}
class BumbleBee implements Robot {
@Override
public void fight() {
System.out.println("로켓 발사!");
}
@Override
public void transform(int mode) {
if(mode == Transformable.MODE_NORMAL) {
System.out.println("기본 모드(로봇)로 변신");
} else if(mode == Transformable.MODE_CAR) {
System.out.println("자동차로 변신");
} else if(mode == Transformable.MODE_AIRPLANE) {
System.out.println("비행기로 변신");
}
}
@Override
public void speak() {
System.out.println("라디오로 말하기!");
}
}
추상메서드 abstract 와 interface의 차이?
abstract - 추상 클래스를 상속받아서 확장/ 다중 모호성 때문에 하나만 상속
interface - 강제 구현 / 인터페이스를 구현한 객체들에 대해 동일한 동작을 해주기 위해 존재