
-
อินเทอร์เฟซอธิบายพฤติกรรมเท่านั้น มันไม่มีสถานะ แต่คลาสนามธรรมรวมถึงสถานะ: มันอธิบายทั้งสองอย่าง
ตัวอย่างเช่น ใช้
Bird
คลาสนามธรรมและCanFly
อินเทอร์เฟซ: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
คลาสนกและสืบทอดกัน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()); } }
อย่างที่คุณเห็น เราสามารถเข้าถึงสถานะของคลาสนามธรรมได้อย่างง่ายดาย — มัน
species
และage
ตัวแปรแต่ถ้าเราพยายามทำเช่นเดียวกันกับอินเทอร์เฟซ ภาพจะแตกต่างออกไป เราสามารถลองเพิ่มตัวแปรเข้าไปได้:
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(); }
เราไม่สามารถประกาศ ตัวแปร ส่วนตัวภายในอินเทอร์เฟซได้ ทำไม เนื่องจาก ตัวดัดแปลง ส่วนตัวถูกสร้างขึ้นเพื่อซ่อนการใช้งานจากผู้ใช้ และอินเทอร์เฟซไม่มีการใช้งานอยู่ภายใน: ไม่มีอะไรต้องซ่อน
อินเทอร์เฟซอธิบายพฤติกรรมเท่านั้น ดังนั้นเราจึงไม่สามารถใช้ getters และ setters ภายในอินเทอร์เฟซได้ นี่คือธรรมชาติของอินเทอร์เฟซ: จำเป็นสำหรับการทำงานกับพฤติกรรม ไม่ใช่สถานะ
Java 8 แนะนำวิธีการเริ่มต้นสำหรับอินเทอร์เฟซที่มีการนำไปใช้งาน คุณรู้เกี่ยวกับพวกเขาแล้ว ดังนั้นเราจะไม่พูดซ้ำ
-
คลาสนามธรรมเชื่อมต่อและรวมคลาสที่เกี่ยวข้องอย่างใกล้ชิด ในเวลาเดียวกัน อินเทอร์เฟซเดียวสามารถนำไปใช้กับคลาสที่ไม่มีอะไรเหมือนกันเลย
กลับไปที่ตัวอย่างของเรากับนก
คลาสนามธรรม ของเรา
Bird
จำเป็นสำหรับการสร้างนกที่มีพื้นฐานมาจากคลาสนั้น แค่นกและไม่มีอะไรอื่น! แน่นอนว่าจะมีนกชนิดต่างๆด้วย
CanFly
อินเทอร์เฟซ ทุกๆ คนดำเนินไปในแบบของตัวเอง มันอธิบายพฤติกรรม (การบิน) ที่เกี่ยวข้องกับชื่อของมันเท่านั้น สิ่งที่ไม่เกี่ยวข้องมากมาย 'บินได้'หน่วยงานทั้ง 4 นี้ไม่เกี่ยวข้องกัน พวกเขาไม่ได้มีชีวิตทั้งหมดด้วยซ้ำ อย่างไรก็ตาม พวกเขา
CanFly
ทั้งหมดเราไม่สามารถอธิบายโดยใช้คลาสนามธรรมได้ พวกเขาไม่ได้แบ่งปันสถานะเดียวกันหรือฟิลด์ที่เหมือนกัน ในการระบุเครื่องบิน เราอาจต้องการฟิลด์สำหรับรุ่น ปีที่ผลิต และจำนวนผู้โดยสารสูงสุด สำหรับคาร์ลสัน เราต้องการทุ่งสำหรับขนมทั้งหมดที่เขากินในวันนี้ และรายชื่อเกมที่เขาจะเล่นกับน้องชายคนเล็กของเขา สำหรับยุง ...เอ่อ... ฉันไม่รู้ด้วยซ้ำว่า... อาจจะเป็น 'ระดับความรำคาญ'? :)
ประเด็นคือเราไม่สามารถใช้คลาสนามธรรมเพื่ออธิบายได้ พวกเขาแตกต่างกันเกินไป แต่พวกมันมีพฤติกรรมร่วมกัน: พวกมันบินได้ อินเทอร์เฟซเหมาะสำหรับการอธิบายทุกสิ่งในโลกที่สามารถบิน ว่ายน้ำ กระโดด หรือแสดงพฤติกรรมอื่นๆ ได้
-
คลาสสามารถใช้อินเทอร์เฟซได้มากเท่าที่คุณต้องการ แต่สามารถสืบทอดได้เพียงคลาสเดียวเท่านั้น
เราได้กล่าวถึงเรื่องนี้มากกว่าหนึ่งครั้งแล้ว Java ไม่มีการสืบทอดหลายคลาส แต่รองรับการสืบทอดหลายอินเตอร์เฟส ประเด็นนี้เป็นไปตามส่วนก่อนหน้า: อินเทอร์เฟซเชื่อมต่อคลาสต่างๆ มากมายที่มักไม่มีอะไรเหมือนกัน ในขณะที่คลาสนามธรรมถูกสร้างขึ้นสำหรับกลุ่มของคลาสที่เกี่ยวข้องกันอย่างใกล้ชิด ดังนั้นจึงสมเหตุสมผลที่คุณจะสามารถสืบทอดคลาสดังกล่าวได้เพียงหนึ่งคลาสเท่านั้น คลาสนามธรรมอธิบายความสัมพันธ์แบบ 'is-a'
อินเทอร์เฟซมาตรฐาน: InputStream และ OutputStream
เราได้ศึกษาคลาสต่าง ๆ ที่รับผิดชอบอินพุตและเอาต์พุตสตรีมแล้ว ลองพิจารณา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
: An InputStreamReader
can do the job. แต่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 read: " + c);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
inputStream.close();
buffer.close();
}
}
}
ในตัวอย่างนี้ เราอ่านข้อมูลจากไฟล์ที่อยู่ในคอมพิวเตอร์ที่ ' D:/Users/UserName/someFile.txt ' เราสร้างวัตถุ 2 ชิ้น — a FileInputStream
และ a BufferedInputStream
ที่ 'ห่อหุ้ม' จากนั้นเราจะอ่านไบต์จากไฟล์และแปลงเป็นอักขระ และเราทำจนกว่าไฟล์จะสิ้นสุด อย่างที่คุณเห็นไม่มีอะไรซับซ้อนที่นี่ คุณสามารถคัดลอกรหัสนี้และรันบนไฟล์จริงบนคอมพิวเตอร์ของคุณ :) OutputStream
คลาสนี้เป็นคลาสนามธรรมที่แสดงถึงเอาต์พุตสตรีมของไบต์ ดังที่คุณทราบแล้ว สิ่งนี้ตรงกันข้ามกับไฟล์InputStream
. ไม่มีหน้าที่ในการอ่านข้อมูลจากที่ใดที่หนึ่ง แต่รับผิดชอบในการส่งข้อมูลที่ใดที่หนึ่ง เช่นInputStream
คลาสนามธรรมนี้ให้ชุดวิธีการที่สะดวกแก่ลูกหลานทั้งหมด:
void 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
) แทนที่จะอ่านข้อมูลตามลำดับตามปกติ จะเขียนข้อมูลโดยใช้บัฟเฟอร์ 'สะสม' แบบพิเศษ บัฟเฟอร์ทำให้สามารถลดจำนวนครั้งที่เข้าถึงอ่างข้อมูล ซึ่งจะเป็นการเพิ่มประสิทธิภาพ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); } }
อีกครั้ง คุณสามารถลองใช้โค้ดนี้ด้วยตัวเองและตรวจสอบว่าโค้ดนี้ใช้ได้กับไฟล์จริงในคอมพิวเตอร์ของคุณ
FileInputStream
และFileOutputStream
ดังนั้นBuffreredInputStream
นี่จึงเป็นข้อมูลที่เพียงพอสำหรับการทำความรู้จักกันครั้งแรก แค่นั้นแหละ! เราหวังว่าคุณจะเข้าใจความแตกต่างระหว่างอินเทอร์เฟซและคลาสนามธรรม และพร้อมที่จะตอบคำถามใด ๆ แม้กระทั่งคำถามลวง :)
GO TO FULL VERSION