Explication détaillée de l'héritage de Scala

1. Étendre la classe
Utilisez le mot clé extend pour étendre la classe

class Employee extends Person {
	var age = 10
	...
}

Dans la définition, indiquez les champs et les méthodes requis par la sous-classe mais pas la superclasse, ou remplacez les méthodes de la superclasse. Comme Java, vous pouvez déclarer une classe comme finale, afin qu'elle ne puisse pas être étendue, et vous pouvez déclarer la méthode ou le champ comme final pour vous assurer qu'ils ne peuvent pas être remplacés.

2. Méthode de réécriture
Pour remplacer une méthode non abstraite dans scala, vous devez utiliser le modificateur de remplacement, par exemple:

public class Person {
  ...
  override def toString = getClass.getName + "[name=" + name + "]"
}

Le modificateur de remplacement peut donner un message d'erreur dans de nombreuses situations courantes:
1. Faute d'orthographe du nom de la méthode à réécrire
2. Utilisez accidentellement le mauvais type de paramètre dans la nouvelle méthode
3. Introduisez-en un nouveau dans la superclasse , Et cette nouvelle méthode entre en conflit avec les méthodes des sous-classes

La méthode d'appel de la super classe dans scala est la même que java, en utilisant le mot clé super:

public class  Employee extends Person {
	...
	override def toString = super.toString
}

super.toString appellera la méthode toString de la super classe, à savoir Person.toString.

3. Vérification et conversion de type Pour
tester si un objet appartient à une classe donnée, vous pouvez utiliser la méthode isInstanceOf. Si le test réussit, vous pouvez utiliser la méthode asInstanceOf pour transformer la référence en référence de sous-classe.

if (p.isInstanceOf[Employee]) {
  val s = p.asInstanceOf[Employee]  //s类型为Employee
}

Si p pointe vers un objet de la classe et des sous-classes Employee (par exemple, s'il existe un Manager), alors p.isInstanceOf [Employee] réussira et retournera true.
Si p est nul, p.isInstanceOf [Employee] renverra false et p.asInstanceOf [Employee] renverra null.
Si p n'est pas un employé, alors p.asInstanceOf [Employee] lèvera une exception.
Si vous souhaitez tester que p pointe vers un objet Employé mais pas sa sous-classe, vous pouvez:

if (p.getClass == classOf[Employee])

La méthode classOf est définie dans l'objet scala.Predef, elle sera donc introduite automatiquement.
Comparaison et vérification de type de Scala par rapport
Insérez la description de l'image ici
à Java: Mais par rapport à la vérification et à la conversion de type, la correspondance de modèle est généralement un meilleur choix, comme:

p match {
  case s: Employee => ... 
  case _ => ...
}

4. Champs et méthodes protégés
Comme Java, vous pouvez déclarer des champs ou des méthodes protégés. Ces membres sont accessibles par n'importe quelle sous-classe, mais ne peuvent pas être vus par d'autres emplacements.
Contrairement à Java, les membres protégés ne sont pas visibles par le package auquel appartient la classe. Si vous avez besoin de cette visibilité, vous pouvez utiliser le modificateur de package.
Il existe également un [this] protégé, qui définit l'autorisation d'accès à l'objet actuel, similaire à private [this].

5. Construction de superclasses
Nous savons qu'une classe a un constructeur principal et un nombre quelconque de constructeurs auxiliaires Chaque constructeur principal doit
commencer par un appel à un constructeur auxiliaire ou constructeur principal précédemment défini. La conséquence de ceci est que les constructeurs auxiliaires ne peuvent jamais appeler directement des constructeurs de superclasse.
Les constructeurs auxiliaires de sous-classes appelleront éventuellement le constructeur principal. Seul le constructeur principal peut appeler le constructeur de la superclasse.
Le constructeur principal est intimement lié à la définition de classe. La façon d'appeler le constructeur de la superclasse est également liée.
Tels que:

class Employee(name: String,age: Int,val salary: Double) extends Person(name,age)

Ce code définit un employé de la sous-classe et un employé du constructeur principal (nom: chaîne, âge: Int, salaire val: double) qui
appelle le constructeur de la superclasse. L'entrelacement de la classe et du constructeur peut rendre le code plus concis , Il peut être préférable de comprendre les paramètres du constructeur principal comme les paramètres de la classe. Par exemple, la classe Employé a trois paramètres:
nom, âge, salaire, dont deux sont transmis à la super classe. Si c'est Java, ce sera beaucoup plus compliqué:

public class Employee extends Person {
  private double salary;
  public Employee(String name,Int age, double salary) {
	super(name,age);
	this.salary = salary;
  }
}

La classe Scala peut étendre la classe Java. Dans ce cas, son constructeur principal doit appeler une méthode de construction de la superclasse Java, telle que:

class Square(x: Int,y: Int,width: Int) extends java.awt.Rectangle(x,y,width.width)

6. Champ de réécriture Le champ
Scala est composé d'un champ privé et d'une méthode de valorisation / changement de valeur. Vous pouvez utiliser un autre champ val du même nom pour réécrire un val (ou def sans paramètres).
La sous-classe a un champ privé et une méthode getter publique, et cette méthode getter remplace la méthode getter de super classe. Tels que:

class Person(val name: String) {
  override def toString = getClass.getName + name
}
class SecretAgent(codename: String) extends Person(codename) {
  override val name = "secret"
  override val toString = "secret"
}

L'exemple ci-dessus montre le mécanisme de réécriture, mais il est plus rigide et il est plus courant d'utiliser val pour réécrire les définitions abstraites, telles que:

abstract class Person {
  def id: Int   //每个人都有某一种方式计算id
  ...
}
class Student(override val id: Int) extends Person

La réécriture a les restrictions suivantes:
1.def ne peut réécrire qu'un autre def
2.val ne peut que réécrire un autre val ou def sans paramètres
3.var ne peut réécrire qu'un autre var abstrait

7. Sous-classes anonymes Comme
Java, une sous-classe anonyme peut être créée en incluant des blocs de code avec des définitions ou des réécritures, telles que:

val alien = new Person("Fred") {
  def greeting = "Grettings, Earthing, my name is Fred"
}

Techniquement parlant, cela crée un objet de type structure, qui est marqué comme Personne {def salutation: Chaîne}, nous pouvons utiliser ce type comme définition du type de paramètre:

def meet(p: Person{def greeting: String}) {
  println(p.name + "says" + p.greeting)
}

8. Classe abstraite
Comme Java, vous pouvez utiliser le mot clé abstract pour marquer une classe qui ne peut pas être instanciée, généralement parce qu'une ou plusieurs de ses méthodes ne sont pas complètement définies, telles que:

abstract class Person(val name: String) {
  def id: Int //没有方法体,这是一个抽象方法
}

Ici, nous disons que tout le monde a un id, mais nous ne savons pas comment le calculer. Chaque sous-classe Person spécifique doit donner une méthode id. Contrairement à Scala, contrairement à Java, nous n'avons pas besoin d'utiliser le mot-clé abstrait pour les méthodes abstraites. , Omettez simplement le corps de la méthode, mais comme Java, s'il y a au moins une méthode abstraite dans une classe, la classe doit être déclarée abstraite.
Lors de la substitution de la méthode abstraite d'une superclasse dans une sous-classe, il n'est pas nécessaire d'utiliser le mot clé override.

class Employee(name: String) extends Person(name) {
  def id = name.hashCode //无需override
}

9. Champ abstrait
En plus des méthodes abstraites, une classe peut également avoir un champ abstrait, un champ abstrait est un champ sans valeur initiale, tel que:

abstract class Person {
 val id: Int   //没有初始化,这是一个带有抽象的getter方法的抽象字段
 var name: String //另一个抽象字段,带有抽象getter和setter方法
}

Cette classe définit des méthodes getter abstraites pour les champs id et name et des méthodes setter abstraites pour le champ name. La classe Java générée n'a pas de champs.
Des sous-classes spécifiques doivent fournir des champs spécifiques, tels que:

class Employee(val id: Int) extends Person { //子类有具体的id属性
  var name = ""  //和具体点的name属性
} 

Comme pour les méthodes, le mot-clé override n'est pas requis lors de la réécriture du champ abstrait d'une superclasse dans une sous-classe.

10. Ordre de construction et définition
à l' avance Lorsque nous réécrivons val dans la sous-classe et que le constructeur dans la superclasse utilise également cette valeur, cela peut entraîner de mauvais résultats.
Par exemple, les animaux peuvent percevoir l'environnement, en supposant que l'animal par défaut peut voir 10 unités devant, alors nous pouvons:

class Creature {
  val range: Int = 10
  val env: Array[Int] = new Array[Int](range)
}
//但蚂蚁是近视的
class Ant extends Creature {
  override val range = 2
}

Nous allons maintenant faire face à un problème, la valeur de la plage est utilisée dans l'initialisation du constructeur de super classe, et le constructeur de super classe s'exécute avant le constructeur de sous-classe. Le processus spécifique est le suivant:
1. Le constructeur de Ant appelle le constructeur de Creature avant de faire sa propre construction.
2. Le constructeur de Creature définit son champ de portée à 10.
3. Afin d'initialiser le tableau env, le constructeur du créateur appelle l'évaluateur range ().
4. Cette méthode est réécrite pour afficher la valeur du champ de plage de la classe Ant (pas encore initialisé).
5. La méthode range renvoie 0 (il s'agit de la valeur initiale de tous les champs entiers lorsque l'espace est alloué à l'objet).
6. env est défini sur un tableau de longueur 0.
7. Le constructeur Ant continue de s'exécuter, définissant son champ de plage sur 2.
Bien que le champ de plage puisse sembler être 2, mais env est défini sur un tableau de longueur 0, la leçon ici est que la valeur de val ne doit pas être invoquée dans le constructeur.
En Java, lorsque vous appelez une méthode dans le constructeur de la superclasse, vous rencontrerez un problème similaire. La méthode appelée peut être réécrite par la sous-classe, de sorte qu'elle peut ne pas se comporter comme prévu. En fait, c'est le cœur du problème. Où, l'expression de plage appelle la méthode getter.
Il existe les solutions suivantes:
1. Déclarez val comme final. Sûr mais pas flexible.
2. Déclarez val comme paresseux dans la superclasse. Sûr mais pas efficace.
3. Utilisez la syntaxe prédéfinie dans la sous-classe.
Définissez la syntaxe à l'avance pour initialiser le champ val de la sous-classe avant l'exécution du constructeur de la superclasse:

class Ant extends {
  override val range = 2
} with Creature
A publié 14 articles originaux · Like1 · Visites 684

Je suppose que tu aimes

Origine blog.csdn.net/qq_33891419/article/details/103853826
conseillé
Classement