추상클래스처럼 추상메서드를 갖지만 추상클래스보다 추상화 정도가 높다. => 추상클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버변수를 구성원으로 가질 수 없다. 오직 추상메서드와 상수만을 멤버로 가질 수 있다.
인터페이스는 구현된 것은 아무것도 없고 밑그림만 그려진 '기본 설계도'
interface 인터페이스이름 { public static final 타입 상수이름 = 값; public abstract 메서드이름(매개변수목록); }
인터페이스 멤버들의 제약사항
모든 멤버변수는 public static final ,이어야 하며, 이를 생략할 수 있다.
모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다. => 단, static 메서드와 디폴트 메서드는 예외(JDK1.8부터)
interface PlayingCard { public static final int SPADE = 4; final int DIAMOND = 3; // public static final int DIAMOND = 3; static int HEART = 2; // public static final int HEART = 2; int CLOVER = 1; // public static final int CLOVER = 1;
public abstract String getCardNumber(); String getCardKind(); // public abstract String getCardKind(); }
인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다.
# 인터페이스 구현
인터페이스도 추상클래스처럼 그 자체로는 인스턴스를 생성할 수 없다.
인터페이스는 자신에 정의된 추상메서드의 몸통을 만들어주는 클래스를 작성해야 한다.
추상클래스는 확장한다는 의미의 키워드 'extends', 인터페이스는 구현한다는 의미의 키워드 'implements'
인터페이스의 이름은 주로 Fightable과 같이 '~ 을 할 수 있는'의 의미인 able로 끝나는 경우가 많다.
class 클래스이름 implements 인터페이스이름 { // 인터페이스에 정의된 추상메서드를 구현해야 한다. }
class Fighter implements Fightable { public void move(int x, int y) { /* 내용 생략 */ } public void attack(Unit u) { /* 내용 생략 */ } }
# 인터페이스의 장점
개발시간을 단축시킬 수 있다.
표준화가 가능하다.
서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
독립적인 프로그래밍이 가능하다. - 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능하다.
같은 타입이 아닌 서로 다른 타입 간의 연산을 수행할 때, 이럴 때는 같은 타입으로 일치시켜야 한다. => 이때 변수나 리터럴의 타입을 다른 타입으로 변환하는 것을 '형 변환(casting)'이라고 한다.
# 형 변환 방법
(타입)피연산자
형 변환하고자 하는 변수나 리터럴의 앞에 변환하고자 하는 타입을 괄호와 함께 붙여주기만 하면 된다.
여기에 사용되는 괄호()는 '캐스트 연산자' 또는 '형 변환 연산자'라고 한다.
class CastingEx1 {
public static void main(String[] args) {
double d= 85.4;
int score = (int)d; // double 타입의 변수 d를 int타입으로 형변환
System.out.println("score="+score); // score=85
System.out.println("d="+d); // d=85.4 <--형변환 후에도 피연산자에는 아무런 변화가 없다.
}
}
형 변환 연산자는 그저 피연산자의 값을 읽어서 지정된 타입으로 형 변환하고 그 결과를 반환할 뿐이다. => 피연산자인 변수 d의 값은 형 변환 후에도 아무런 변화가 없다.
float타입의 값을 int타입으로 변환할 때 소수점 이하의 값은 반올림이 아닌 버림으로 처리된다.
# 정수형 간의
int타입(4 byte)의 값을 byte타입(1 byte)으로 변환하는 경우는 크기의 차이만큼 잘려나간다. => 경우에 따라 '값 손실(loss of data)'이 발생할 수 있다. ex) int -> byte로 형 변환 시
# 실수형 간의 형 변환
정수형처럼 작은 타입에서 큰 타입으로 변환하는 경우, 빈 공간을 0으로 채운다.
반대로 double타입에서 float타입으로 변환하는 경우, double의 가수 52자리 중 23자리만 저장되고 나머지는 버려진다.
double d = 1.0e100; // float의 최대값보다 큰 값을 d에 저장(1.0x10^100)
float f = (float)d; // d의 값을 float로 형변환해서 f에 저장. f는 무한대가 된다.
double d = 1.0e-50; // float의 최소값보다 작은 값을 d에 저장(1.0x10^-50)
float f = (float)d; // f의 값은 0이 된다.
float타입의 범위를 넘는 float로 형 변환하는 경우는 '+-무한대' 또는 '+-0'을 결과로 얻는다.
# 정수형과 실수형 간의 형 변환
정수형과 실수형은 저장형식이 완전히 다르기 때문에 정수형간의 변환처럼 간단히 값을 채우고 자르는 식으로 할 수 없다 => 좀 더 복잡한 변환 과정을 거쳐야 한다.
정수형을 실수형으로 변환
정수는 소수점 이하의 값이 없으므로 비교적 변환이 간단하다.
정수를 2진수로 변환한 다음 정규화를 거쳐 실수의 저장 형식으로 저장될 뿐이다.
실수형은 정수형보다 훨씬 큰 저장 범위를 갖기 때문에, 정수형을 실수형으로 변환하는 것은 별 무리가 없다.
실수형을 정수형으로 변환
실수형을 정수형으로 변환하면, 실수형의 소수점 이하 값은 버려진다. => 정수형의 표현 형식으로 소수점 이하의 값은 표현할 수 없기 때문
# 자동 형 변환
경우에 따라 편의상의 이유로 형 변환을 생략할 수 있다 그렇다고 해서 이루어지지 않는 것은 아니다. => 컴파일러가 생략된 형 변환을 자동적으로 추가한다.
자동 형 변환의 규칙
컴파일러는 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형 변환시킨다.
boolean을 제외한 나머지 7개의 기본형은 서로 형 변환이 가능하다.
기본형과 참조형은 서로 형 변환할 수 없다.
서로 다른 타입의 변수 간의 연산은 형 변환을 하는 것이 원칙이지만, 값의 범위가 작은 타입에서 큰 타입으로의 형 변환을 생략할 수 있다.
프로그래밍 언어에서는 값을 저장할 수 있는 메모리상의 공간을 의미한다. => 이 공간에 저장된 값은 변경될 수 있기 때문에 '변수' 라는 수학용어의 정의와 상통하는 면이 있어서 이렇게 이름을 붙여졌다.
변수란, 단 하나의 값을 저장할 수 있는 메모리 공간."
* 하나의 변수에 단 하나의 값만 저장할 수 있으므로, 새로운 값을 저장하면 기존의 값은 사라진다.
# 변수의 선언과 초기화
변수타입
변수에 저장될 값이 어떤 '타입(type)'인지를 지정하는 것이다.
지정하고자 하는 값의 종류에 맞게 변수의 타입을 선택해서 적어주면 된다.
자바는 정수형, 실수형, 문자형 등 다양한 타입을 제공한다.
변수이름
말 그대로 변수에 붙인 이름이다.
변수는 '값을 저장할 수 있는 메모리 공간'이므로 변수의 이름은 메모리 공간에 이름을 붙여주는 것이다. => 그 이름을 이용해서 저장공간(변수)에 값을 저장하고, 저장된 값을 읽어오기도 할 수 있다.
서로 구별될 수 있게 지어야 한다.
변수의 초기화
변수를 선언한 이후부터는 변수를 사용할 수 있으나, 그 전에 반드시 변수를 '초기화(initialization)'해야 한다. => 메모리는 여러 프로그램이 공유하는 자원이므로 전에 다른 프로그램에 의해 저장된 '알 수 없는 값(쓰레기값, garbage value)'이 남아있을 수 있기 때문이다.