CodeGym /Java Blog /무작위의 /추상 클래스와 인터페이스의 차이점
John Squirrels
레벨 41
San Francisco

추상 클래스와 인터페이스의 차이점

무작위의 그룹에 게시되었습니다
안녕! 이 단원에서는 추상 클래스가 인터페이스와 어떻게 다른지 설명하고 일반적인 추상 클래스에 대한 몇 가지 예를 고려합니다. 추상 클래스와 인터페이스의 차이점 - 1이 주제는 매우 중요하기 때문에 추상 클래스와 인터페이스의 차이점에 대해 별도의 강의를 할애했습니다. 향후 인터뷰의 90%에서 이러한 개념의 차이점에 대해 질문을 받게 될 것입니다. 즉, 읽고 있는 내용을 파악해야 합니다. 그리고 무언가를 완전히 이해하지 못하는 경우 추가 소스를 읽으십시오. 그래서 우리는 추상 클래스가 무엇인지, 인터페이스가 무엇인지 압니다. 이제 차이점을 살펴보겠습니다.
  1. 인터페이스는 동작만 설명합니다. 상태가 없습니다. 그러나 추상 클래스는 상태를 포함합니다. 둘 다 설명합니다.

    예를 들어 Bird추상 클래스와 CanFly인터페이스를 가져옵니다.

    
    public abstract class Bird {
       private String species;
       private int age;
    
       public abstract void fly();
    
       public String getSpecies() {
           return species;
       }
    
       public void setSpecies(String species) {
           this.species = species;
       }
    
       public int getAge() {
           return age;
       }
    
       public void setAge(int age) {
           this.age = age;
       }
    }
    

    MockingJay새 클래스를 만들고 상속하도록 합시다 Bird.

    
    public class MockingJay extends Bird {
    
       @Override
       public void fly() {
           System.out.println("Fly, bird!");
       }
    
       public static void main(String[] args) {
    
           MockingJay someBird = new MockingJay();
           someBird.setAge(19);
           System.out.println(someBird.getAge());
       }
    }
    

    보시다시피 추상 클래스의 상태(그것 speciesage변수)에 쉽게 접근할 수 있습니다.

    그러나 인터페이스로 동일한 작업을 수행하려고 하면 상황이 달라집니다. 변수를 추가하려고 시도할 수 있습니다.

    
    public interface CanFly {
    
       String species = new String();
       int age = 10;
    
       public void fly();
    }
    
    public interface CanFly {
    
       private String species = new String(); // Error
       private int age = 10; // Another error
    
       public void fly();
    }
    

    인터페이스 내부에 개인 변수를 선언할 수도 없습니다 . 왜? 사용자로부터 구현을 숨기기 위해 private 한정자가 만들어졌기 때문 입니다. 그리고 인터페이스에는 내부에 구현이 없습니다. 숨길 것이 없습니다.

    인터페이스는 동작만 설명합니다. 따라서 인터페이스 내부에 getter 및 setter를 구현할 수 없습니다. 이것이 인터페이스의 특성입니다. 인터페이스는 상태가 아니라 동작과 함께 작업하는 데 필요합니다.

    Java 8에는 구현이 있는 인터페이스에 대한 기본 메서드가 도입되었습니다. 당신은 이미 그들에 대해 알고 있으므로 우리는 반복하지 않을 것입니다.

  2. 추상 클래스는 매우 밀접하게 관련된 클래스를 연결하고 통합합니다. 동시에 단일 인터페이스는 전혀 공통점이 없는 클래스에 의해 구현될 수 있습니다.

    새의 예로 돌아가 보겠습니다.

    추상 클래스 Bird는 해당 클래스를 기반으로 새를 생성하는 데 필요합니다. 새만 있고 다른 것은 없습니다! 물론 다양한 종류의 새들이 있을 것입니다.

    추상 클래스와 인터페이스의 차이점 - 2

    인터페이스를 사용하면 CanFly모든 사람이 자신의 방식으로 작업을 수행할 수 있습니다. 이름과 관련된 동작(비행)만 설명합니다. 관련 없는 많은 것들이 '날 수 있다'.

    추상 클래스와 인터페이스의 차이점 - 3

    이 4개의 엔터티는 서로 관련이 없습니다. 그들은 모두 살아 있지도 않습니다. 그러나 그들은 모두 CanFly.

    추상 클래스를 사용하여 설명할 수 없습니다. 동일한 상태 또는 동일한 필드를 공유하지 않습니다. 항공기를 정의하려면 모델, 생산 연도 및 최대 승객 수에 대한 필드가 필요할 것입니다. Carlson의 경우 오늘 먹은 모든 과자를 위한 필드와 남동생과 함께 할 게임 목록이 필요합니다. 모기의 경우, ...어... 나도 모르겠어... 아마도 '성가심 수준'? :)

    요점은 그것들을 설명하기 위해 추상 클래스를 사용할 수 없다는 것입니다. 그들은 너무 다릅니다. 그러나 그들은 공유된 행동을 가지고 있습니다. 그들은 날 수 있습니다. 인터페이스는 날고, 수영하고, 점프하거나, 다른 행동을 보일 수 있는 세상의 모든 것을 설명하는 데 적합합니다.

  3. 클래스는 원하는 만큼 많은 인터페이스를 구현할 수 있지만 하나의 클래스만 상속할 수 있습니다.

    우리는 이미 이것을 두 번 이상 언급했습니다. Java는 클래스의 다중 상속이 없지만 인터페이스의 다중 상속을 지원합니다. 이 점은 이전 항목에서 부분적으로 이어집니다. 인터페이스는 종종 공통점이 없는 많은 다른 클래스를 연결하는 반면 추상 클래스는 매우 밀접하게 관련된 클래스 그룹에 대해 생성됩니다. 따라서 이러한 클래스를 하나만 상속할 수 있다는 것이 이치에 맞습니다. 추상 클래스는 'is-a' 관계를 설명합니다.

표준 인터페이스: InputStream 및 OutputStream

우리는 이미 입력 및 출력 스트림을 담당하는 다양한 클래스를 살펴보았습니다. 그리고 InputStream. OutputStream_ 일반적으로 이들은 전혀 인터페이스가 아니라 완전히 순수한 추상 클래스입니다. 이제 그것이 무엇을 의미하는지 알았으므로 작업하기가 훨씬 쉬울 것입니다. :) InputStream는 바이트 입력을 담당하는 추상 클래스입니다. Java에는 InputStream. 각각은 서로 다른 소스에서 데이터를 수신하도록 설계되었습니다. 부모이기 때문에 InputStream데이터 스트림 작업을 쉽게 하는 여러 메서드를 제공합니다. 의 각 자손에는 InputStream다음 메서드가 있습니다.
  • int available()읽을 수 있는 바이트 수를 반환합니다.
  • close()입력 스트림을 닫습니다.
  • int read()스트림에서 사용 가능한 다음 바이트의 정수 표현을 반환합니다. 스트림의 끝에 도달하면 -1이 반환됩니다.
  • int read(byte[] buffer)바이트를 버퍼로 읽으려고 시도하고 읽은 바이트 수를 반환합니다. 파일 끝에 도달하면 -1을 반환합니다.
  • int read(byte[] buffer, int byteOffset, int byteCount)바이트 블록의 일부를 씁니다. 바이트 배열이 완전히 채워지지 않았을 때 사용됩니다. 파일 끝에 도달하면 -1을 반환합니다.
  • long skip(long byteCount)입력 스트림에서 byteCount 바이트를 건너뛰고 무시된 바이트 수를 반환합니다.
전체 방법 목록을 공부하는 것이 좋습니다 . 실제로 10개 이상의 하위 클래스가 있습니다. 예를 들어 다음은 몇 가지입니다.
  1. FileInputStream: 가장 일반적인 유형의 InputStream. 파일에서 정보를 읽는 데 사용됩니다.
  2. StringBufferInputStream: 의 또 다른 유용한 유형입니다 InputStream. 문자열을 InputStream;
  3. BufferedInputStream: 버퍼링된 입력 스트림입니다. 성능을 향상시키기 위해 가장 자주 사용됩니다.
우리가 가서 BufferedReader그것을 사용할 필요가 없다고 말했던 때를 기억하십니까? 우리가 쓸 때:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
...사용할 필요가 없습니다 BufferedReader. An이 InputStreamReader작업을 수행할 수 있습니다. 그러나 BufferedReader성능이 향상되고 개별 문자가 아닌 전체 데이터 행을 읽을 수도 있습니다. 에도 동일하게 적용됩니다 BufferedInputStream! 이 클래스는 입력 장치에 지속적으로 액세스하지 않고 특수 버퍼에 입력 데이터를 축적합니다. 예를 들어 보겠습니다.

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

public class BufferedInputExample {

   public static void main(String[] args) throws Exception {
       InputStream inputStream = null;
       BufferedInputStream buffer = null;

       try {

           inputStream = new FileInputStream("D:/Users/UserName/someFile.txt");

           buffer = new BufferedInputStream(inputStream);

           while(buffer.available()>0) {

               char c = (char)buffer.read();

                System.out.println("Character read: " + c);
           }
       } catch(Exception e) {

           e.printStackTrace();

       } finally {

           inputStream.close();
           buffer.close();
       }
   }
}
이 예제에서는 컴퓨터의 ' D:/Users/UserName/someFile.txt '에 있는 파일에서 데이터를 읽습니다. 우리는 2개의 객체를 만듭니다. a FileInputStreamBufferedInputStream그것을 '감싸는' a입니다. 그런 다음 파일에서 바이트를 읽고 문자로 변환합니다. 파일이 끝날 때까지 그렇게 합니다. 보시다시피 여기에는 복잡한 것이 없습니다. 이 코드를 복사하여 컴퓨터의 실제 파일에서 실행할 수 있습니다 :) 클래스는 OutputStream바이트의 출력 스트림을 나타내는 추상 클래스입니다. 이미 알고 있듯이 이것은 InputStream. 어딘가에서 데이터를 읽는 것이 아니라 데이터를 어딘가로 보내는 역할을 합니다 . 와 마찬가지로 InputStream이 추상 클래스는 모든 하위 항목에 편리한 메서드 집합을 제공합니다.
  • void close()출력 스트림을 닫습니다.
  • void flush()모든 출력 버퍼를 지웁니다.
  • abstract void write(int oneByte)출력 스트림에 1바이트를 씁니다.
  • void write(byte[] buffer)출력 스트림에 바이트 배열을 씁니다.
  • void write(byte[] buffer, int offset, int count)오프셋 위치에서 시작하여 배열에서 카운트 바이트 범위를 씁니다.
다음은 클래스의 일부 후손입니다 OutputStream.
  1. DataOutputStream. 표준 Java 데이터 유형을 작성하기 위한 메소드를 포함하는 출력 스트림입니다.

    기본 Java 데이터 유형 및 문자열을 작성하기 위한 매우 간단한 클래스입니다. 설명이 없어도 다음 코드를 이해할 수 있을 것입니다.

    
    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           DataOutputStream dos = new DataOutputStream(new FileOutputStream("testFile.txt"));
    
           dos.writeUTF("SomeString");
           dos.writeInt(22);
           dos.writeDouble(1.21323);
           dos.writeBoolean(true);
    
       }
    }
    

    writeDouble(), writeLong(), writeShort()등 각 유형에 대해 별도의 메서드가 있습니다 .


  2. FileOutputStream. 이 클래스는 데이터를 디스크의 파일로 보내는 메커니즘을 구현합니다. 그건 그렇고, 우리는 이미 마지막 예제에서 그것을 사용했습니다. 눈치채셨나요? '래퍼' 역할을 하는 DataOutputStream에 전달했습니다.

  3. BufferedOutputStream. 버퍼링된 출력 스트림. 여기에도 복잡한 것은 없습니다. 그 목적은 BufferedInputStream(또는 BufferedReader)와 유사합니다. 일반적인 순차적 데이터 읽기 대신 특수 '누적' 버퍼를 사용하여 데이터를 씁니다. 버퍼를 사용하면 데이터 싱크에 액세스하는 횟수를 줄일 수 있으므로 성능이 향상됩니다.

    
    import java.io.*;
    
    public class DataOutputStreamExample {
    
         public static void main(String[] args) throws IOException {
    
               FileOutputStream outputStream = new FileOutputStream("D:/Users/Username/someFile.txt");
               BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
    
               String text = "I love Java!"; // We'll convert this string to a byte array and write it to a file
    
               byte[] buffer = text.getBytes();
    
               bufferedStream.write(buffer, 0, buffer.length);
         }
    }
    

    다시 말하지만, 이 코드를 직접 가지고 놀면서 컴퓨터의 실제 파일에서 작동하는지 확인할 수 있습니다.

FileInputStream, FileOutputStream및 에 대한 별도의 강의가 있으므로 BuffreredInputStream처음 아는 사람에게는 충분한 정보입니다. 그게 다야! 우리는 당신이 인터페이스와 추상 클래스의 차이점을 이해하고 어떤 질문, 심지어 속임수 질문에도 대답할 준비가 되어 있기를 바랍니다 :)
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION