-
An interface only describes behavior. He has no fortune. But an abstract class has a state: it describes both.
Let's take an abstract class
Bird
and interface as an exampleFlyable
: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; } }
Let's create a bird class
Mockingjay
(mockingjay) and inherit fromBird
: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()); } }
As you can see, we can easily access the state of the abstract class - its variables
species
(type) andage
(age).But if we try to do the same with the interface, the picture will be different. We can try adding variables to it:
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(); }
We won't even be able to create private variables inside the interface. Why? Because the private modifier was created to hide the implementation from the user. But there is no implementation inside the interface: there is nothing to hide there.
The interface only describes the behavior. Accordingly, we will not be able to implement getters and setters inside the interface. That's the nature of an interface: it's meant to deal with behavior, not state.
Java8 introduced default interface methods that have an implementation. You already know about them, so we won’t repeat them.
-
An abstract class links and combines classes that have a very close relationship. At the same time, the same interface can be implemented by classes that have nothing in common at all.
Let's return to our example with birds.
Our abstract class
Bird
is needed to create birds based on it. Only birds and no one else! Of course they will be different.With the interface
Flyable
everything is different. It only describes the behavior corresponding to its name - "flying". The definition of “flying”, “capable of flying” includes many objects that are not related to each other.These 4 entities are not related to each other in any way. What can I say, not all of them are even animate. However, they are all
Flyable
capable of flight.We wouldn't be able to describe them using an abstract class. They do not have a common state or identical fields. To characterize an aircraft, we will probably need the fields “model”, “year of manufacture” and “maximum number of passengers”. For Carlson, there are fields for all the sweets that he ate today, and a list of games that he will play with the Kid. For a mosquito...uh-uh...we don’t even know... Maybe “annoyance level”? :)
The main thing is that we cannot describe them using an abstract class. They are too different. But there is a common behavior: they can fly. The interface is ideal for describing everything in the world that can fly, swim, jump, or have some other behavior.
-
Classes can implement as many interfaces as they want, but they can only inherit from one class.
We have already talked about this more than once. There is no multiple inheritance in Java, but there is multiple implementation. This point partly follows from the previous one: an interface connects many different classes that often have nothing in common, and an abstract class is created for a group of classes that are very close to each other. Therefore, it is logical that you can inherit from only one such class. An abstract class describes the “is a” relationship.
Standard InputStream & OutputStream Interfaces
We have already gone through the various classes responsible for streaming input and output. Let's look atInputStream
and OutputStream
. In general, these are not interfaces, but real abstract classes. Now you know what they are, so working with them will be much easier :) InputStream
- this is an abstract class that is responsible for byte input. Java has a series of classes that inherit from InputStream
. Each of them is configured to receive data from different sources. Because InputStream
it is a parent, it provides several methods for conveniently working with data streams. Each child has these methods InputStream
:
int available()
returns the number of bytes available for reading;close()
closes the input source;int read()
returns an integer representation of the next available byte in the stream. If the end of the stream is reached, the number -1 will be returned;int read(byte[] buffer)
attempts to read bytes into a buffer, returning the number of bytes read. When it reaches the end of the file, it returns -1;int read(byte[] buffer, int byteOffset, int byteCount)
reads part of a block of bytes. Used when there is a possibility that the data block was not completely filled. When it reaches the end of the file, returns -1;long skip(long byteCount)
skipsbyteCount
, a byte of input, returning the number of bytes ignored.
FileInputStream
: the most common typeInputStream
. Used to read information from a file;StringBufferInputStream
: another useful typeInputStream
. It turns a string into an input data streamInputStream
;BufferedInputStream
: buffered input stream. It is most often used to improve efficiency.
BufferedReader
and said that we don’t have to use it? When we write:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
... BufferedReader
no need to use it: InputStreamReader
it will do the job. But BufferedReader
it does it more efficiently and, moreover, can read data in entire lines, rather than individual characters. Everything BufferedInputStream
is the same! The class accumulates input data in a special buffer without constantly accessing the input device. Let's look at an example:
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();
}
}
}
In this example, we are reading data from a file that is located on the computer at the address "D:/Users/UserName/someFile.txt" . We create 2 objects - FileInputStream
and BufferedInputStream
as its “wrapper”. After that, we read the bytes from the file and convert them into characters. And so on until the file ends. As you can see, there is nothing complicated here. You can copy this code and run it on some real file that is stored on your computer :) A class OutputStream
is an abstract class that defines a byte stream output. As you already understand, this is the antipode of InputStream
'a. It is responsible not for where to read data from, but for where to send it . Like InputStream
, this abstract class provides all descendants with a group of methods for convenient work:
int close()
closes the output stream;void flush()
clears all output buffers;abstract void write (int oneByte)
writes 1 byte to the output stream;void write (byte[] buffer)
writes an array of bytes to the output stream;void write (byte[] buffer, int offset, int count)
writes a range of count bytes from the array, starting at position offset.
OutputStream
:
-
DataOutputStream
. An output stream that includes methods for writing standard Java data types.A very simple class for writing primitive Java types and strings. Surely you will understand the written code even without explanation:
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); } }
It has separate methods for each type -
writeDouble()
,writeLong()
,writeShort()
and so on. -
Class
FileOutputStream
. Implements a mechanism for sending data to a file on disk. By the way, we already used it in the previous example, did you notice? We passed it inside the DataOutputStream, which acted as a “wrapper”. -
BufferedOutputStream
. Buffered output stream. Nothing complicated either, the essence is the same as inBufferedInputStream
(orBufferedReader
'a). Instead of the usual sequential data recording, recording through a special “storage” buffer is used. By using a buffer, you can reduce the number of round trips to the data destination and thereby improve efficiency.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(); } }
Again, you can “play” with this code yourself and check how it will work on real files on your computer.
InputStream
Input /Output System ”. Oh , and we will also have a separate lecture, so there is enough information about them for the first acquaintance. That's all! We hope you have a good understanding of the differences between interfaces and abstract classes and are ready to answer any question, even a tricky one :) OutputStream
FileInputStream
FileOutputStream
BufferedInputStream
GO TO FULL VERSION