package access1;
public class AccessTest {
int data1 = 10;
public int data2 = 20;
private int data3 = 30;
protected int data4 = 40;
// Alt + shift + s > R : getter, setter 사용하기
public int getData3() {
return data3;
}
// 세터는 리턴 값을 반환하지 않고 아래와 같이 값을 수정한다.
public void setData3(int data3) {
this.data3 = data3;
}
}
abstract class 클래스명{
abstract 리턴타입 추상메소드명();
}
package zoo;
// animal은 추상 클래스이다.
public abstract class Animal {
String name;
String gender;
int age;
// final 메소드는 자식 클래스에서 재정의가 불가능하다.
final void intro() {
System.out.println("나는 동물입니다.");
}
// 추상 메소드를 만든다.
abstract void makeSomeNoise();
// 일반 메소드도 선언 가능하다.
void eat() {
System.out.println(name + "이(가) 냠냠 먹는중..");
}
}
package zoo;
public class Snake extends Animal{
// 추상 클래스를 상속 받으면 추상 클래스 내부의 추상 메소드를 반드시 재정의한다.
@Override
void makeSomeNoise() {
System.out.println("슬리데린");
}
}
package zoo;
// 인터페이스 선언, 마찬가지로 추상 메소드를 만들 수 있다.
public interface Mammal {
abstract void eungAe();
}
package zoo;
// cat은 animal를 상속 받으면서 mammal를 인터페이스로 받는다.
public class Cat extends Animal implements Mammal{
// final은 재정의가 안되는 것을 알 수 있다.
// @Override
// void intro() {
// System.out.println("나는 식물입니다.");
// }
@Override
void makeSomeNoise() {
System.out.println("음멩");
}
// 인터페이스의 추상메소드도 재정의가 필요하다.
@Override
public void eungAe() {
System.out.println("새끼를 한 네다섯마리 정도 낳는다.");
}
}
package zoo;
// 비어있는 인터페이스를 만들 수 있다.
public interface Bird {
}
package zoo;
// 비어 있는 인터페이스는 아래와 같이 animal의 상속과 추상 메소드만이 정의하고 있다.
public class Avialae extends Animal implements Bird{
@Override
void makeSomeNoise() {
System.out.println("시져시져");
}
}
package zoo;
public class Ground {
public static void main(String[] args) {
Animal [] arr= {
new Cat(),
new Snake(),
new Whale(),
new Avialae(),
new Kangaroo()
};
for (int i = 0; i < arr.length; i++) {
arr[i].makeSomeNoise();
}
// 인터페이스를 이용하여 Bird라는 다른 클래스와의 구분점으로 사용할 수있다.
for (int i = 0; i < arr.length; i++) {
if(arr[i] instanceof Bird) {
System.out.println(i + "번 방은 새가 있어ㅏ요");
}
}
}
}
interface A
package multi;
public interface A {
// 인터페이스는 추상메소드만 선언 가능하기 때문에 그냥 선언해도 추상 메소드, 상수로 선언된다.
//void f();
// 하지만 default를 사용하면 아래와 같이 선언이 가능하다.
default void f() {
System.out.println("A 인터페이스의 f()");
}
}
interface B
package multi;
public interface B {
// jdk8에 추가된 문법으로 메소드를 추상메소드가 아닌 아래처럼 메소드를 정의 할 수 있다.
default void f() {
System.out.println("B 인터페이스의 f()");
}
}
class C
package multi;
public class C {
public void f() {
System.out.println("C 클래스의 f()");
}
}
인터페이스A, B를 상속받은 class D
package multi;
public class D implements A, B{
// 같은 이름의 메소드를 받아오면 모호성으로 인하여 아래와 같이 재정의를 해야 한다.
@Override
public void f() {
System.out.println("D 클래스의 f()");
}
void doSomething() {
A.super.f();
B.super.f();
f();
}
}
인터페이스A, B를 상속받고 C를 상속받은 E
package multi;
public class E extends C implements A,B{
// C클래스와 A,B 인터페이스에도 f함수가 존재하며 어떤 함수를 사용할지 모르기 때문에
// 재정의를 통한 모호성을 해결해야 사용이 가능하다.
@Override
public void f() {
System.out.println("E 클래스의 f()");
}
void dosomthing() {
// A개체로 접근하여
A.super.f();
B.super.f();
// super는 상속받은 C클래스의 주소를 가지고 있다.
super.f();
f();
}
}
main method 사용 class
package multi;
public class MultiTest {
public static void main(String[] args) {
// D d = new D();
// d.doSomething();
E obj2 = new E();
// obj2.f();
obj2.dosomthing();
}
}
위 코드의 핵심은
1. 인터페이스는 다중상속이 가능하고
2. 기존 인터페이스는 추상 메소드와 상수만 가능했지만
3. default로 메소드 정의도 가능하다.
4. 인터페이스를 상속 받으면 무조건 재정의를 해야되고
5. 함수 이름이 동일해도 재정의를 하기 때문에 메소드의 모호성이 해결된다.
6. 기존 부모의 메소드를 사용하고 싶으면 메소드를 정의하면서 super객체로 접근한다.
7. ex. A인터페이스의 메소드 접근 A.super.f() 또는 C클래스의 메소드 접근 super.f()