
-
Arayüz sadece davranışı tanımlar. Devleti yoktur. Ancak soyut bir sınıf durumu içerir: her ikisini de tanımlar.
Örneğin,
Bird
soyut sınıfı veCanFly
arayü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
MockingJay
ve miras almasını sağlayalımBird
: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()); } }
species
Gördüğünüz gibi, soyut sınıfın durumuna - onun ve değişkenlerine kolayca erişebiliyoruzage
.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.
-
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.Arayüz ile
CanFly
herkes kendi yolunda ilerliyor. Yalnızca adıyla ilişkili davranışı (uçmayı) açıklar. Pek çok ilgisiz şey 'uçabilir'.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.
-
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üşünelimInputStream
ve 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 :) InputStream
bayt 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.
FileInputStream
: en yaygın türüInputStream
. Bir dosyadan bilgi okumak için kullanılır;StringBufferInputStream
: Başka bir yararlı türInputStream
. Bir diziyi birInputStream
;BufferedInputStream
: Arabelleğe alınmış bir giriş akışı. En sık performansı artırmak için kullanılır.
BufferedReader
kullanmak 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 InputStreamReader
işi yapabilir. Ancak BufferedReader
performansı 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 FileInputStream
ve BufferedInputStream
onu "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, OutputStream
baytlı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.
OutputStream
:
-
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 . 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.BufferedOutputStream
. Tamponlanmış bir çıktı akışı. Ayrıca burada karmaşık bir şey yok. AmacıBufferedInputStream
(veyaBufferedReader
) 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.
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 :) FileOutputStream
BuffreredInputStream
GO TO FULL VERSION