CodeGym /Java Blogu /Rastgele /Soyut sınıflar ve arayüzler arasındaki fark
John Squirrels
Seviye
San Francisco

Soyut sınıflar ve arayüzler arasındaki fark

grupta yayınlandı
MERHABA! Bu derste, soyut sınıfların arayüzlerden ne kadar farklı olduğu hakkında konuşacağız ve ortak soyut sınıflarla ilgili bazı örnekleri ele alacağız. Soyut sınıflar ve arayüzler arasındaki fark - 1Soyut bir sınıf ile arayüz arasındaki farklara ayrı bir ders ayırdık çünkü bu konu çok önemli. Gelecekteki görüşmelerin %90'ında size bu kavramlar arasındaki fark sorulacak. Bu, ne okuduğunuzu anladığınızdan emin olmanız gerektiği anlamına gelir. Ve bir şeyi tam olarak anlamadıysanız, ek kaynakları okuyun. Böylece, soyut bir sınıfın ve arayüzün ne olduğunu biliyoruz. Şimdi onların farklılıklarını ele alacağız.
  1. Arayüz sadece davranışı tanımlar. Devleti yoktur. Ancak soyut bir sınıf durumu içerir: her ikisini de tanımlar.

    Örneğin, Birdsoyut sınıfı ve CanFlyarayüzü ele alalım:

    
    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;
       }
    }
    

    Bir kuş sınıfı oluşturalım MockingJayve miras almasını sağlayalım 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());
       }
    }
    

    speciesGördüğünüz gibi, soyut sınıfın durumuna - onun ve değişkenlerine kolayca erişebiliyoruz age.

    Ama aynısını bir arayüz ile yapmaya çalışırsak, resim farklıdır. Buna değişkenler eklemeyi deneyebiliriz:

    
    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();
    }
    

    Bir arayüz içinde özel değişkenleri bile bildiremiyoruz . Neden? Özel değiştirici, uygulamayı kullanıcıdan gizlemek için yaratıldığı için . Ve bir arayüzün içinde uygulaması yoktur: saklanacak bir şey yoktur.

    Arayüz sadece davranışı tanımlar. Buna göre, bir arayüz içinde alıcılar ve ayarlayıcılar uygulayamayız. Arayüzlerin doğası budur: durumla değil davranışla çalışmaları gerekir.

    Java 8, uygulaması olan arabirimler için varsayılan yöntemleri tanıttı. Onları zaten biliyorsunuz, bu yüzden kendimizi tekrar etmeyeceğiz.

  2. Soyut bir sınıf, çok yakından ilişkili olan sınıfları birbirine bağlar ve birleştirir. Aynı zamanda, kesinlikle hiçbir ortak noktası olmayan sınıflar tarafından tek bir arayüz uygulanabilir.

    Kuşlarla olan örneğimize geri dönelim.

    Soyut sınıfımız Bird, o sınıfa dayalı kuşlar oluşturmak için gereklidir. Sadece kuşlar ve başka bir şey yok! Tabii ki, farklı türde kuşlar olacak.

    Soyut sınıflar ve arayüzler arasındaki fark - 2

    Arayüz ile CanFlyherkes kendi yolunda ilerliyor. Yalnızca adıyla ilişkili davranışı (uçmayı) açıklar. Pek çok ilgisiz şey 'uçabilir'.

    Soyut sınıflar ve arayüzler arasındaki fark - 3

    Bu 4 varlık birbiriyle ilişkili değildir. Hepsi yaşamıyor bile. Ancak hepsi CanFly.

    Onları soyut bir sınıf kullanarak tanımlayamadık. Aynı durumu veya aynı alanları paylaşmazlar. Bir uçağı tanımlamak için muhtemelen model, üretim yılı ve maksimum yolcu sayısı alanlarına ihtiyacımız olacaktır. Carlson için, bugün yediği tüm şekerlemeler için tarlalara ve küçük kardeşiyle oynayacağı oyunların bir listesine ihtiyacımız olacak. Bir sivrisinek için, ...uh... Bilmiyorum bile... Belki, 'sıkıntı seviyesi'? :)

    Mesele şu ki, onları tanımlamak için soyut bir sınıf kullanamayız. Onlar çok farklı. Ama ortak davranışları var: uçabilirler. Bir arayüz, dünyada uçabilen, yüzebilen, zıplayabilen veya başka davranışlar sergileyebilen her şeyi tanımlamak için mükemmeldir.

  3. Sınıflar istediğiniz kadar arabirim uygulayabilir ancak yalnızca bir sınıfı miras alabilirler.

    Bundan zaten bir kereden fazla bahsettik. Java, sınıfların çoklu kalıtımına sahip değildir, ancak arayüzlerin çoklu kalıtımını destekler. Bu nokta kısmen bir öncekini takip eder: bir arabirim, genellikle başka hiçbir ortak noktası olmayan birçok farklı sınıfı birbirine bağlarken, çok yakından ilişkili sınıflardan oluşan bir grup için soyut bir sınıf oluşturulur. Bu nedenle, yalnızca böyle bir sınıfı miras alabileceğiniz mantıklıdır. Soyut bir sınıf, bir 'is-a' ilişkisini tanımlar.

Standart arayüzler: InputStream ve OutputStream

Girdi ve çıktı akışlarından sorumlu çeşitli sınıfları zaten inceledik. Düşünelim InputStreamve OutputStream. Genel olarak, bunlar hiç arayüz değil, tamamen gerçek soyut sınıflardır. Artık bunun ne anlama geldiğini biliyorsunuz, bu yüzden onlarla çalışmak çok daha kolay olacak :) InputStreambayt girişinden sorumlu soyut bir sınıftır. Java'nın miras alan birkaç sınıfı vardır InputStream. Her biri farklı kaynaklardan veri almak için tasarlanmıştır. Ebeveyn olduğu için InputStream, veri akışlarıyla çalışmayı kolaylaştıran çeşitli yöntemler sağlar. Her torunu InputStreamşu yöntemlere sahiptir:
  • int available()okunabilir bayt sayısını döndürür;
  • close()giriş akışını kapatır;
  • int read()akıştaki bir sonraki kullanılabilir baytın tamsayı gösterimini döndürür. Akışın sonuna ulaşıldıysa, -1 döndürülür;
  • int read(byte[] buffer)baytları arabelleğe okumaya çalışır ve okunan bayt sayısını döndürür. Dosyanın sonuna geldiğinde -1 döndürür;
  • int read(byte[] buffer, int byteOffset, int byteCount)bayt bloğunun bir kısmını yazar. Bayt dizisi tamamen doldurulmamış olduğunda kullanılır. Dosyanın sonuna geldiğinde -1 döndürür;
  • long skip(long byteCount)giriş akışındaki byteCount baytlarını atlar ve yoksayılan bayt sayısını döndürür.
Yöntemlerin tam listesini incelemenizi tavsiye ederim . Aslında ondan fazla çocuk sınıfı var. Örneğin, işte birkaçı:
  1. FileInputStream: en yaygın türü InputStream. Bir dosyadan bilgi okumak için kullanılır;
  2. StringBufferInputStream: Başka bir yararlı tür InputStream. Bir diziyi bir InputStream;
  3. BufferedInputStream: Arabelleğe alınmış bir giriş akışı. En sık performansı artırmak için kullanılır.
Gidip BufferedReaderkullanmak zorunda olmadığını söylediğimizi hatırlıyor musun? Yazdığımızda:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
…şunu kullanmak zorunda değilsiniz BufferedReader: An InputStreamReaderişi yapabilir. Ancak BufferedReaderperformansı artırır ve tek tek karakterler yerine tüm veri satırlarını da okuyabilir. Aynı şey için de geçerli BufferedInputStream! Sınıf, giriş cihazına sürekli olarak erişmeden giriş verilerini özel bir arabellekte toplar. Bir örnek ele alalım:

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();
       }
   }
}
Bu örnekte, bir bilgisayarda bulunan ' D:/Users/UserName/someFile.txt ' dosyasındaki verileri okuyoruz . 2 nesne yaratıyoruz - a FileInputStreamve BufferedInputStreamonu "saran" a. Daha sonra dosyadan baytları okuruz ve bunları karakterlere dönüştürürüz. Ve bunu dosya bitene kadar yapıyoruz. Gördüğünüz gibi, burada karmaşık bir şey yok. Bu kodu kopyalayabilir ve bilgisayarınızdaki gerçek bir dosyada çalıştırabilirsiniz :) Sınıf, OutputStreambaytlık bir çıktı akışını temsil eden soyut bir sınıftır. Bildiğiniz gibi, bu bir InputStream. Bir yerden veri okumaktan değil, bir yere veri göndermekten sorumludur . Gibi InputStream, bu soyut sınıf, tüm soyundan gelenlere bir dizi uygun yöntem verir:
  • void close()çıkış akışını kapatır;
  • void flush()tüm çıktı arabelleklerini temizler;
  • abstract void write(int oneByte)çıkış akışına 1 bayt yazar;
  • void write(byte[] buffer)çıktı akışına bir bayt dizisi yazar;
  • void write(byte[] buffer, int offset, int count)uzaklık konumundan başlayarak bir diziden sayılan bayt aralığını yazar.
İşte sınıfın torunlarından bazıları OutputStream:
  1. DataOutputStream. Standart Java veri türlerini yazmak için yöntemler içeren bir çıktı akışı.

    İlkel Java veri türleri ve dizeleri yazmak için çok basit bir sınıf. Muhtemelen aşağıdaki kodu bir açıklama olmadan da anlayacaksınız:

    
    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()Her tür — , writeLong(), writeShort()vb. için ayrı yöntemleri vardır .


  2. FileOutputStream. Bu sınıf, verileri diskteki bir dosyaya göndermek için bir mekanizma uygular. Bu arada, onu zaten son örnekte kullandık. Fark ettin mi? Bunu bir 'sarmalayıcı' görevi gören DataOutputStream'e ilettik.

  3. BufferedOutputStream. Tamponlanmış bir çıktı akışı. Ayrıca burada karmaşık bir şey yok. Amacı BufferedInputStream(veya BufferedReader) ile benzerdir. Verilerin olağan sıralı okuması yerine, özel bir 'kümülatif' arabellek kullanarak veri yazar. Arabellek, veri havuzuna erişilme sayısını azaltarak performansı artırmayı mümkün kılar.

    
    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);
         }
    }
    

    Yine, bu kodla kendiniz oynayabilir ve bilgisayarınızdaki gerçek dosyalarda çalışacağını doğrulayabilirsiniz.

ve hakkında ayrı bir dersimiz olacak FileInputStream, yani bu ilk tanışma için yeterli bilgi. Bu kadar! Arayüzler ve soyut sınıflar arasındaki farkları anladığınızı ve hileli sorular da dahil olmak üzere her soruyu yanıtlamaya hazır olduğunuzu umuyoruz :) FileOutputStreamBuffreredInputStream
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION