Search
Duplicate

자바를 자바 09 (interface, inheritance, 인터페이스, 상속)

간단소개
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Java
Scrap
태그
9 more properties

Interface(나머지 부분)

Interface variable

변수들은 모두 자동으로 public static final variable 이 된다. 그렇기 때문에 이 변수들은 클래스의 실채와 상관없이 사용 가능하며 final은 값이 바뀌지 않기 때문에 상수처럼 사용할 수 있게 된 것이라고 생각해 볼 수 있다.
interface Motion{ int NORTH = 1; int EAST = 2; int SOUTH = 3; int WEST = 4; void move(int direction); int getX(); int getY(); } class TwoDMotion implements Motion { private int posX, posY; public TwoDMotion() { posX = 0; posY = 0; } // 여기와 같이 interface의 변수들이 상수처럼 사용되고 있다. public void move(int direction) { if(direction == NORTH) posY--; else if(direction == SOUTH) posY++; else if(direction == EAST) posX++; else if(direction == WEST) posX--; } public int getX() { return posX; } public int getY() { return posY; } }
Java
복사

Interface method

이제 interface의 함수는 abstract 함수라고 하였지만 자바의 버전이 8/9가 되면서 추가적인 다른 형태의 메소드가 나오게 되었다.
static method (java 8)
default method (java 8)
private method (java 9) (현재 우리는 java 14이다.)
static method 이 method는 내부에 구현이 되어 있는 것을 이야기 한다. 우리는 이번에 클래스 객체를 생성하는 메소드인 factory method 에 대해서 언급하고 갈 것이다.
interface IntSequence{ // 이러한 형태의 메소드를 factory method라고 부른다. static IntSequence digitsOf(int n){ return new DigitSequence(n); } boolean hasNext(); int next(); }
Java
복사
이것을 사용하기 위해서는
IntSequence digits = IntSequence.digitsOf(1729);
Java
복사
위와 같이 class method를 호출하여서 바로 사용할 수 있다.
Default method interface 내부에 method에 default 선언도 하고 구현도 해놓는다. 그래서 어떠한 클래스가 interface를 implement하게 되었을때 만약 subtype class가 interface의 default method를 선언하지 않았다면 default method의 기능을 그대로 사용하겠다는 extends로 클래스를 상속받은 것과 비슷한 형태의 결과물이 생기게 된다.목적 : 코드의 중복을 줄이기 위해 예를 들어서 기존의 클래스를 interface로 받는다고 하면 그때마다 새로 함수를 정의해주어야 한다. 그렇기에 상당히 귀찮은 상황이 샐길 수 밖에 없기 때문이다.
intercface IntSequence{ default boolean hasNext() {return true;} int next(); } //아래와 같이 클래스는 implements 하였지만 //hasNext를 새롭게 정의하지 않았다. class SquareSequence implements IntSequence{ private int i; public int next(){ i++; return i * i; } }
Java
복사
하지만 한가지 문제점이 생길 수 있다. 만약에 implement를 두 클래스를 받았을 때 똑같은 이름의 메소드를 각 클래스가 모두 가지고 있다면 이때는 문제가 생길 수 있다.
interface Person { String getName(); default int getId() { return 0; } // Error: duplicate // default methods with the same type of parameters } interface Identified { default int getId() { return 1; } // Error: duplicate // default methods with the same type of parameters } class Employee implements Person, Identified { private String name; public Employee(String name) { this.name = name; } public String getName() { return this.name; } } public class Lecture { public static void main(String[] args) { Employee m = new Employee("Peter"); //바로 이부분에서 문제가 생길 수 있다. System.out.println(m.getId()); } }
Java
복사
해결책
1.
두 클래스 중 하나가 default가 아니라면 문제가 생기지 않을 것이다.
2.
혹은 subtype class에서 따로 함수를 정의한다면 문제가 생기지 않을 것이다.
3.
두 클래스 중 하나의 default method의 매개변수 혹은 반환값이 다른 경우도 문제가 생기지 않을 것이다.
private methods private method는 interface 내부에서만 호출 될 수 있는 메소드를 이야기 한다. 아래와 같이 method4는 private로 선언이 되어 있다. 또한 여기에서는 기존 static method가 오로지 static method 내부에서만 호출 될 수 있었으나 static method가 default method에서도 호출된 모습을 볼 수 있다. 즉 기존 static과의 차이점은 존재하지 않으나 private을 선언함으로써 외부에서 static method에 접근하는 것을 막은 것이다.
interface CustomInterface { public abstract void method1(); public default void method2() { // private method를 당연하듯이 사용한다. method4(); // 또한 여기와 같이 static method로 // 정의된 method5가 default method에서 // 호출 된 것을 확인할 수 있다. method5(); System.out.println("default method"); } public static void method3() { method5(); //static method inside other static method System.out.println("static method"); } //method4 private 선언 : 함수의 구현도 해주었다. private void method4() { System.out.println("private method"); } //private static method가 선언되어 있다. private static void method5() { System.out.println("private static method"); } }
Java
복사
하지만 method4는 interface를 상속받은 다른 클래스에서는 사용이 불가능하다.
public class Lecture implements CustomInterface { public void method1() { System.out.println("abstract method"); } //현재 여기에서는 method4의 호출을 하지 않았으나 사용이 불가능하다. public static void main(String[] args){ CustomInterface instance = new Lecture(); instance.method1(); instance.method2(); CustomInterface.method3(); } }
Java
복사

이때 몇가지 규칙이 있는데(시험)

1.
private method는 abstract일 수 없다. => 내부를 반드시 구현해 주어야 한다.
2.
private method는 정의된 interface 내부에서만 사용할 수 있다.
3.
private static method는 다른 static 혹은 non-static method에서 호출 할 수 있다.(기존 static과 다르지 않으나 외부에서 static method에 접근하는 것을 막은 것이다.)
4.
private static method 내부에는 다른 non-static method가 들어올 수 없다.(private static 을 자유롭게 쓸 수 있어! 하지만 들어오지는 마 - 기존과 달라진 것은 없다.)
<br><br><br>

Inheritance(상속)

두 클래스 간의 관계로 super class 과 sub class로 관계가 나뉘게 된다.

Extending a class

1.
코드의 중복성을 줄인다.
class Employee{ private String name; private int salary; public Employee(){ this.name = "NoName"; this.salary = 0; } public String getName() {return this.name;} public void setName(String name) {this.name = name;} public int getSalary() {return this.salary;} public void setSalary(int salary) {this.salary = salary;} }
Java
복사
사용법 extends를 사용하여서 클래스 명을 넣으면 된다.
class Manager extends Employee{ private int bonus; public void setBonus(int bonus) {this.bonus = bonus;} }
Java
복사
이렇게 정의하면 Manager class는 Employee class의 public으로 선언된 함수와 변수를 사용함과 동시에 새로운 함수와 변수를 정의할 수 있다.

Super class vs Sub class

Manager 가 subclass 이고 Employee가 superclass 이다.
public static void main(String[] args){ Manager m = new Manager(); System.out.println(m.getName() + " " + m.getSalary()); }
Java
복사

Method overriding

이제 클래스를 상속받으면 같은 이름의 새로운 함수를 정의하고 싶지 않겠는가???? 그래서 나온 개념이 오버라이딩이다. 오버라이딩은 subclass의 함수를 superclass에서 새롭게 정의하여서 사용하는 것을 이야기 한다.
부모클래스의 기능 사용하기
그러면서 동시에 superclass의 함수를 사용하고 싶다면 super 키워드를 사용하여서 superclass의 함수를 호출 할 수 있다.
class Manager extends Employee{ private int bonus; public void setBonus(int bonus) {this.bonus = bonus;} //아래는 함수의 재정의 + superclass 함수의 사용을 보여준다. public int getSalary(){ return super.getSalary()+bonus; } }
Java
복사
여기에서 access modifier에 대한 개념을 다시금 생각하여 보자 public>protected>없음>private 순으로 접근이 가능하다고 우리는 알고 있다. 여기에서 상속을 받았을 때 사용할 수 있는 범위는 protected까지이다.
class Manager extends Employee { private int bonus; public void setBonus(int bonus) { this.bonus = bonus; } public int getSalary() { return this.salary + bonus; // Error: salary is private in class Employee. } }
Java
복사
그래서 위와 같은 superclass의 salary를 사용하는 거은 불가능하다고 에러표시가 뜨게 된다.
또한 상속받은 클래스는 반드시 상위클래스의 생성자도 함께 호출하여 주어야 한다.
기본 기본은 당연하게도 그냥 같은 이름의 함수를 그대로 작성하는 것이다.
class Employee { private String name; protected int salary; public Employee() { this.name = "NoName"; this.salary = 100000; } public String getName() {return this.name;} public void setName(String name) {this.name = name;} public int getSalary() {return this.salary;} public void setSalary(int salary) {this.salary = salary;} } class Manager extends Employee{ private int bonus = 50000; public void setBonus(int bonus) {this.bonus = bonus;} public int getSalary() { return super.getSalary()+bonus; } }
Java
복사
매개변수가 달라 오버라이딩으로 인정 못받음
이제 method overriding 에 대해서 생각하여 보자
class Employee{ private String name; protected Employee supervisor; public Employee(){ this.name = "NoName"; } public boolean worksFor(Employee supervisor){ System.out.println("Employee.worksFor"); return (this.supervisor == supervisor) } } class Manager extends Employee{ public boolean worksFor(Manager supervisor){ System.out.println("Manager.worksFor"); return (this.supervisor == supervisor) } }
Java
복사
위의 경우는 오버라이딩이 되었다고 말할 수 없다 왜냐하면 매개변수가 서로 다르기 때문에 Manager에 Employee 함수가 오버라이딩 된게 아닌 단순히 오버로딩 즉 다른 함수가 정의된 것 뿐이라는 결론이 생기게 된다.
그래서 이러한 문제점을 해결하기 위해서
class Manager extends Employee{ @Override public boolean worksFor(Manager supervisor){ System.out.println("Manager.worksFor"); return (this.supervisor == supervisor) } }
Java
복사
@Override 키워드를 함수 위에 작성하여 준다. 이러면 에러가 생긴다. 이를 통해서 우리는 이게 문제가 있는 코드라는 것을 알게 된다.
그렇기 때문에 에러를 방지하기 위해서 가급적이면 @Override 라는 키워드는 써주는 것이 에러를 방지할 수 있는 가장 좋은 방법이다.
클래스 반환형은 오버라이딩에 영향을 미치나?
정답은 YES 반환형이 다르면 오버라이딩으로 인정받는다. 단 서브타입 클래스인것만 인정 받는다. 그게 아닌 평범한 자료형이면 불가능하다. 왜냐하면 이건 함수가 끝날때 영향을 미치니 처음에 들어갈때는 크게 중요하게 여기지 않는다. 하지만 그렇다고 하더라도 가급적 @Override를 작성하여 주자
class Employee { private String name; protected Employee supervisor; public Employee() { this.name = "NoName"; } public Employee getSupervisor() { System.out.println("Employee"); return supervisor; } } class Manager extends Employee { @Override // this is ok! public Manager getSupervisor() { System.out.println("Manager"); return (Manager)supervisor; } }
Java
복사
그러면 access modifier은 함수 오버라이딩으로 인정 받는가?
정답은 YES 정확하게는 subclass의 제한 수준이 더 높으면 문제가 생긴다. 하지만 그 역이라면 인정받는다. 단, private는 안된다.

오버로딩 인정범위

access modifier 인정X
반환형 인정X
매개변수 인정O

@Override 인정범위

access modifier 인정O (단 subclass가 superclass보다 제한 수준이 낮거나 같아야 함
Search
Column 1
Column 2
일반 자료형 반환형 인정X
클래스 자료형 반환형 인정O
클래스 매개변수 인정X