-
یک رابط فقط رفتار را توصیف می کند. او هیچ ثروتی ندارد. اما یک کلاس انتزاعی حالتی دارد: هر دو را توصیف می کند.
بیایید یک کلاس انتزاعی
Bird
و رابط را به عنوان مثال در نظر بگیریمFlyable
: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
(mockingjay) ایجاد کنیم و ازBird
:public class Mockingjay extends Bird { @Override public void fly() { System.out.println("Fly, birdie!"); } public static void main(String[] args) { Mockingjay someBird = new Mockingjay(); someBird.setAge(19); System.out.println(someBird.getAge()); } }
همانطور که می بینید، ما به راحتی می توانیم به وضعیت کلاس انتزاعی - متغیرهای آن
species
(نوع) وage
(سن) دسترسی پیدا کنیم.اما اگر بخواهیم همین کار را با رابط انجام دهیم، تصویر متفاوت خواهد بود. می توانیم متغیرهایی را به آن اضافه کنیم:
public interface Flyable { String species = new String(); int age = 10; public void fly(); } public interface Flyable { private String species = new String(); // error private int age = 10; // also an error public void fly(); }
ما حتی قادر به ایجاد متغیرهای خصوصی در داخل رابط نخواهیم بود . چرا؟ زیرا اصلاح کننده خصوصی برای پنهان کردن پیاده سازی از کاربر ایجاد شده است. اما هیچ پیاده سازی در داخل رابط وجود ندارد: چیزی برای پنهان کردن وجود ندارد.
رابط فقط رفتار را توصیف می کند. بر این اساس، نمیتوانیم گیرندهها و تنظیمکنندهها را در داخل اینترفیس پیادهسازی کنیم. این ماهیت یک رابط است: به معنای برخورد با رفتار است، نه حالت.
Java8 روش های رابط پیش فرضی را معرفی کرد که پیاده سازی دارند. شما قبلاً در مورد آنها می دانید، بنابراین ما آنها را تکرار نمی کنیم.
-
یک کلاس انتزاعی کلاس هایی را که رابطه بسیار نزدیکی دارند پیوند می دهد و یکی می کند. در عین حال، همان رابط را می توان توسط کلاس هایی پیاده سازی کرد که هیچ وجه اشتراکی ندارند.
بیایید به مثال خود در مورد پرندگان بازگردیم.
کلاس انتزاعی ما
Bird
برای ایجاد پرندگان بر اساس آن مورد نیاز است. فقط پرندگان و هیچ کس دیگری! البته آنها متفاوت خواهند بود.با رابط
Flyable
همه چیز متفاوت است. این فقط رفتار مربوط به نام آن - "پرواز" را توصیف می کند. تعریف "پرواز"، "قابلیت پرواز" شامل بسیاری از اشیاء است که به یکدیگر مرتبط نیستند.این 4 موجودیت به هیچ وجه با یکدیگر مرتبط نیستند. چه بگویم، همه آنها حتی جاندار نیستند. با این حال، همه آنها
Flyable
قادر به پرواز هستند.ما نمی توانیم آنها را با استفاده از یک کلاس انتزاعی توصیف کنیم. آنها حالت مشترک یا زمینه های یکسانی ندارند. برای مشخص کردن یک هواپیما، احتمالاً به فیلدهای «مدل»، «سال ساخت» و «حداکثر تعداد مسافر» نیاز داریم. برای کارلسون، زمینهایی برای همه شیرینیهایی که امروز خورد و فهرستی از بازیهایی که با بچه بازی خواهد کرد وجود دارد. برای یک پشه ... اوه - اوه ... ما حتی نمی دانیم ... شاید "سطح آزار"؟ :)
نکته اصلی این است که ما نمی توانیم آنها را با استفاده از یک کلاس انتزاعی توصیف کنیم. آنها خیلی متفاوت هستند. اما یک رفتار مشترک وجود دارد: آنها می توانند پرواز کنند. رابط کاربری ایده آل برای توصیف هر چیزی در جهان است که می تواند پرواز کند، شنا کند، بپرد یا رفتار دیگری داشته باشد.
-
کلاس ها می توانند هر تعداد رابط را که بخواهند پیاده سازی کنند، اما فقط می توانند از یک کلاس ارث بری کنند.
ما قبلاً بیش از یک بار در مورد این موضوع صحبت کرده ایم. در جاوا وراثت چندگانه وجود ندارد، اما پیاده سازی چندگانه وجود دارد. این نکته تا حدی از مورد قبلی پیروی می کند: یک اینترفیس کلاس های مختلفی را که اغلب هیچ وجه اشتراکی ندارند به هم متصل می کند و یک کلاس انتزاعی برای گروهی از کلاس ها ایجاد می شود که بسیار نزدیک به یکدیگر هستند. بنابراین، منطقی است که شما فقط از یک کلاس از این قبیل ارث ببرید. یک کلاس انتزاعی رابطه "است" را توصیف می کند.
رابط های جریان ورودی و خروجی استاندارد
ما قبلاً از کلاس های مختلف مسئول ورودی و خروجی جریان عبور کرده ایم. بیایید نگاه کنیمInputStream
و OutputStream
. به طور کلی، اینها رابط نیستند، بلکه کلاس های انتزاعی واقعی هستند. اکنون می دانید آنها چه هستند، بنابراین کار با آنها بسیار ساده تر خواهد بود :) InputStream
- این یک کلاس انتزاعی است که مسئول ورودی بایت است. جاوا یک سری کلاس دارد که از 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)
skipsbyteCount
، یک بایت ورودی، تعداد بایت های نادیده گرفته شده را برمی گرداند.
FileInputStream
: رایج ترین نوعInputStream
. برای خواندن اطلاعات از یک فایل استفاده می شود.StringBufferInputStream
InputStream
: یک نوع مفید دیگر یک رشته را به یک جریان داده ورودی تبدیل می کندInputStream
.BufferedInputStream
: جریان ورودی بافر. اغلب برای بهبود کارایی استفاده می شود.
BufferedReader
و گفتیم که لازم نیست از آن استفاده کنیم؟ وقتی می نویسیم:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
... BufferedReader
نیازی به استفاده از آن نیست: 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 was read" + c);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
inputStream.close();
buffer.close();
}
}
}
در این مثال، ما در حال خواندن دادهها از فایلی هستیم که در رایانه در آدرس "D:/Users/UserName/someFile.txt" قرار دارد . ما 2 شی ایجاد می کنیم - FileInputStream
و BufferedInputStream
به عنوان "لفاف بندی" آن. پس از آن، بایت های فایل را می خوانیم و آنها را به کاراکتر تبدیل می کنیم. و به همین ترتیب تا زمانی که فایل تمام شود. همانطور که می بینید، هیچ چیز پیچیده ای در اینجا وجود ندارد. شما می توانید این کد را کپی کرده و آن را بر روی برخی از فایل های واقعی که در رایانه شما ذخیره شده است اجرا کنید :) کلاس یک OutputStream
کلاس انتزاعی است که خروجی جریان بایت را تعریف می کند. همانطور که قبلاً فهمیدید، این نقطه مقابل InputStream
«a» است. مسئول این نیست که داده ها را از کجا بخواند، بلکه مسئول مکان ارسال آن است . مانند InputStream
، این کلاس انتزاعی گروهی از متدها را برای کار راحت به همه فرزندان ارائه می دهد:
int close()
جریان خروجی را می بندد.void flush()
تمام بافرهای خروجی را پاک می کند.abstract void write (int oneByte)
1 بایت را در جریان خروجی می نویسد.void write (byte[] buffer)
آرایه ای از بایت ها را در جریان خروجی می نویسد.void write (byte[] buffer, int offset, int count)
محدوده ای از تعداد بایت ها را از آرایه می نویسد، که از موقعیت افست شروع می شود.
OutputStream
:
-
DataOutputStream
. یک جریان خروجی که شامل روش هایی برای نوشتن انواع داده های استاندارد جاوا است.یک کلاس بسیار ساده برای نوشتن انواع و رشته های جاوا اولیه. مطمئناً کد نوشته شده را حتی بدون توضیح نیز متوجه خواهید شد:
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()
غیره. -
کلاس
FileOutputStream
. مکانیزمی را برای ارسال داده ها به فایل روی دیسک پیاده سازی می کند. به هر حال، قبلاً در مثال قبلی از آن استفاده کردیم، آیا متوجه شدید؟ ما آن را در داخل DataOutputStream، که به عنوان یک "پوشش" عمل می کرد، عبور دادیم. -
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 will convert this string into an array of bytes and write it to a file byte[] buffer = text.getBytes(); bufferedStream.write(buffer, 0, buffer.length); bufferedStream.close(); } }
باز هم، می توانید خودتان با این کد «بازی» کنید و بررسی کنید که چگونه روی فایل های واقعی روی رایانه شما کار می کند.
InputStream
ورودی / خروجی " بخوانید. اوه ، و ما همچنین یک سخنرانی جداگانه خواهیم داشت، بنابراین اطلاعات کافی در مورد آنها برای اولین آشنایی وجود دارد. همین! امیدواریم درک خوبی از تفاوتهای بین رابطها و کلاسهای انتزاعی داشته باشید و آماده پاسخگویی به هر سوالی باشید، حتی یک سوال دشوار :) OutputStream
FileInputStream
FileOutputStream
BufferedInputStream
GO TO FULL VERSION