티스토리 뷰

 

추상 클래스 인터페이스
   
객체 생성 불가능
자식 클래스에서 객체 생성
객체 생성 불가능
클래스로 구현해 객체 생성
부모 클래스가 추상 클래스라면
자식 클래스에서 미완성 메소드 반드시 구현
 
   

실제로는 클래스를 만들다, 공통 특성을 가지게 될 때 부모 클래스를 만듦.

 

1. abstract

여러 사람이 협업할 때, 메소드 매개변수 입력 종류나 순서 등의 공통적인 틀을 갖추기 위해 사용.

 

※추상클래스

객체는 생성하지 않고 공통 특성만 모아두는 곳  ex) 자료형, 메소드 등등

-일반 클래스 : 객체 생성 가능

-추상 클래스 : 객체 생성 불가능

                   abstract class거나 abstract method가 하나라도 포함된 클래스

 

(1) abstract 메소드

미완성 메소드로 기능없이 이름만 정의된 것. 구현 x(중괄호 없는 메소드)

구현 여부 : 중괄호({ })가 없으면 구현 x, 있으면 구현 o

리턴 타입 앞에 입력.

abstract void cry();
//구현 안 된 '추상 메소드'

void cry(){
    //구현된 '메소드'. 실행할 내용이 없을 뿐.
}

 

(2) abstract 클래스

내부에 추상 메소드를 하나 이상 포함하고 있거나 클래스 자체가 추상 클래스인 것.

추상 클래스는 객체 생성 불가하므로 서브 클래스(자식 클래스)에서 객체 생성한다.

abstract class A{
    abstract void abc();  //추상 메소드
    void bcd(){...}  //일반 메소드
}

└클래스 내부에 abstract 메소드가 하나라도 있으면 abstract class여야 함.

부모 클래스가 추상 클래스라면 자식클래스에서 미완성 메소드를 무조건 구현해줘야 한다.

 

(3) 추상 클래스 구현

-오버라이딩 : 부모 클래스 메소드를 자식 클래스에서 재정의(수정, 추가 등등)

-구현(implements) : 부모 클래스의 미완성 메소드를 자식 클래스에서 재정의

추상 클래스의 추상 메소드를 상속받은 자식 클래스에서 반드시 재정의해줘야 함. 해줄 때까지 오류

package aa;
public abstract class Animal{
    abstract void cry(); // 추상 메소드 cry()
    void func(){
        System.out.println("구현 메소드");
    }
}//추상 클래스

class Dog extends Animal{
    //빨간 줄 쳐진 Dog에 커서 갖다대면 Add ~ 누르면 메소드 자동완성해줌.
    @Override
    void cry(){
        System.out.println("멍멍");
    }
}

class Cat extends Animal{
    @Override
    void cry(){
        System.out.println("냐옹");
    }
}

└abstract Animal의 추상 메소드 cry()를 자식 클래스인 Dog, Cat에서 메소드 구현했음. 구현하지 않으면 구현할 때까지 오류.

 

(4) 객체 생성하는 법

추상 클래스 자체로는 객체 생성 불가

package ff;
public abstract calss Animal{
    abstract void cry(); //추상 메서드
}

//출력하는 메인 함수
public class AnimalTest{
    public static main(String[] args){
        Animal animal = new Animal();  //객체 생성 불가
        //Animal class가 abstract class라서
    }
}

 

-아래의 추상클래스를 바탕으로 객체 생성하는 방법 2개 설명.

더보기
package aa;
public abstract class Animal{
    abstract void cry(); // 추상 메소드 cry()
    void func(){
        System.out.println("구현 메소드");
    }
}//추상 클래스

class Dog extends Animal{
    //빨간 줄 쳐진 Dog에 커서 갖다대면 Add ~ 누르면 메소드 자동완성해줌.
    @Override
    void cry(){
        System.out.println("멍멍");
    }
}

class Cat extends Animal{
    @Override
    void cry(){
        System.out.println("냐옹");
    }
}

(4-1) 상속받은 자식 클래스에서 객체 생성

객체를 많이 만들 때 유용. 정의해놓고 필요할 때마다 불러쓸 수 있어서.

상속 받은 자식 클래스 이름을 사용해 객체 만든다.

package aa;
public class AnimalTest {
    public static main (String[] args){
        Animal a = new Dog();  //Animal의 자식클래스 Dog에서 객체 생성
        Animal a = new Cat();  //Animal의 자식클래스 Cat에서 객체 생성
        
        a.cry();  // 멍멍
        a.func(); // 구현 메소드
        b.cry();  // 냐옹
        b.func();  // 구현 메소드
    }
}

 

(4-2) 익명이너클래스

일회용. 잠깐 쓰고 말 거라면 익명이너클래스 이용한다.

추상 클래스 이름을 사용해 객체를 만든다.

package aa;
public class AnimalTest {
    public static void main (String[] args){
        Animal c = new Animal(){  //추상클래스 - 익명이너클래스
            @Override
            void cry(){
                System.out.println("왈왈");
            }
        };
        
        Animal d = new Animal(){  //추상클래스 - 익명이너클래스
            @Override
            void cry(){
                System.out.println("컹컹");
            }
        };
        c.cry();  // 월월
        d.cry();  // 컹컹
    }
}

└익명이너클래스의 중괄호 끝에 세미콜론(;) 붙여줄 것!

 

-자식 클래스에서 객체 생성 vs 익명이너클래스 비교

└자식 클래스로 객체 생성 : 객체를 많이 만들 때 유용. 정의해놓고 필요할 때마다 호출해서 사용할 수 있으므로.

└익명이너클래스 : 일회용. 잠깐 쓰고 말 때.

package aa;
public class AnimalTest02{
    public static void main(String[] args){
        //자식클래스에서 객체 생성
        Animal dog = new Dog();
        Animal cat = new Cat();
        
        //익명이너클래스 이용해 객체 생성
        //└사용하려면 구현부터 해줘야 한다.
        Animal c = new Animal(){
            @Override
            void cry(){
                System.out.println("짹짹");
            }
        };
    }//main
}

 


언제, 왜 쓰는가를 이해할 것!

2. 인터페이스(interface)

동일한 목적 하에서 동일한 기능을 수행하게끔 강제하는 것.

가이드라인(틀)을 주는 것. 어떤 자료형, 어떤 순서, 어떤 리턴 타입 등을 쓸 것인지 틀을 미리 정해두는 것.

자체적으로 객체 생성 불가.

상수와 추상메소드로만 구성  -(자바 1.8)→ default method(구현된 메소드), static method

 

어떤 객체(클래스)가 있고, 그 객체(클래스)가 특정한 인터페이스를 사용한다면(구현하고 있다면), 그 객체(클래스)는 반드시 인터페이스의 메소드를 구현(implements)해야 한다.

interface I{
	public void abc();
}

class A implements I{
	public void abc(){
    	//상속받고 있는 interface I의 구현되지 않은 메소드를 구현해야 함.
    }
}

 

(1) 인터페이스 정의(또는 구현)

일반 필드 못 씀. 그냥 적어도 상수(public static final)추상 메소드(public abstract)가 자동으로 붙음.

package bb;
public interface bb {
    //field
    public static final int a = 3;

    //추상 메소드
    public abstract void abs();
    
    //디폴트 메소드
    default void bcd(){
        //구현 안 해도 됨.
    }
    
    //정적 메소드
    static void cde(){
        System.out.println("cde");
    }
}

 

(1-1) 필드(field)

인터페이스엔 일반 필드 못 씀. 그냥 선언해도 public static final이 자동 붙으며 생략된 것으로 간주함.

interface A{
    int a = 3;
    //public static final int a = 3;
}

객체 생성 불가. static이라 객체 생성없이 접근 가능. 상수라 값 변경 불가능.

package bb;
public class InterfaceTest{
    public static void main(String[] args){
        //객체 생성 불가능
//      A a = new A();
//      B b = new B();

        //static이라 A 이름으로 바로 접근 가능
        System.out.println(A.a);
        
        //final이라 값 변경 불가능
//      a.a = 4;
    }
}

 

(1-2) 추상 메소드(abstract method)

 

(1-3) 디폴트 메소드(default method)

인터페이스를 상속하는 클래스가 존재. 이후 인터페이스에 메소드를 추가하면 인터페이스를 상속받는 클래스에서 전부 구현해줘야 함. 해줄 때까지 오류뜸. 그런데 추가한 메소드를 '디폴트 메소드'라고 해주면 괜찮음. 오류 안 뜸.

디폴트 메소드는 다른 클래스에서 공통적으로 사용하는 것. 수정없이. 즉, 상속받는 클래스에서 구현할 필요 없는 메소드

package ee;
public interface A {
    void abc();
    default void bcd(){ //구현 안 해도 됨.
        System.out.println("method bcd");
    }
}

class B implement A {
    @Override
    public void abc() {
        System.out.println("B class의 abc");
    }
}

class C implement A {
    @Override
    public void abc(){
        System.out.println("C class의 abc");
    }
}

-메인 함수에서 객체 생성 및 출력

package ee;
public class DefaultTest {
    public static void main(String[] args) {
        //인터페이스 A를 가지고 B, C 클래스의 객체 만들 수 있음.
        A b = new B();
        A c = new C();
        
        b.abc();  //B class의 abc
        b.bcd();  //method bcd
        c.abc();  //C class의 abc
        c.bcd();  //method bcd
    }
}

 

*디폴트 메소드(default method)는 구현할 필요 없음. 근데 굳이 구현해보겠다.

package ee;
public interface A {
    void abc();
    default void bcd(){ //구현 안 해도 됨.
        System.out.println("method bcd");
    }
}

class B implement A {
    @Override
    public void abc() {
        System.out.println("B class의 abc");
    }
    //default method 굳이 구현
    public void bcd(){
        A.super.bcd();  //부모의 bcd 출력
                        //interface는 부모가 여러 개일 수 있으므로 지정해줘야 한다.
        System.out.println("B 클래스에서 재정의한 bcd");
    }
}

class C implement A {
    @Override
    public void abc(){
        System.out.println("C class의 abc");
    }
    //default method 굳이 구현
    public void bcd(){
        A.super.bcd();
        System.out.println("C 클래스에서 재정의한 bcd");
    }
       
    
}
package ee;
public class DefaultTest {
    public static void main(String[] args) {
        //인터페이스 A를 가지고 B, C 클래스의 객체 만들 수 있음.
        A b = new B();
        A c = new C();
        
        b.abc();  //B class의 abc
        b.bcd();  //method bcd / B 클래스에서 재정의한 bcd
        c.abc();  //C class의 abc
        c.bcd();  //method bcd  / C 클래스에서 재정의한 bcd
    }
}

 

(1-4) 정적 메소드(static method)

완성형으로 만들 수 있음.

package ee;
public interface A {
    static void cde(){
        System.out.println("cde");
    }
}

A라는 인터페이스 소속 메소드. 객체 생성없이 바로 접근할 수 있음.

package ee;
public class DefaultTest {
    public static void main(String[] args) {
        A.cde(); //cde
    }

 

(2) 인터페이스 상속

인터페이스는 구현 불가 → 클래스로 상속받아 구현

상속 시 implements 키워드 사용. 다중상속 가능(*일반/추상 클래스는 다중상속 불가)

//가능
클래스 extends 클래스 {    }
인터페이스 extends 인터페이스 {    }
클래스 implements 인터페이스 {    }

//불가능
인터페이스 implements 클래스 {    }

└종류가 같은 것일 때는 extends 쓰고 다를 때 implement 쓰나?

package bb;
public interface A {
    public static final int a = 3;
    public abstract void abc(); //추상 메소드
}

interface B{
    int b = 5;    //생략됐지만 public static final 붙어있음
    void bcd();
}

//상속 type_1
class C_class implement A {
    //A가 추상 메소드를 포함하고 있기 때문에 메소드를 구현할 때까지 오류.
    @Override
    public void abc(){
        System.out.println("C_class");
    }
}
//상속 type_2 : 다중상속 가능
class A_B_class implement A, B {
    //A, B가 추상 메소드를 포함하고 있기 때문에 메소드를 구현할 때까지 오류.
    @Override
    public void abc(){  //interface A 메소드 구현
        System.out.println("A Interface method");
    }
    
    @Override
    public void abc(){  //interface B 메소드 구현 
        System.out.println("B Interface method");
    }
}

//상속 type_3 : 클래스 C 상속받고 A, B를 구현
class C {
    void func(){
        System.out.println("C의 메소드");
    }
}

class D extends C implements A, B {
    @Override
    public void abc(){  }
    
    @Override
    public void bcd(){  }
    
    @Override
    void func(){
        super.func();
        System.out.println("D의 메소드");
    }
}

-메인 함수에서 객체 생성 및 출력

package bb;
public class InterfaceTest{
    public static void main(String[] args){
    //interface 객체 생성 불가
    //A a = new A();
    
    //static이라 객체 생성없이 접근 가능
    System.out.println(A.a);  //3
    
    A c = new C_class();
    c.abc();  //C_class
    
    B ab = new A_B_class();
    ab.abc();  //B Interface method
    ab.bcd();  //A Interface method
    
    D d = new D();
    d.abc();  //
    d.bcd();  //
    d.func(); //C의 메소드 / D의 메소드
    }
}

└d.abc();, d.bcd();은 구현하지 않아서 출력될 것이 없음.

 

_예제) 상속

interface A를 상속한 interface B를 구현한 클래스 생성. 이때 B의 메소드뿐만 아니라 B가 상속받은 A의 메소드도 구현해줘야 함.

package bb;
public interface A {
    public static final int a = 3;
    public abstract void abc(); //추상 메소드
}

interface B extends A {
    int b = 3;
    void bcd();  //추상 메소드
}

//B를 구현한 클래스 생성
class BImple implements B {
//B의 메소드뿐만 아니라 B가 상속받은 A 메소드까지 구현.
    @Override
    public void abc(){
        System.out.println("method abc");
    }
    
    @Override
    public void bcd(){
        System.out.println("method bcd");
    }
}

//A, B를 상속받은 ABExt를 구현한 클래스 ABExtImple
interface ABExt extends A, B {
    void cde();
}

class ABExtImple implements ABExt {
    @Override  
    public void abc(){ //interface A
        System.out.println("abc method");
    }
    
    @Override
    public void bcd(){ //interface B
        System.out.println("bcd method");
    }
    
    @Override
    public void cde(){ //interface ABExt
        System.out.println("cde method");
    }
}

 

(3) 인터페이스 객체 생성

자체 객체 생성 불가.

(3-1) 인터페이스를 일반 클래스로 상속해 클래스에서 객체 생성

(위에서 했던 예시들이 인터페이스를 일반 클래스로 상속해 클래스에서 객체 생성한 것)

 

(3-2) 익명이너클래스 사용

package cc;
public interface Computer {
    void display(String name);  //추상 메소드
    void typing(int ssd, String cpu, int memory);  //추상 메소드
}

class Desktop implements Computer {  //구현
    @Override
    public void display(){
        System.out.println("My "+name+" 컴퓨터입니다.");
    }
    
    @Override
    public void typing(int ssd, String cpu, int memory){
        System.out.println("모니터 크기 : 22인치");
        System.out.println("SSD : "+ssd+", CPU : "+cpu+", 메모리 :"+memory+"입니다.");
    }
}

class Notbook implements Computer {  //구현
    @Override
    public void display(){
        System.out.println("My "+name+" 노트북입니다.");
    }
    
    @Override
    public void typing(int ssd, String cpu, int memory){
        System.out.println("무게 : 300mg");
        System.out.println("SSD : "+ssd+", CPU : "+cpu+", 메모리 :"+memory+"입니다.");
    }
}

└모니터 크기나 노트북 무게 출력문장은 구색맞추려고 넣은 것...

package cc;
public class ComputerTest {
    public static void main(String[] args){
        Computer[] computers = new Computer[3];
        computers[0] = new Desktop();
        computers[1] = new Desktop();
        computers[2] = new Notbook();  //배열로 객체 생성
        
        computers[0].display("samsung");
        computers[0].typing(512, "i5", 16);  System.out.println();
        
        computers[1].display("LG");
        computers[1].typing(512, "i7", 16);  System.out.println();
        
        computers[2].display("Apple");
        computers[2].typing(512, "IOS", 16);
    }
}
My samsung 컴퓨터입니다.
모니터 크기 : 22인치
SSD : 512, CPU : i5, 메모리 :16입니다.

My LG 컴퓨터입니다.
모니터 크기 : 22인치
SSD : 512, CPU : i7, 메모리 :16입니다.

My Apple 노트북입니다.
무게 : 300mg
SSD : 512, CPU : IOS, 메모리 :16입니다.

 

(↔) 추상 클래스 사용

package dd;
public abstract class Computer {
    int ssd;
    String cpu;
    int memory;
    String name;
    
    void display(){ //method - 추상클래스에 구현된 메소드
        System.out.println("My "+name+" 입니다.");
    }
    
    public abstract void typing();  //추상메소드
}

class Desktop extends Computer {
    int size;
    
    //생성자
    public Desktop(int ssd, String cpu, int memory, String name, int size){
        this.ssd = ssd;
        this.cpu = cpu;
        this.memory = memory;
        this.name = name;
        this.size = size;
    }
    
    @Override
    public void typing(){
        System.out.println("Monitor size : "+size);
        System.out.println("SSD : "+ssd+", CPU : "+cpu+", MEMORY : "+memory+"입니다.");
    }
}

-main 함수에서 객체 생성 및 출력

package dd;
public class ComputerTest{
    public static void main(String[] args) {
//      Computer computer = new Computer(); //abstract class라 객체 생성 불가
        Computer computer = new Desktop(512, "i7", 16, "DeskTop", 25);
        computer.display();
        computer.typing();
}
My DeskTop 입니다.
Monitor size : 25
SSD : 512, CPU : i7, MEMORY : 16입니다.

 

인터페이스 사용? 추상 클래스 사용? 둘 중 어느 것 사용?

인터페이스는 함수를 모아두는 역할.

 

(4) 인터페이스 필요성

일을 할 때, 틀을 만들어 두는 것.

interface A {
    public void abc();
}

interface B {
    public void bcd();
}

-각기 다른 사람에게 클래스를 만들어 interface 구현하도록 지시

class C implements A {
    public void abc(){...}
}

class D implement B {
    public void bcd(){...}
}

-사용 : 객체 생성 및 출력

A a1 = new C();
a1.abc();

B b1 = new D();
b1.bcd();

 

'수업 > └Java' 카테고리의 다른 글

[실습문제6_1]Person, Customer, Test  (0) 2022.02.04
[CH10]이너클래스(innner class)  (0) 2022.02.04
[Ch08]자바 제어자 : final  (0) 2022.02.02
[00]Wrapper class  (0) 2022.02.02
[CH7]상속과 다형성  (0) 2022.02.02
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함