-
อินเทอร์เฟซอธิบายเฉพาะพฤติกรรมเท่านั้น เขาไม่มีโชคลาภ แต่คลาสนามธรรมนั้นมีสถานะ: มันอธิบายทั้งสองอย่าง
ลองใช้คลาสนามธรรม
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(); }
เราไม่สามารถสร้าง ตัวแปร ส่วนตัวภายในอินเทอร์เฟซได้ ทำไม เนื่องจาก ตัวแก้ไข ส่วนตัวถูกสร้างขึ้นเพื่อซ่อนการใช้งานจากผู้ใช้ แต่ไม่มีการใช้งานภายในอินเทอร์เฟซ: ไม่มีอะไรจะซ่อนอยู่ที่นั่น
อินเทอร์เฟซอธิบายลักษณะการทำงานเท่านั้น ดังนั้นเราจะไม่สามารถใช้ getters และ setters ภายในอินเทอร์เฟซได้ นั่นคือธรรมชาติของอินเทอร์เฟซ: มีไว้เพื่อจัดการกับพฤติกรรม ไม่ใช่สถานะ
Java8 แนะนำวิธีอินเทอร์เฟซเริ่มต้นที่มีการนำไปใช้งาน คุณรู้เกี่ยวกับพวกเขาแล้ว ดังนั้นเราจะไม่ทำซ้ำ
-
คลาสนามธรรมเชื่อมโยงและรวมคลาสที่มีความสัมพันธ์ใกล้ชิดกันมาก ในเวลาเดียวกัน อินเทอร์เฟซเดียวกันสามารถนำไปใช้โดยคลาสที่ไม่มีอะไรเหมือนกันเลย
กลับมาที่ตัวอย่างของเรากับนก
คลาสนามธรรมของเรา
Bird
จำเป็นสำหรับการสร้างนกตามคลาสนั้น มีเพียงนกเท่านั้นและไม่มีใครอื่น! แน่นอนว่าพวกเขาจะแตกต่างออกไปด้วยอินเทอร์เฟซ
Flyable
ทุกอย่างจะแตกต่างออกไป อธิบายเฉพาะพฤติกรรมที่สอดคล้องกับชื่อเท่านั้น - "การบิน" คำจำกัดความของ "การบิน" "สามารถบินได้" รวมถึงวัตถุหลายอย่างที่ไม่เกี่ยวข้องกันตัวตนทั้ง 4 นี้ไม่เกี่ยวข้องกันแต่อย่างใด ฉันจะพูดอะไรได้บ้าง ไม่ใช่ทั้งหมดที่มีชีวิตด้วยซ้ำ อย่างไรก็ตาม พวกมันทั้งหมด
Flyable
สามารถบินได้เราจะไม่สามารถอธิบายสิ่งเหล่านี้โดยใช้คลาสนามธรรมได้ ไม่มีสถานะทั่วไปหรือช่องที่เหมือนกัน ในการจำแนกลักษณะของเครื่องบิน เราอาจจำเป็นต้องระบุข้อมูลในช่อง “รุ่น”, “ปีที่ผลิต” และ “จำนวนผู้โดยสารสูงสุด” สำหรับคาร์ลสัน มีทุ่งนาสำหรับขนมหวานที่เขากินวันนี้ และรายชื่อเกมที่เขาจะเล่นกับเดอะคิด สำหรับยุง...เอ่อ...เอ่อ...เราไม่รู้ด้วยซ้ำ...อาจจะเป็น “ระดับน่ารำคาญ” เหรอ? :)
สิ่งสำคัญคือเราไม่สามารถอธิบายโดยใช้คลาสนามธรรมได้ พวกเขาแตกต่างกันเกินไป แต่มีพฤติกรรมทั่วไป: พวกมันบินได้ อินเทอร์เฟซนี้เหมาะสำหรับการอธิบายทุกสิ่งในโลกที่สามารถบิน ว่ายน้ำ กระโดด หรือมีพฤติกรรมอื่น ๆ ได้
-
คลาสสามารถใช้อินเทอร์เฟซได้มากเท่าที่ต้องการ แต่สามารถสืบทอดจากคลาสเดียวเท่านั้น
เราได้พูดคุยเกี่ยวกับเรื่องนี้มากกว่าหนึ่งครั้งแล้ว ไม่มีการสืบทอดหลายรายการใน Java แต่มีการใช้งานหลายอย่าง จุดนี้ส่วนหนึ่งตามมาจากจุดก่อนหน้า: อินเทอร์เฟซเชื่อมต่อคลาสต่างๆ มากมายที่มักจะไม่มีอะไรเหมือนกัน และคลาสนามธรรมถูกสร้างขึ้นสำหรับกลุ่มของคลาสที่อยู่ใกล้กันมาก ดังนั้นจึงเป็นตรรกะที่คุณสามารถสืบทอดจากคลาสดังกล่าวเพียงคลาสเดียวเท่านั้น คลาสนามธรรมอธิบายความสัมพันธ์ "เป็น"
อินเทอร์เฟซอินพุตสตรีมและเอาต์พุตสตรีมมาตรฐาน
เราได้ผ่านคลาสต่างๆ ที่รับผิดชอบในการสตรีมอินพุตและเอาต์พุตไปแล้ว มาดูกัน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
ไบต์ของอินพุต ส่งคืนจำนวนไบต์ที่ถูกละเว้น
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
. สตรีมเอาต์พุตที่มีวิธีการเขียนชนิดข้อมูล 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()
และอื่นๆ -
ระดับ
FileOutputStream
. ใช้กลไกในการส่งข้อมูลไปยังไฟล์บนดิสก์ ยังไงก็ตาม เราใช้มันไปแล้วในตัวอย่างที่แล้ว คุณสังเกตเห็นไหม? เราส่งผ่านมันไปภายใน DataOutputStream ซึ่งทำหน้าที่เป็น "wrapper" -
BufferedOutputStream
. กระแสเอาต์พุตบัฟเฟอร์ ไม่มีอะไรซับซ้อนเช่นกัน สาระสำคัญก็เหมือนกับในBufferedInputStream
(หรือBufferedReader
'a) แทนที่จะใช้การบันทึกข้อมูลตามลำดับตามปกติ จะใช้การบันทึกผ่านบัฟเฟอร์ "การจัดเก็บ" พิเศษ ด้วยการใช้บัฟเฟอร์ คุณสามารถลดจำนวนการเดินทางไปกลับไปยังปลายทางข้อมูลได้ และด้วยเหตุนี้จึงปรับปรุงประสิทธิภาพได้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