-
Antara muka hanya menerangkan tingkah laku. Ia tidak mempunyai negeri. Tetapi kelas abstrak termasuk keadaan: ia menerangkan kedua-duanya.
Sebagai contoh, ambil
Bird
kelas abstrak danCanFly
antara muka: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; } }
Mari buat
MockingJay
kelas burung dan jadikan ia mewarisiBird
: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()); } }
Seperti yang anda lihat, kami boleh mengakses keadaan kelas abstrak dengan mudah —
species
danage
pembolehubahnya.Tetapi jika kita cuba melakukan perkara yang sama dengan antara muka, gambarnya berbeza. Kita boleh cuba menambah pembolehubah kepadanya:
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(); }
Kami tidak boleh mengisytiharkan pembolehubah peribadi dalam antara muka. kenapa? Kerana pengubah suai peribadi dicipta untuk menyembunyikan pelaksanaan daripada pengguna. Dan antara muka tidak mempunyai pelaksanaan di dalamnya: tidak ada apa-apa untuk disembunyikan.
Antara muka hanya menerangkan tingkah laku. Oleh itu, kami tidak boleh melaksanakan getter dan setter di dalam antara muka. Ini adalah sifat antara muka: mereka diperlukan untuk berfungsi dengan tingkah laku, bukan keadaan.
Java 8 memperkenalkan kaedah lalai untuk antara muka yang mempunyai pelaksanaan. Anda sudah tahu tentang mereka, jadi kami tidak akan mengulangi diri kami sendiri.
-
Kelas abstrak menghubungkan dan menyatukan kelas yang sangat berkait rapat. Pada masa yang sama, antara muka tunggal boleh dilaksanakan oleh kelas yang sama sekali tidak mempunyai persamaan.
Mari kita kembali kepada contoh kita dengan burung.
Kelas abstrak kami
Bird
diperlukan untuk mencipta burung yang berdasarkan kelas itu. Hanya burung dan tidak ada yang lain! Sudah tentu, akan ada pelbagai jenis burung.Dengan
CanFly
antara muka, semua orang meneruskan dengan cara mereka sendiri. Ia hanya menerangkan tingkah laku (terbang) yang dikaitkan dengan namanya. Banyak benda tak berkaitan 'boleh terbang'.4 entiti ini tidak berkaitan antara satu sama lain. Mereka bukan semua hidup. Namun, mereka semua
CanFly
.Kami tidak dapat menerangkannya menggunakan kelas abstrak. Mereka tidak berkongsi keadaan yang sama atau medan yang sama. Untuk menentukan pesawat, kita mungkin memerlukan medan untuk model, tahun pengeluaran dan bilangan penumpang maksimum. Untuk Carlson, kami memerlukan ladang untuk semua gula-gula yang dia makan hari ini, dan senarai permainan yang akan dia mainkan bersama adik lelakinya. Untuk nyamuk, ...eh... Saya pun tak tahu... Mungkin, 'tahap kegusaran'? :)
Intinya ialah kita tidak boleh menggunakan kelas abstrak untuk menerangkannya. Mereka terlalu berbeza. Tetapi mereka mempunyai tingkah laku yang dikongsi: mereka boleh terbang. Antara muka sesuai untuk menerangkan segala-galanya di dunia yang boleh terbang, berenang, melompat atau mempamerkan beberapa tingkah laku lain.
-
Kelas boleh melaksanakan seberapa banyak antara muka yang anda mahu, tetapi mereka hanya boleh mewarisi satu kelas.
Kami telah menyebut perkara ini lebih daripada sekali. Java tidak mempunyai berbilang warisan kelas, tetapi ia menyokong berbilang warisan antara muka. Perkara ini mengikuti sebahagian daripada yang sebelumnya: antara muka menghubungkan banyak kelas berbeza yang selalunya tidak mempunyai persamaan lain, manakala kelas abstrak dicipta untuk sekumpulan kelas yang sangat berkait rapat. Oleh itu, masuk akal bahawa anda hanya boleh mewarisi satu kelas sedemikian. Kelas abstrak menerangkan hubungan 'ialah-a'.
Antara muka standard: InputStream dan OutputStream
Kami telah pun meneliti pelbagai kelas yang bertanggungjawab untuk aliran input dan output. Mari kita pertimbangkanInputStream
dan OutputStream
. Secara umum, ini bukan antara muka sama sekali, tetapi kelas abstrak sepenuhnya tulen. Sekarang anda tahu maksudnya, jadi lebih mudah untuk bekerja dengan mereka :) InputStream
ialah kelas abstrak yang bertanggungjawab untuk input bait. Java mempunyai beberapa kelas yang mewarisi InputStream
. Setiap daripada mereka direka untuk menerima data daripada sumber yang berbeza. Kerana InputStream
merupakan ibu bapa, ia menyediakan beberapa kaedah yang memudahkan untuk bekerja dengan aliran data. Setiap keturunan InputStream
mempunyai kaedah ini:
int available()
mengembalikan bilangan bait yang tersedia untuk dibaca;close()
menutup aliran input;int read()
mengembalikan perwakilan integer bagi bait seterusnya yang tersedia dalam strim. Jika akhir aliran telah dicapai, -1 akan dikembalikan;int read(byte[] buffer)
cuba membaca bait ke dalam penimbal, dan mengembalikan bilangan bait yang dibaca. Apabila ia mencapai penghujung fail, ia mengembalikan -1;int read(byte[] buffer, int byteOffset, int byteCount)
menulis sebahagian daripada blok bait. Ia digunakan apabila tatasusunan bait mungkin tidak diisi sepenuhnya. Apabila ia mencapai penghujung fail, ia mengembalikan -1;long skip(long byteCount)
melangkau byteCount byte dalam aliran input dan mengembalikan bilangan bait yang diabaikan.
FileInputStream
: jenis yang paling biasaInputStream
. Ia digunakan untuk membaca maklumat daripada fail;StringBufferInputStream
: Satu lagi jenisInputStream
. Ia menukar rentetan menjadiInputStream
;BufferedInputStream
: Strim input terkumpul. Ia digunakan paling kerap untuk meningkatkan prestasi.
BufferedReader
dan mengatakan bahawa anda tidak perlu menggunakannya? Apabila kita menulis:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
…anda tidak perlu menggunakan BufferedReader
: Seorang InputStreamReader
boleh melakukan kerja itu. Tetapi BufferedReader
meningkatkan prestasi dan juga boleh membaca keseluruhan baris data dan bukannya aksara individu. Perkara yang sama berlaku untuk BufferedInputStream
! Kelas mengumpul data input dalam penimbal khas tanpa sentiasa mengakses peranti input. Mari kita pertimbangkan contoh:
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();
}
}
}
Dalam contoh ini, kami membaca data daripada fail yang terletak pada komputer di ' D:/Users/UserName/someFile.txt '. Kami mencipta 2 objek — a FileInputStream
dan a BufferedInputStream
yang 'membungkusnya'. Kemudian kami membaca bait daripada fail dan menukarnya kepada aksara. Dan kami melakukannya sehingga fail tamat. Seperti yang anda lihat, tidak ada yang rumit di sini. Anda boleh menyalin kod ini dan menjalankannya pada fail sebenar pada komputer anda :) Kelas OutputStream
ialah kelas abstrak yang mewakili aliran keluaran bait. Seperti yang anda sedia maklum, ini adalah bertentangan dengan InputStream
. Ia tidak bertanggungjawab untuk membaca data dari suatu tempat, sebaliknya untuk menghantar data ke suatu tempat . Seperti InputStream
, kelas abstrak ini memberikan semua keturunannya satu set kaedah yang mudah:
void close()
menutup aliran keluaran;void flush()
mengosongkan semua penimbal keluaran;abstract void write(int oneByte)
menulis 1 bait ke aliran keluaran;void write(byte[] buffer)
menulis tatasusunan bait ke aliran keluaran;void write(byte[] buffer, int offset, int count)
menulis julat bait kiraan daripada tatasusunan, bermula pada kedudukan mengimbangi.
OutputStream
kelas tersebut:
-
DataOutputStream
. Strim output yang merangkumi kaedah untuk menulis jenis data Java standard.Kelas yang sangat mudah untuk menulis jenis data dan rentetan Java primitif. Anda mungkin akan memahami kod berikut walaupun tanpa penjelasan:
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); } }
Ia mempunyai kaedah berasingan untuk setiap jenis —
writeDouble()
,writeLong()
,writeShort()
, dan seterusnya. FileOutputStream
. Kelas ini melaksanakan mekanisme untuk menghantar data ke fail pada cakera. Dengan cara ini, kami sudah menggunakannya dalam contoh terakhir. perasan tak? Kami menyerahkannya kepada DataOutputStream, yang bertindak sebagai 'pembungkus'.BufferedOutputStream
. Aliran keluaran penimbal. Tidak ada yang rumit di sini. Tujuannya adalah serupa denganBufferedInputStream
(atauBufferedReader
). Daripada bacaan berurutan biasa data, ia menulis data menggunakan penimbal 'kumulatif' khas. Penampan memungkinkan untuk mengurangkan bilangan kali sink data diakses, dengan itu meningkatkan prestasi.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); } }
Sekali lagi, anda boleh bermain-main dengan kod ini sendiri dan mengesahkan bahawa ia akan berfungsi pada fail sebenar pada komputer anda.
FileInputStream
, FileOutputStream
dan BuffreredInputStream
, jadi ini adalah maklumat yang mencukupi untuk kenalan pertama. Itu sahaja! Kami harap anda memahami perbezaan antara antara muka dan kelas abstrak dan bersedia untuk menjawab sebarang soalan, walaupun soalan helah :)
GO TO FULL VERSION