-
Une interface décrit uniquement le comportement. Il n'a pas de fortune. Mais une classe abstraite a un état : elle décrit les deux.
Prenons comme exemple une classe abstraite
Bird
et une interfaceFlyable
: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; } }
Créons une classe d'oiseau
Mockingjay
(geai moqueur) et héritons deBird
: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()); } }
Comme vous pouvez le voir, nous pouvons facilement accéder à l'état de la classe abstraite - ses variables
species
(type) etage
(âge).Mais si nous essayons de faire de même avec l’interface, le tableau sera différent. Nous pouvons essayer d'y ajouter des variables :
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(); }
Nous ne pourrons même pas créer de variables privées dans l'interface. Pourquoi? Parce que le modificateur privé a été créé pour cacher l'implémentation à l'utilisateur. Mais il n’y a pas d’implémentation à l’intérieur de l’interface : il n’y a rien à cacher.
L'interface décrit uniquement le comportement. Par conséquent, nous ne pourrons pas implémenter de getters et de setters à l'intérieur de l'interface. C'est la nature d'une interface : elle est censée gérer le comportement, pas l'état.
Java8 a introduit des méthodes d'interface par défaut qui ont une implémentation. Vous les connaissez déjà, nous ne les répéterons donc pas.
-
Une classe abstraite relie et fédère des classes qui entretiennent une relation très étroite. Dans le même temps, la même interface peut être implémentée par des classes qui n'ont rien en commun.
Revenons à notre exemple avec les oiseaux.
Notre classe abstraite
Bird
est nécessaire pour créer des oiseaux basés sur elle. Seulement des oiseaux et personne d'autre ! Bien sûr, ils seront différents.Avec l'interface,
Flyable
tout est différent. Il décrit uniquement le comportement correspondant à son nom – « voler ». La définition de « voler », « capable de voler » inclut de nombreux objets qui ne sont pas liés les uns aux autres.Ces 4 entités ne sont en aucun cas liées les unes aux autres. Que puis-je dire, ils ne sont pas tous animés. Cependant, ils sont tous
Flyable
capables de voler.Nous ne pourrions pas les décrire à l’aide d’une classe abstraite. Ils n'ont pas d'état commun ni de champs identiques. Pour caractériser un avion, nous aurons probablement besoin des champs « modèle », « année de fabrication » et « nombre maximum de passagers ». Pour Carlson, il y a des champs pour tous les bonbons qu'il a mangés aujourd'hui et une liste de jeux auxquels il jouera avec le Kid. Pour un moustique... euh-euh... on ne sait même pas... Peut-être « niveau de gêne » ? :)
L’essentiel est que nous ne pouvons pas les décrire à l’aide d’une classe abstraite. Ils sont trop différents. Mais il existe un comportement commun : ils peuvent voler. L'interface est idéale pour décrire tout ce qui dans le monde peut voler, nager, sauter ou avoir un autre comportement.
-
Les classes peuvent implémenter autant d’interfaces qu’elles le souhaitent, mais elles ne peuvent hériter que d’une seule classe.
Nous en avons déjà parlé plus d'une fois. Il n'y a pas d'héritage multiple en Java, mais il existe une implémentation multiple. Ce point découle en partie du précédent : une interface relie de nombreuses classes différentes qui n'ont souvent rien en commun, et une classe abstraite est créée pour un groupe de classes très proches les unes des autres. Il est donc logique que vous ne puissiez hériter que d’une seule de ces classes. Une classe abstraite décrit la relation « est un ».
Interfaces standard InputStream et OutputStream
Nous avons déjà passé en revue les différentes classes responsables du streaming d'entrée et de sortie. RegardonsInputStream
et OutputStream
. En général, ce ne sont pas des interfaces, mais de véritables classes abstraites. Maintenant que vous savez ce qu'ils sont, il sera donc beaucoup plus facile de travailler avec eux :) InputStream
- il s'agit d'une classe abstraite responsable de l'entrée d'octets. Java possède une série de classes qui héritent de InputStream
. Chacun d'eux est configuré pour recevoir des données de différentes sources. Puisqu'il InputStream
s'agit d'un parent, il propose plusieurs méthodes pour travailler facilement avec les flux de données. Chaque enfant a ces méthodes InputStream
:
int available()
renvoie le nombre d'octets disponibles en lecture ;close()
ferme la source d'entrée ;int read()
renvoie une représentation entière du prochain octet disponible dans le flux. Si la fin du flux est atteinte, le nombre -1 sera renvoyé ;int read(byte[] buffer)
tente de lire des octets dans un tampon, renvoyant le nombre d'octets lus. Lorsqu'il atteint la fin du fichier, il renvoie -1 ;int read(byte[] buffer, int byteOffset, int byteCount)
lit une partie d'un bloc d'octets. Utilisé lorsqu'il est possible que le bloc de données n'ait pas été complètement rempli. Lorsqu'il atteint la fin du fichier, renvoie -1 ;long skip(long byteCount)
skipsbyteCount
, un octet d'entrée, renvoyant le nombre d'octets ignorés.
FileInputStream
: le type le plus courantInputStream
. Utilisé pour lire les informations d'un fichier ;StringBufferInputStream
: un autre type utileInputStream
. Il transforme une chaîne en un flux de données d'entréeInputStream
;BufferedInputStream
: flux d’entrée mis en mémoire tampon. Il est le plus souvent utilisé pour améliorer l’efficacité.
BufferedReader
et avons dit que nous n'étions pas obligés de l'utiliser ? Quand on écrit :
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
... BufferedReader
pas besoin de l'utiliser : InputStreamReader
il fera l'affaire. Mais BufferedReader
il le fait plus efficacement et, en outre, peut lire des données sur des lignes entières plutôt que sur des caractères individuels. Tout BufferedInputStream
est pareil! La classe accumule les données d'entrée dans un tampon spécial sans accéder constamment au périphérique d'entrée. Regardons un exemple :
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();
}
}
}
Dans cet exemple, nous lisons les données d'un fichier situé sur l'ordinateur à l'adresse "D:/Users/UserName/someFile.txt" . Nous créons 2 objets - FileInputStream
et BufferedInputStream
comme son « wrapper ». Après cela, nous lisons les octets du fichier et les convertissons en caractères. Et ainsi de suite jusqu'à la fin du fichier. Comme vous pouvez le constater, il n'y a rien de compliqué ici. Vous pouvez copier ce code et l'exécuter sur un fichier réel stocké sur votre ordinateur :) Une classe OutputStream
est une classe abstraite qui définit une sortie de flux d'octets. Comme vous l'avez déjà compris, c'est l'antipode de InputStream
'a. Il n'est pas responsable de l'endroit où lire les données, mais de l' endroit où les envoyer . Comme InputStream
, cette classe abstraite fournit à tous les descendants un groupe de méthodes pour un travail pratique :
int close()
ferme le flux de sortie ;void flush()
efface tous les tampons de sortie ;abstract void write (int oneByte)
écrit 1 octet dans le flux de sortie ;void write (byte[] buffer)
écrit un tableau d'octets dans le flux de sortie ;void write (byte[] buffer, int offset, int count)
écrit une plage de nombres d'octets à partir du tableau, en commençant au décalage de position.
OutputStream
:
-
DataOutputStream
. Flux de sortie qui inclut des méthodes d'écriture de types de données Java standard.Une classe très simple pour écrire des types et des chaînes Java primitifs. Vous comprendrez sûrement le code écrit même sans explication :
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); } }
Il a des méthodes distinctes pour chaque type -
writeDouble()
,writeLong()
,writeShort()
etc. -
Classe
FileOutputStream
. Implémente un mécanisme pour envoyer des données vers un fichier sur le disque. D’ailleurs, nous l’avons déjà utilisé dans l’exemple précédent, l’avez-vous remarqué ? Nous l'avons transmis à l'intérieur du DataOutputStream, qui a fait office de « wrapper ». -
BufferedOutputStream
. Flux de sortie tamponné. Rien de compliqué non plus, l'essence est la même que dansBufferedInputStream
(ouBufferedReader
'a). Au lieu de l'enregistrement séquentiel habituel des données, un enregistrement via un tampon de « stockage » spécial est utilisé. En utilisant un tampon, vous pouvez réduire le nombre d'allers-retours vers la destination des données et ainsi améliorer l'efficacité.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(); } }
Encore une fois, vous pouvez « jouer » vous-même avec ce code et vérifier comment il fonctionnera sur de vrais fichiers sur votre ordinateur.
InputStream
d'entrée /sortie ». Oh , et nous aurons également une conférence séparée, il y aura donc suffisamment d'informations à leur sujet pour la première connaissance. C'est tout! Nous espérons que vous comprenez bien les différences entre les interfaces et les classes abstraites et que vous êtes prêt à répondre à toute question, même délicate :) OutputStream
FileInputStream
FileOutputStream
BufferedInputStream
GO TO FULL VERSION