[JAVA] Ich habe Scala ~ [Klasse] ~ berührt

Introduction

image.png

Es ist eine direkte Migration des Dwango-Tutorials, in dem Sie es studieren, bearbeiten und durch Ihre eigenen Begriffe ersetzen.

Klasse

Lassen Sie uns nun über Klassendefinitionen in Scala sprechen. Bitte beachten Sie, dass davon ausgegangen wird, dass Sie die Java-Klasse kennen.

Klassendefinition

Klassen in Scala unterscheiden sich nur in Notation von Java-Sprachklassen. Die Klassendefinition von Scala hat folgende Form:


class <Name der Klasse> '(' (<Argumentname 1> : <Argumenttyp 1>, <Argumentname 2>: <Argumenttyp 2> ...)? ')' {
  (<Felddefinition> | <Methodendefinition> )*
}

Angenommen, Sie möchten einen Klassenpunkt definieren, der einen Punkt darstellt. Angenommen, Point besteht aus einem Feld x (Int-Typ) und einem Feld y (Int-Typ), die x-Koordinaten darstellen. Das Schreiben dieser Klasse Point in Scala sieht folgendermaßen aus:


class Point(_x: Int, _y: Int) {
  val x = _x
  val y = _y
}

Wenn Sie ein Feld mit demselben Namen wie das Konstruktorargument definieren und verfügbar machen möchten, können Sie es wie folgt kurz schreiben.

class Point(val x: Int, val y: Int)

Unmittelbar nach dem Klassennamen befindet sich eine Konstruktorargumentdefinition Mit val / var können Konstruktorargumente als Felder verfügbar gemacht werden Beachten Sie den Punkt. Zunächst verwendet Scala nur einen Konstruktor pro Klasse. Scala behandelt diesen Konstruktor speziell als primären Konstruktor. Obwohl es grammatikalisch möglich ist, mehrere Konstruktoren zu definieren, wird es in der Praxis selten verwendet. Wenn Sie eine Möglichkeit zum Erstellen mehrerer Objekte bereitstellen möchten, definieren Sie diese häufig als Apply-Methode eines Objekts.

Der zweite Punkt ist, dass, wenn Sie dem Argument des primären Konstruktors val / var hinzufügen, das Feld verfügbar gemacht wird und von außen zugegriffen werden kann. Beachten Sie, dass sich der Umfang der Argumente des primären Konstruktors auf die gesamte Klassendefinition erstreckt. Daher können Sie wie unten gezeigt direkt aus der Methodendefinition auf das Konstruktorargument verweisen.


class Point(val x: Int, val y: Int) {
  def +(p: Point): Point = {
    new Point(x + p.x, y + p.y)
  }
  override def toString(): String = "(" + x + ", " + y + ")"
}

Methodendefinition

Die + -Methodendefinition wurde bereits früher als Beispiel für die Methodendefinition aufgeführt, hat jedoch im Allgemeinen die folgende Form.

(private([this | <Paketnamen>])? | protected([<Paketnamen>])?)? def <Methodenname> '('
  (<Argumentname> :Argumenttyp(, Argumentname : <Argumenttyp>)*)?
')': <Rückgabetyp> = <Körper>

In der Praxis wird häufig die folgende Form unter Verwendung eines Blockausdrucks angenommen.


(private([this | <Paketnamen>])? | protected([<Paketnamen>])?)? def <Methodenname> '('
  (<Argumentname> :Argumenttyp(, Argumentname : <Argumenttyp>)*)?
')': <Rückgabetyp> = {
  (<Formel> (; | <Neue Zeile>)?)*
}

Dies ist nur dann der Fall, wenn der Methodenkörper aus einem Blockausdruck besteht und es keine dedizierte Syntax zum Einschließen der Methodendefinition in {} gibt.

Selbst wenn Sie den Rückgabetyp weglassen, wird der Typ außer in besonderen Fällen abgeleitet. Machen Sie es sich jedoch zur besseren Lesbarkeit zur Gewohnheit, den Rückgabetyp anzugeben. Mit private kann auf die Methode nur innerhalb dieser Klasse zugegriffen werden, und mit protected kann nur auf abgeleitete Klassen zugegriffen werden. Mit private [this] kann nur von demselben Objekt aus darauf zugegriffen werden. Wenn Sie einen privaten [Paketnamen] hinzufügen, können Sie nur von denjenigen aus zugreifen, die zu demselben Paket gehören, und wenn Sie einen geschützten [Paketnamen] hinzufügen, können Sie zusätzlich zu der abgeleiteten Klasse von allen Benutzern darauf zugreifen, die zu demselben Paket gehören. Wird sein. Wenn weder privat noch geschützt angehängt ist, wird die Methode als öffentlich betrachtet.

Verwenden wir die zuvor in REPL definierte Point-Klasse.


scala> class Point(val x: Int, val y: Int) {
     |   def +(p: Point): Point = {
     |     new Point(x + p.x, y + p.y)
     |   }
     |   override def toString(): String = "(" + x + ", " + y + ")"
     | }
defined class Point

scala> val p1 = new Point(1, 1)
p1: Point = (1, 1)

scala> val p2 = new Point(2, 2)
p2: Point = (2, 2)

scala> p1 + p2
res0: Point = (3, 3)

Methode mit mehreren Argumentlisten

Die Methode kann so definiert werden, dass sie mehrere Argumentlisten enthält:


(private([this | <Paketnamen>])? | protected([<Paketnamen>])?)? def <Methodenname> '('
  (<Argumentname> :Argumenttyp(, Argumentname : <Argumenttyp>)*)?
')'( '('
  (<Argumentname> :Argumenttyp(, Argumentname : <Argumenttyp>)*)?
')' )* : <Rückgabetyp> = <Körpertyp>

Methoden mit mehreren Argumentlisten können in Kombination mit der zuckerbeschichteten Syntax von Scala verwendet werden, um fließende APIs zu erstellen, die für die unten beschriebenen impliziten Parameter benötigt werden, oder um die Typinferenz zu unterstützen. .. Definieren wir eine Additionsmethode mit mehreren Argumentlisten.


scala> class Adder {
     |   def add(x: Int)(y: Int): Int = x + y
     | }
defined class Adder

scala> val adder = new Adder()
adder: Adder = Adder@55f0d6ee

scala> adder.add(2)(3)
res1: Int = 5

scala> val fun = adder.add(2) _
fun: Int => Int = $$Lambda$7309/854803072@56ddbb41

scala> fun(3)
res2: Int = 5

Methoden mit mehreren Argumentlisten werden in der Form obj.method (x) (y) anstelle der Form obj.method (x, y) aufgerufen. Sie können auch eine neue Funktion (Teilanwendung) erstellen, indem Sie nur das erste Argument wie im Beispiel unten anwenden.

Sie können auch eine Methode erstellen, die einfach mehrere Argumente enthält, ohne eine Liste mit mehreren Argumenten zu verwenden:


scala> class Adder {
     |   def add(x: Int, y: Int): Int = x + y
     | }
defined class Adder

scala> val adder = new Adder()
adder: Adder = Adder@2fb31283

scala> adder.add(2, 3)
res3: Int = 5

scala> val fun: Int => Int = adder.add(2, _)
fun: Int => Int = $$Lambda$7310/1712767810@7dbbe2d8

scala> fun(3)
res4: Int = 5

Felddefinition

Die Felddefinition lautet

(private([this | <Paketnamen>])? | protected([<Paketnamen>])?)? (val | var) <Feldname>: <Feldtyp> = <Initialisierungsformel>

Es hat die Form von. Wenn es val ist, ist es ein unveränderliches Feld, und wenn es var ist, ist es ein veränderliches Feld. Wenn privat hinzugefügt wird, kann auf das Feld nur innerhalb der Klasse zugegriffen werden, und wenn geschützt hinzugefügt wird, kann auf das Feld nur von der abgeleiteten Klasse der Klasse zugegriffen werden. Wenn Sie private [this] hinzufügen, kann nur von demselben Objekt aus darauf zugegriffen werden. Wenn Sie private [] hinzufügen, können Sie nur von demselben Paket aus zugreifen. Wenn Sie geschützte [Paketnamen] hinzufügen, können Sie zusätzlich von der abgeleiteten Klasse von allen zum selben Paket gehörenden Personen darauf zugreifen. Wenn weder privat noch geschützt angehängt ist, wird das Feld als öffentlich betrachtet. Der Zugriff auf Felder mit privatem [this] ist etwas schneller, da sie normalerweise direkten Zugriff auf Felder auf JVM-Ebene bieten. Sie sollten sich dessen bewusst sein, wenn Sie die Leistung auf einem feinen Niveau einstellen.

Abstraktes Mitglied

Zu diesem Zeitpunkt können Sie möglicherweise keine Implementierung schreiben, und Sie möchten möglicherweise beim Erben eine Implementierung einer Methode oder eines Felds angeben, die später beschrieben wird. Um solche Fälle zu behandeln, können Sie mit Scala abstrakte Elemente definieren. Abstrakte Mitglieder können Methoden oder Felder sein und für Methoden:


(private([this | <Paketnamen>])? | protected([<Paketnamen>])?)? def <Methodenname> '('
  (<Argumentname> :Argumenttyp(, Argumentname : <Argumenttyp>)*)?
')': <Rückgabetyp>

Die Felddefinition sieht folgendermaßen aus:


(private([this | <Paketnamen>])? | protected([<Paketnamen>])?)? (val | var) <Feldname>: <Feldtyp>

Es ist dasselbe wie eine normale Methode oder Felddefinition, außer dass es keinen Inhalt der Methode oder des Feldes gibt. Außerdem muss eine Klasse mit einer oder mehreren abstrakten Methoden als abstrakte Klasse deklariert werden. Beispielsweise wird eine abstrakte Klasse XY mit x- und y-Koordinaten wie folgt definiert: Der Punkt ist, dass Sie der Klasse den abstrakten Modifikator voranstellen müssen.


scala> abstract class XY {
     |   def x: Int
     |   def y: Int
     | }
defined class XY

Erbe

Scala-Klassen können genau wie Java-Klassen vererbt werden. Vererbung hat zwei Zwecke. Eine besteht darin, die Implementierung wiederzuverwenden, indem die Implementierung der Oberklasse in der Unterklasse durch Vererbung verwendet wird. Das andere ist, dass mehrere Unterklassen die Schnittstelle einer gemeinsamen Oberklasse erben, um die Verarbeitung zu standardisieren1. Es ist bekannt, dass die Implementierungsvererbung Probleme wie das Verhalten aufweist, wenn Methoden- und Feldnamen aufgrund mehrerer Vererbungen in Konflikt stehen, und Java die Implementierungsvererbung auf nur eine beschränkt. Java 8 ermöglicht Schnittstellen eine Standardimplementierung, jedoch mit der Einschränkung, dass Variablen dies nicht können. Scala verwendet einen Mechanismus namens Merkmale, um mehrere Implementierungen zu erben. Merkmale werden jedoch in einem separaten Abschnitt erläutert.

Dieser Abschnitt beschreibt die Vererbung normaler Scala-Klassen. Die Klassenvererbung in Scala hat die folgende Syntax:


class <Name der Klasse> <Klassenargument> (extends <Super Klasse>)? (with <Trate Name>)* {
  (<Felddefinition> | <Methodendefinition>)*
}

Der Name des Merkmals wird hier nicht verwendet, wird aber später im Abschnitt über das Merkmal erläutert. Die Vererbung funktioniert genauso wie Java-Klassen, außer dass Sie das Schlüsselwort override verwenden müssen, wenn Sie vorhandene Methoden überschreiben. Sie können beispielsweise Folgendes tun:


scala> class APrinter() {
     |   def print(): Unit = {
     |     println("A")
     |   }
     | }
defined class APrinter

scala> class BPrinter() extends APrinter {
     |   override def print(): Unit = {
     |     println("B")
     |   }
     | }
defined class BPrinter

scala> new APrinter().print
A

scala> new BPrinter().print
B

Wenn Sie das Überschreibungsschlüsselwort hier entfernen, wird die folgende Meldung ausgegeben und ein Kompilierungsfehler tritt auf.


scala> class BPrinter() extends APrinter {
     |   def print(): Unit = {
     |     println("B")
     |   }
     | }
<console>:14: error: overriding method print in class APrinter of type ()Unit;
 method print needs `override' modifier
         def print(): Unit = {
             ^

Java macht häufig den Fehler, eine neue Methode zu definieren, um eine vorhandene Methode unbemerkt zu überschreiben. Scala verwendet jedoch das Schlüsselwort override, um dieses Problem auf Sprachebene zu beheben.

Ende

Nächstes Mal werden wir Objekte untersuchen.

Referenz

Dieses Dokument ist CC BY-NC-SA 3.0

image.png Es wird unter verteilt.

https://dwango.github.io/scala_text/

Recommended Posts

Ich habe Scala ~ [Klasse] ~ berührt
Ich habe Scala berührt
Ich habe Scala ~ [Objekt] ~ berührt
Ich habe Scala ~ [Trate] ~ berührt
Ich habe Scala ~ [Steuerungssyntax] ~ berührt
Ich habe zuerst Java touched berührt
Ich habe zuerst Java touched berührt
Ich habe zuerst Java touched berührt
Ich habe Scala ~ [Typparameter und Verschiebungsspezifikation] ~ berührt
Ich habe zuerst Java berührt
Ich ging zur Scala Fukuoka 2019!
Ich habe einen Öko-Server mit Scala gemacht
Beachten Sie, dass ich SQLiteOpenHelper unter Android leicht berührt habe
Form Scala Fallklasse für einfache Anzeige
Ich habe ODM für Entwickler ② Regelentwicklung berührt