본 포스팅은 프로그래머스 자바 입문 강의에 기반하여 작성되었습니다.
자바 강의의 모든 내용이 적힌것이 아닌 복습시 놓쳤던 부분을 하나하나 정리한 내용입니다.
순서 인터페이스 만들기, 사용하기, 인터페이스의 default method, 내부클래스, 익명클래스
- 인터페이스
객체를 만들때 어떤 기능을 가지고 있을까를 고민해야한다.
Tv라는 객체를 만들때 어떤 기능을 가질까?
켜고 끄는 기능
볼륨 조절 기능
채널 변경 기능
실제로 구현을 하지않고 그 기능들만 선언해서 가지고 있는것이 인터페이스다.
인터페이스를 정의하는 방법
추상 메소드와 상수를 정의 할 수 있다.
메소드 앞에 abstract를 써주지 않아도 오류를 발생시키지 않는다.
상수 앞에 final을 써주지 않아도 오류를 발생시키지 않는다.
public interface TV{
public int MAX_VOLUME = 100;
public int MIN_VOLUME = 0;
public void turnOn(); // 추상메소드와 비슷하다.
public void turnOff();
public void changeVolume(int volume);
public void changeChannel(int channel);
}
인터페이스는 자체적으로 타입의 역할을 할 수 있지만, 구현이 하나도 없기때문에
인터페이스 자체가 객체를 생성 해놓지는 못한다.
인터페이스에서 변수를 선언하면 컴파일시 자동으로 아래와 같이 바뀐다.
public static final int MAX_VOLUME = 100;
public static final int MIN_VOLUME = 0;
인터페이스에서 정의된 메소드는 모두 추상 메소드이다.
위에서 선언된 모든 메소드는 컴파일 시에 다음과 같이 자동으로 변경된다.
public abstract void turnOn();
public abstract void turnOff();
public abstract void changeVolume(int value);
public abstract void changeChannel(int number);
인터페이스 사용하기
기능들을 정의만 하였고 구현은 하지 않았기 때문에 인터페이스 만으로 무언가를 사용 할 수는 없다.
인터페이스 사용하는 방법
인터페이스는 사용할때 해당 인터페이스를 구현하는 클래스에서 implements 키워드를 이용한다.
LedTV는 반드시 TV가 가지고 있는 모든 메소드들을 구현해야한다.
public class LedTV implements TV{
public void on(){
System.out.println("켜다");
}
public void off(){
System.out.println("끄다");
}
public void volume(int volume){
System.out.println(value + "로 볼륨조정하다.");
}
public void channel(int channel){
System.out.println("channel을 조정하다.");
}
}
인터페이스가 가지고 있는 메소드를 하나라도 구현하지 않는다면 해당 클래스는 추상클래스가 된다.
(추상클래스는 인스턴스를 만들 수 없음)
public class LedTVExam{
public static void main(String args[]){
TV tv = new LedTV(); // 인터페이스도 타입이 될수있다.
tv.turnOn();
tv.changeVolume(50);
tv.changeChannel(6);
tv.turnOff();
}
}
참조변수의 타입으로 인터페이스를 사용할 수 있다. 이 경우 인터페이스가 가지고 있는 메소드만 사용할 수 있다.
(상속의 개념과 같다)
만약 LedTV가 TV라는 인터페이스가 가지지않은 기능들을 확장해서 사용하고 있고,
그 기능을 사용하고 싶다면 클래스의 형변환을 사용한다.
인터페이스를 사용해야하는 중요한 이유
만약 TV인터페이스를 구현하는 LcdTV를 만들었다면 위의 코드에서 new LedTV부분만 new LcdTV로 변경해도
똑같이 프로그램이 동작할 것이다.
LcdTV도 implements TV 를하여 클래스를 생성하고 메소드를 구현해야한다.
동일한 인터페이스를 구현한다는 것은 클래스 사용법이 같다는 것을 의미한다.
클래스는 이러한 인터페이스를 여러개 구현할 수 있다.
ex) default 메소드는 아래에 설명이 나옴
public interface Screen{
public void a();
default void c() {
System.out.println("c출력");
}
}
public interface Monitor{
public void b();
}
public class LedTv implement Tv, Screen, Monitor{
public void on(){
System.out.println("켜다");
}
public void off(){
System.out.println("끄다");
}
public void volume(int volume){
System.out.println(value + "로 볼륨조정하다.");
}
public void channel(int channel){
System.out.println("channel을 조정하다.");
}
public void a(){
System.out.println("a출력");
}
public void b(){
System.out.println("b출력");
}
//@Override
//public void c(){
// System.out.println("d출력");
//}
//default 메소드라서 오버라이드 하지않고 사용해도 된다.
}
인터페이스의 default 메소드
기존의 인터페이스는 추상메소드만 가질수 있었는데
JAVA 8이 등장하면서 interface에 대한 정의가 몇 가지 변경되었다.
default method와 static method를 정의하수 있도록 변경됨
default메소드
인터페이스가 default 라는 키워드로 선언되면 메소드를 구현할 수 있다.
이를 구현한 클래스에서는 default 메소드를 오버라이딩 할 수 있다.
인터페이스를 사용하는 클래스에서 꼭 구현해도 되지 않도록 하기위해서.
default 메소드에 구현된 내용을 그대로 사용할 수도 있고, 오버라이딩 할 수도 있다.
public interface Calculator {
public int plus(int i, int j); // 여기에 메소드를 구현하면 오류가 생긴다.
public int multiple(int i, int j); // 여기에 메소드를 구현하면 오류가 생긴다.
default int exec(int i, int j) { // default로 선언함으로 메소드를 구현할 수 있다.
return i + j;
}
}
Calculator인터페이스를 구현한 MyCal클래스
public class MyCal implements Calculator {
@Override
public int plus(int i, int j) {
return i + j;
}
@Override
public int multiple(int i, int j) {
return i * j;
}
}
MyCal클래스를 사용하기
public class MyCalTest {
public static void main(String[] args){
Calculator cal = new MyCal();
cal.plus(3, 4);
int i = cal.exec(5, 6); // default로 구현된 메소드도 사용된다.
System.out.println(i);
}
}
결과값
11
인터페이스가 변경이 되면, 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제가 있다.
이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현해 놓을 수 있도록 하였다.
static메소드
public interface Calculator {
public int plus(int i, int j);
public int multiple(int i, int j);
default int exec(int i, int j){
return i + j;
}
public static int exec2(int i, int j){ // static한 메소드 구현시 사용된다.
return i * j;
}
}
위의 MyCalTest 클래스의 main메소드에 Calculator.exec2(3, 4); 를 사용 가능하다.
인터페이스에서 정의한 static메소드는 반드시 인터페이스명.메소드 형식으로 호출해야한다.
car.exec2 이런식으로 만들면 호출이 불가능하다.
public class MyCalTest {
public static void main(String[] args){
Calculator cal = new MyCal();
int i = cal.exec(5, 10);
System.out.println(i);
Calculator.exec2(5, 10); // static메소드 호출
}
}
인터페이스에 static 메소드를 선언함으로써,
인터페이스를 이용하여 간단한 기능을 가지는 유틸리티성 인터페이스를 만들 수 있게 되었다.
내부클래스
클래스 안에 선언된 클래스
어느 위치에 선언하느냐에 따라서 4가지 형태가 있을 수 있다.
첫번째는 클래스 안에 인스턴스 변수, 즉 필드를 선언하는 위치에 선언되는 경우.
보통 중첩클래스 혹은 인스턴스 클래스라고 한다.
내부에 있는 Cal객체를 생성하기 위해서는, 밖에있는 InnerExam1의 객체를 만든 후에
InnerExam1.Cal cal = t.new Cal();과 같은 방법으로 Cal객체를 생성한 후 사용한다.
public class InnerExam1{
class Cal{
int value = 0;
public void plus(){
value++;
}
}
public static void main(String args[]){
InnerExam1 t = new InnerExam1();
InnerExam1.Cal cal = t.new Cal(); // 바깥쪽 클래스 타입.내부타입
cal.plus(); // 내부 클래스의 메소드 호출
System.out.println(cal.value); // 내부 클래스의 필드도 사용가능
}
}
결과값
1
두번째는 내부 클래스가 static으로 정의된 경우, 정적 중첩 클래스 또는 static 클래스라고 한다.
필드 선언할 때 스태틱한 필드로 선언한 것과 같다.
이 경우에는 InnerExam2객체를 생성할 필요없이 new InnerExam2.Cal() 로 객체를 생성할 수 있다.
public class InnerExam2{
static class Cal{
int value = 0;
public void plus(){
value++;
}
}
public static void main(String args[]){
InnerExam2.Cal cal = new InnerExam2.Cal();
cal.plus();
System.out.println(cal.value);
}
}
세번째로는 메소드 안에 클래스를 선언한 경우, 지역 중첩 클래스 또는 지역 클래스라고 한다.
메소드 안에서 해당 클래스를 이용할 수 있다.
public class InnerExam3{
public void exec(){
class Cal{
int value = 0;
public void plus(){
value++;
}
}
Cal cal = new Cal(); // 메소드 안에서만 클래스 사용가능하다.
cal.plus();
System.out.println(cal.value);
}
public static void main(String args[]){
InnerExam3 t = new InnerExam3();
t.exec(); // 내부적으로 Cal이라는 클래스가 정의되어 있는 부분이 실행된다.
}
}
결과값
1
메소드 안에서도 지역변수 처럼 클래스를 선언하여 사용할 수 있다.
네번째로는 익명클래스가 있다.
익명클래스
익명 중첩 클래스는 익명 클래스라고 보통 말하며, 내부 클래스이기도 하다.
추상클래스 Action
public abstract class Action{
public abstract void exec();
}
추상클래스 Action을 사용하기 위해서 상속받은 클래스 MyAction
public class MyAction extends Action{
public void exec(){
System.out.println("exec"); // 반드시 추상클래스의 메소드를 구현해야한다.
}
}
MyAction을 사용하는 클래스 ActionExam
public class ActionExam{
public static void main(String args[]) {
Action action = new MyAction(); // Action은 추상 클래스이기 때문에 객체가 생성되지 않는다.
// 생성은 MyAction이라는 자식 클래스가 생성되어야 한다.
action.exec(); // 이때 Action이 가진 메소드를 사용 가능하다.
}
}
익명클래스 만들기
MyAction을 사용하지 않고 Action을 상속받는 익명 클래스를 만들어서 사용하도록 수정해 보도록 하겠습니다.
public class ActionExam{
public static void main(String args[]) {
Action action = new Action() { // 추상 클래스이기 때문에 Action 자체가 생성되지 않는다.
public void exec() { // 익명으로 클래스가 만들어진다.
System.out.println("exec"); // 똑같이 수행하는 메소드를 만들 수 있다.
}
};
action.exec(); // 사용하는방법
}
}
결과값
exec
Action action = new Action()뒤에 {}가 나오는데 이때 해당 생성자 이름에 해당하는 클래스를 상속받은 이름없는 객체를 만든다.
괄호 안에는 메소드를 구현하거나 추가할 수 있다. 이렇게 생성된 이름없는 객체를 Action이라고하는 참조변수가 참조하도록 하였다.
그리고 exec 메소드를 호출하였다.
익명클래스를 만드는 이유는 Action을 상속받는 클래스를 굳이 만들어낼 필요가 없는 경우에 사용가능하다.
Action을 상속받는 클래스가 해당 클래스 안에서만 사용이되고 다른 클래스에서는 전혀 사용할 필요가 없는경우
'프로그래밍 공부 > JAVA' 카테고리의 다른 글
JAVA 중급 강의정리 Object클래스 ~ java.lang 패키지 (0) | 2021.08.10 |
---|---|
JAVA 입문 강의정리 예외 Exception, throws (0) | 2021.07.25 |
JAVA 입문 강의정리 상속 (0) | 2021.07.21 |
JAVA 입문 강의정리 (클래스~패키지) (0) | 2021.07.20 |
JAVA 입문 강의정리 (JAVA란? ~ for each구문) (0) | 2021.07.18 |