Einführung in Scala aus Java-Perspektive (grundlegend)

Dieser Artikel ist eine interne technische Community von Fujitsu Systems Web Technology, "Community für Innovationsförderung". Dies ist der Artikel am 14. Tag des Inobeko-Sommerferien-Adventskalenders 2020, der kurz von "Inobeko" geplant ist. Der Inhalt dieses Artikels ist meine eigene Meinung und repräsentiert nicht die Organisation, zu der ich gehöre. Versprechen bisher: zwinker:

Einführung

In diesem Artikel kompiliert ein Java-Programmierer, der Scala gestartet hat, die durch das Kompilieren von Scala generierte Klassendatei rückwärts. Ich begann zu denken, dass ich Scala aus einer Java-Perspektive verstehen wollte.

Ich möchte mit dem Grundablauf wie folgt fortfahren.

Das ist es.

Lassen Sie uns ein wenig auf die Welt von Scala eingehen. Dieses Mal möchte ich die Welt von Scala mit der "Basic" Edition von TOUR OF SCALA berühren. (Es gibt einige Entwicklungsprobleme)

Klasse

Klassen in Scala sehen fast genauso aus wie Java, jedoch mit Unterschieden in den Konstruktorparametern. Überprüfen wir außerdem anhand des Beispiels, wie eine Überlastung implementiert wird.

Beispielcode

class Greeter(prefix: String, suffix: String) {
  def greet(name: String): Unit =
    println(prefix + name + suffix)
}

Nach der Dekompilierung

package com.github.fishibashi.scaladecompile;

import scala.Predef$;
import scala.reflect.ScalaSignature;

@ScalaSignature(bytes = "\006\005A2A!\002\004\001\037!Aa\003\001B\001B\003%q\003\003\005#\001\t\005\t\025!\003\030\021\025\031\003\001\"\001%\021\025I\003\001\"\001+\005\0359%/Z3uKJT!a\002\005\002\035M\034\027\r\\1eK\016|W\016]5mK*\021\021BC\001\013M&\034\b.\0332bg\"L'BA\006\r\003\0319\027\016\0365vE*\tQ\"A\002d_6\034\001a\005\002\001!A\021\021\003F\007\002%)\t1#A\003tG\006d\027-\003\002\026%\t1\021I\\=SK\032\fa\001\035:fM&D\bC\001\r \035\tIR\004\005\002\033%5\t1D\003\002\035\035\0051AH]8pizJ!A\b\n\002\rA\023X\rZ3g\023\t\001\023E\001\004TiJLgn\032\006\003=I\taa];gM&D\030A\002\037j]&$h\bF\002&O!\002\"A\n\001\016\003\031AQAF\002A\002]AQAI\002A\002]\tQa\032:fKR$\"a\013\030\021\005Ea\023BA\027\023\005\021)f.\033;\t\013=\"\001\031A\f\002\t9\fW.\032")
public class Greeter {
  private final String prefix;
  
  private final String suffix;
  
  public Greeter(String prefix, String suffix) {}
  
  public void greet(String name) {
    Predef$.MODULE$.println((new StringBuilder(0)).append(this.prefix).append(name).append(this.suffix).toString());
  }
}

ScalaSignature

Es scheint, dass es die Metainformationen speichert, als es kompiliert wurde. Es gab einen Artikel in Qiita, der bestätigte, wie versiegelt zu implementieren ist. https://qiita.com/ocadaruma/items/93818bd1a5318e71f0d8

Ich weiß nicht, ob es etwas ist, das Sie wissen wollen, aber es ist dafür. .. ..

Konstruktorargumente

Die Argumente Präfix: String, Suffix: String wurden als private final Felder definiert.

Wenn Sie als Test den Konstruktorparameter als "var" -Parameter schreiben, ist dies wie folgt.

class Greeter(var prefix: String, var suffix: String) {
  def greet(name: String): Unit =
    println(prefix + name + suffix)
}
public class Greeter {
  private String prefix;
  
  private String suffix;
  
  public String prefix() {
    return this.prefix;
  }
  
  public void prefix_$eq(String x$1) {
    this.prefix = x$1;
  }
  
  public String suffix() {
    return this.suffix;
  }
  
  public void suffix_$eq(String x$1) {
    this.suffix = x$1;
  }
  
  public Greeter(String prefix, String suffix) {}
  
  public void greet(String name) {
    Predef$.MODULE$.println((new StringBuilder(0)).append(prefix()).append(name).append(suffix()).toString());
  }
}

Sie können sehen, dass das final weg ist und die Getter-Methode (Präfix (), Suffix ()) und die Setter-Methode ($ eq) generiert werden. Wenn Sie aus Scala-Code aufrufen, können Sie das Präfix normalerweise abrufen und festlegen. Beim Aufrufen aus Java-Code scheint es sich jedoch um "Feldname_ $ eq" zu handeln. Es ist kompliziert ...

Begrüßungsmethode

Bei der greet-Methode wurden die Zeichenfolgen mit der + Methode verkettet (in scala wird + auch als Methode behandelt!). Wenn ich mir jedoch das Ergebnis der umgekehrten Kompilierung anschaue, verwende ich StringBuilder und verkette die Zeichenfolgen. Was! Clever! Wenn Sie Zeichenfolgen in Java-Code kombinieren und verarbeiten möchten, besteht kein Zweifel daran, dass ** "StringBuilder verwenden: wütend:" in die Überprüfungstabelle geschrieben wird, im Fall von Scala jedoch Mach dir keine Sorgen.

Das Ergebnis des Umschreibens in Java und des Dekompilierens ist wie folgt.

JavaGreeeter.java


//Vorkompilierter Code
//public class JavaGreeter {
//    private final String prefix;
//
//    private final String suffix;
//
//    public JavaGreeter(String prefix, String suffix) {
//        this.prefix = prefix;
//        this.suffix = suffix;
//    }
//
//    public String greet(String name) {
//        return prefix + name + suffix;
//    }
//}

import scala.Predef$;

public class JavaGreeter {
  private final String prefix;
  
  private final String suffix;
  
  public JavaGreeter(String prefix, String suffix) {
    this.prefix = prefix;
    this.suffix = suffix;
  }
  
  public void greet(String name) {
    Predef$.MODULE$.println(this.prefix + this.prefix + name);
  }
}

Es scheint, dass es entworfen wurde, um einfach Saiten zu kombinieren. Vielleicht behandelt Scala auch alle Operatoren als Funktionen. Ich stelle mir vor, dass die + -Methode von String selbst wahrscheinlich StringBuilder verwendet (vielleicht soll Scalac sie mit StringBuilder interpretieren ...).

Selbst wenn Sie Literale verwenden, wird StringBuilder anscheinend auf die gleiche Weise verwendet.

  def greet(name: String): Unit =
    println(s"${prefix} ${name} ${suffix}")
  /**
    public void greet(String name) {
      Predef$.MODULE$.println((new StringBuilder(2)).append(prefix()).append(" ").append(name).append(" ").append(suffix()).toString());
    }
   */

Objekt

Als nächstes kommt "Objekt". Es ist nicht Javas java.lang.Object. Entspricht Scalas "Objekt" dem Singleton-Muster in Java? Die Syntax lautet wie folgt.

Beispielcode

object IdFactory {
  private var counter = 0
  def create(): Int = {
    counter += 1
    counter
  }
}

Nach der Dekompilierung

IdFactory.class


@ScalaSignature(bytes = "\006\0051:Qa\002\005\t\002E1Qa\005\005\t\002QAQaG\001\005\002qAq!H\001A\002\023%a\004C\004#\003\001\007I\021B\022\t\r%\n\001\025)\003 \021\025Q\023\001\"\001,\003%IEMR1di>\024\030P\003\002\n\025\005q1oY1mC\022,7m\\7qS2,'BA\006\r\003)1\027n\0355jE\006\034\b.\033\006\003\0339\taaZ5uQV\024'\"A\b\002\007\r|Wn\001\001\021\005I\tQ\"\001\005\003\023%#g)Y2u_JL8CA\001\026!\t1\022$D\001\030\025\005A\022!B:dC2\f\027B\001\016\030\005\031\te.\037*fM\0061A(\0338jiz\"\022!E\001\bG>,h\016^3s+\005y\002C\001\f!\023\t\tsCA\002J]R\f1bY8v]R,'o\030\023fcR\021Ae\n\t\003-\025J!AJ\f\003\tUs\027\016\036\005\bQ\021\t\t\0211\001 \003\rAH%M\001\tG>,h\016^3sA\00511M]3bi\026$\022a\b")
public final class IdFactory {
  public static int create() {
    return IdFactory$.MODULE$.create();
  }
}

IdFactory$.class


public final class IdFactory$ {
  public static final IdFactory$ MODULE$ = new IdFactory$();
  
  private static int counter = 0;
  
  private int counter() {
    return counter;
  }
  
  private void counter_$eq(int x$1) {
    counter = x$1;
  }
  
  public int create() {
    counter_$eq(counter() + 1);
    return counter();
  }
}

Was! Die anonyme Klasse ist bereit.

Wahrscheinlich besteht es aus einem Singleton-Objekt, "IdFactory $", und einer "IdFactory" -Klasse, die es aufruft. Gibt es einen Grund, getrennt zu werden? Dies ist das Ende dieser Zeit, da ich denke, dass ich mit meinem Studium fortfahren kann. Das offizielle Dokument besagt auch, dass später ausführlich behandelt wird, also freue ich mich darauf.

trait

Was ist ein Merkmal? Es ist wie eine Schnittstelle, aber es scheint, dass sie Felder haben kann, standardmäßig implementiert werden kann oder mehrere Merkmale erben (mischen) kann.

Hier erstellen wir ein Merkmal und eine geerbte Klasse, um zu sehen, welche Art von Klasse erstellt wird.

Beispielcode

trait Greeter {
  def greet(name: String): Unit =
    println("Hello, " + name + "!")
}

class DefaultGreeter extends Greeter

class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
  override def greet(name: String): Unit = {
    println(prefix + name + postfix)
  }
}

Nach der Dekompilierung

Dieses Mal wurden insgesamt 3 Klassendateien erstellt. Im Fall von Java ist es nicht möglich, mehrere öffentliche Klassen in einem Java-Quellcode zu erstellen, daher wurde es in mehrere unterteilt.

Greeter.java


@ScalaSignature(bytes = "\006\005!2qa\001\003\021\002\007\005Q\002C\003\025\001\021\005Q\003C\003\032\001\021\005!DA\004He\026,G/\032:\013\005\0251\021AD:dC2\fG-Z2p[BLG.\032\006\003\017!\t!BZ5tQ&\024\027m\0355j\025\tI!\"\001\004hSRDWO\031\006\002\027\005\0311m\\7\004\001M\021\001A\004\t\003\037Ii\021\001\005\006\002#\005)1oY1mC&\0211\003\005\002\007\003:L(+\0324\002\r\021Jg.\033;%)\0051\002CA\b\030\023\tA\002C\001\003V]&$\030!B4sK\026$HC\001\f\034\021\025a\"\0011\001\036\003\021q\027-\\3\021\005y)cBA\020$!\t\001\003#D\001\"\025\t\021C\"\001\004=e>|GOP\005\003IA\ta\001\025:fI\0264\027B\001\024(\005\031\031FO]5oO*\021A\005\005")
public interface Greeter {
  static void $init$(Greeter $this) {}
  
  default void greet(String name) {
    Predef$.MODULE$.println((new StringBuilder(8)).append("Hello, ").append(name).append("!").toString());
  }
}

Merkmal ist jetzt Schnittstelle

DefaultGreeter.java


@ScalaSignature(bytes = "\006\005i1AAA\002\001\031!)q\003\001C\0011\tqA)\0324bk2$xI]3fi\026\024(B\001\003\006\0039\0318-\0317bI\026\034w.\0349jY\026T!AB\004\002\025\031L7\017[5cCND\027N\003\002\t\023\0051q-\033;ik\nT\021AC\001\004G>l7\001A\n\004\0015\031\002C\001\b\022\033\005y!\"\001\t\002\013M\034\027\r\\1\n\005Iy!AB!osJ+g\r\005\002\025+5\t1!\003\002\027\007\t9qI]3fi\026\024\030A\002\037j]&$h\bF\001\032!\t!\002\001")
public class DefaultGreeter implements Greeter {
  public void greet(String name) {
    Greeter.greet$(this, name);
  }
  
  public DefaultGreeter() {
    Greeter.$init$(this);
  }
}

Dies erfolgt in Form eines Aufrufs der Standardimplementierung der Schnittstelle.

python


@ScalaSignature(bytes = "\006\005M2A!\002\004\001\037!A!\004\001B\001B\003%1\004\003\005'\001\t\005\t\025!\003\034\021\0259\003\001\"\001)\021\025a\003\001\"\021.\005M\031Uo\035;p[&T\030M\0317f\017J,W\r^3s\025\t9\001\"\001\btG\006d\027\rZ3d_6\004\030\016\\3\013\005%Q\021A\0034jg\"L'-Y:iS*\0211\002D\001\007O&$\b.\0362\013\0035\t1aY8n\007\001\0312\001\001\t\027!\t\tB#D\001\023\025\005\031\022!B:dC2\f\027BA\013\023\005\031\te.\037*fMB\021q\003G\007\002\r%\021\021D\002\002\b\017J,W\r^3s\003\031\001(/\0324jqB\021Ad\t\b\003;\005\002\"A\b\n\016\003}Q!\001\t\b\002\rq\022xn\034;?\023\t\021##\001\004Qe\026$WMZ\005\003I\025\022aa\025;sS:<'B\001\022\023\003\035\001xn\035;gSb\fa\001P5oSRtDcA\025+WA\021q\003\001\005\0065\r\001\ra\007\005\006M\r\001\raG\001\006OJ,W\r\036\013\003]E\002\"!E\030\n\005A\022\"\001B+oSRDQA\r\003A\002m\tAA\\1nK\002")
public class CustomizableGreeter implements Greeter {
  private final String prefix;
  
  private final String postfix;
  
  public CustomizableGreeter(String prefix, String postfix) {
    Greeter.$init$(this);
  }
  
  public void greet(String name) {
    Predef$.MODULE$.println((new StringBuilder(0)).append(this.prefix).append(name).append(this.postfix).toString());
  }
}

Es scheint, dass es nur die implementierte Implementierung überschreibt. Nun, es wird erwartet.

mixin

Mit Scala können Sie mehrere Klassen mit Mixin synthetisieren. Java kann nicht mehrere Klassen oder Schnittstellen erben, sondern eine einzelne übergeordnete Klasse.

Beispielcode mit Mixin

Mixin.scala


abstract class BaseMixinSample(val prefix: String, val suffix: String) {
  def greet(name: String): Unit = println(prefix + name + suffix)
}

trait TraitA {
  val a: String
  def A(): Unit = println("A")
}

trait TraitB {
  val b: String
  def B(): Unit = println("B")
}

class DefaultMixinSample() extends BaseMixinSample("Hello", "!") with TraitA with TraitB {
  override def greet(name: String): Unit = super.greet(name)

  override val a: String = "Value is A"
  override val b: String = "Value is B"
}

Nach der Dekompilierung


import scala.Predef$;
import scala.reflect.ScalaSignature;

@ScalaSignature(bytes = "\006\005U2Qa\002\005\002\002EA\001\002\007\001\003\006\004%\t!\007\005\tK\001\021\t\021)A\0055!Aa\005\001BC\002\023\005\021\004\003\005(\001\t\005\t\025!\003\033\021\025A\003\001\"\001*\021\025q\003\001\"\0010\005=\021\025m]3NSbLgnU1na2,'BA\005\013\0039\0318-\0317bI\026\034w.\0349jY\026T!a\003\007\002\025\031L7\017[5cCND\027N\003\002\016\035\0051q-\033;ik\nT\021aD\001\004G>l7\001A\n\003\001I\001\"a\005\f\016\003QQ\021!F\001\006g\016\fG.Y\005\003/Q\021a!\0218z%\0264\027A\0029sK\032L\0070F\001\033!\tY\"E\004\002\035AA\021Q\004F\007\002=)\021q\004E\001\007yI|w\016\036 \n\005\005\"\022A\002)sK\022,g-\003\002$I\t11\013\036:j]\036T!!\t\013\002\017A\024XMZ5yA\00511/\0364gSb\fqa];gM&D\b%\001\004=S:LGO\020\013\004U1j\003CA\026\001\033\005A\001\"\002\r\006\001\004Q\002\"\002\024\006\001\004Q\022!B4sK\026$HC\001\0314!\t\031\022'\003\0023)\t!QK\\5u\021\025!d\0011\001\033\003\021q\027-\\3")
public abstract class BaseMixinSample {
  private final String prefix;
  
  private final String suffix;
  
  public String prefix() {
    return this.prefix;
  }
  
  public String suffix() {
    return this.suffix;
  }
  
  public BaseMixinSample(String prefix, String suffix) {}
  
  public void greet(String name) {
    Predef$.MODULE$.println((new StringBuilder(0)).append(prefix()).append(name).append(suffix()).toString());
  }
}

public class DefaultMixinSample extends BaseMixinSample implements TraitA, TraitB {
  public void B() {
    TraitB.B$(this);
  }
  
  public void A() {
    TraitA.A$(this);
  }
  
  public DefaultMixinSample() {
    super("Hello", "!");
    TraitA.$init$(this);
    TraitB.$init$(this);
  }
  
  public void greet(String name) {
    super.greet(name);
  }
  
  public static void test() {
    DefaultMixinSample$.MODULE$.test();
  }
}

public interface TraitA {
  static void $init$(TraitA $this) {}
  
  default void A() {
    Predef$.MODULE$.println("A");
  }
  
  String a();
}

public interface TraitB {
  static void $init$(TraitB $this) {}
  
  default void B() {
    Predef$.MODULE$.println("B");
  }
  
  String b();
}

Anscheinend wird durch das implizite Definieren eines Felds in einem Merkmal eine Methode in der Schnittstelle erstellt, die dem Feldnamen entspricht. Es scheint also, dass das Merkmal realisiert wird, indem der tatsächliche Zustand der Methode definiert wird, die das Feld in der Klasse des Syntheseziels erfasst.

Schließlich

Der Zweck des Artikels war es zu verstehen, wie Scala funktioniert, aber Java-Programmierer finden Scala möglicherweise etwas besser! Ich kam zu dem Schluss, dass dies eine Gelegenheit für die Menschen sein würde, nachzudenken. Es ist eine Sprache mit einer langen Geschichte, aber ich denke, es ist eine sehr attraktive Sprache, weil sie viele neue Funktionen hat, die Java-Programmierer sehen möchten.

Ich hoffe, eine Gelegenheit zu schaffen, Scala aus einer Java-Perspektive zu überdenken, so wie ich weiter studiere.

Recommended Posts

Einführung in Scala aus Java-Perspektive (grundlegend)
Wie schreibe ich Scala aus der Perspektive von Java
[Einführung in Java] So schreiben Sie ein Java-Programm
Einführung in die Überwachung von Java Touching Prometheus
[Einführung in Java] Informationen zu Variablendeklarationen und -typen
[Java] Einführung in Java
Einführung in Java
Stellen Sie über eine Java-Anwendung eine Verbindung zu Aurora (MySQL) her
Um ein VB.net-Programmierer aus einem Java-Shop zu werden
Erstellen Sie Scala Seq aus Java, machen Sie Scala Seq zu einer Java-Liste
Konvertieren Sie Java Enum Enumeration und JSON von und nach Jackson
Änderungen von Java 8 zu Java 11
Summe von Java_1 bis 100
So springen Sie von Eclipse Java zu einer SQL-Datei
Java-Sprache aus der Sicht von Kotlin und C #
6 Funktionen, die ich nach meiner Rückkehr von Scala nach Java verpasst habe
Von Java zu Ruby !!
[Java] So löschen Sie ein bestimmtes Zeichen aus einer Zeichenfolge
Einführung in den Java-Befehl
Einführung in effektives Java durch Üben und Lernen (Builder-Muster)
Weisen Sie Variablen Java8-Lambda-Ausdrücke zu und verwenden Sie sie erneut
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich möchte eine Funktion mit Kotlin und Java erstellen!
Speichern von Zeichenfolgen von ArrayList zu Zeichenfolge in Java (Personal)
So entwickeln und registrieren Sie eine Sota-App in Java
ClassCastException tritt bei der Migration von Java7 auf Java8 auf. ~ Generics and overload ~
Schauen Sie sich Kotlin aus einer effektiven Java-Perspektive an
Migration von Cobol nach JAVA
Neue Funktionen von Java7 bis Java8
Stellen Sie eine Verbindung von Java zu PostgreSQL her
[Java] Einführung in die Stream-API
[Einführung in Janken (ähnliche) Spiele] Java
Konvertieren Sie Excel mit Java in Blob, speichern Sie es, lesen Sie es aus der Datenbank und geben Sie es als Datei aus!
[Einführung in Java] Informationen zu Variablen und Typen (Variablendeklaration, Initialisierung, Datentyp)
Herstellen einer Verbindung zu einer Datenbank mit Java (Teil 1) Möglicherweise die grundlegende Methode
Hinweise zum Erstellen der Kotlin-Entwicklungsumgebung und zur Migration von Java nach Kotlin
Vom jungen Java (3 Jahre) bis zu Node.js (4 Jahre). Und der Eindruck, nach Java zurückzukehren
[Swift5] So kommunizieren Sie von ViewController zu Model und übergeben einen Wert
[Java] So konvertieren Sie vom Typ String in den Pfadtyp und erhalten den Pfad
[Einführung in Java] Über Lambda-Ausdrücke
[Java] Grundtypen und Anweisungshinweise
[Einführung in Java] Informationen zur Stream-API
So erstellen Sie einen Java-Container
Einführung in die funktionale Programmierung (Java, Javascript)
Verwenden Sie JDBC mit Java und Scala.
Führen Sie eine Batchdatei von Java aus
Greifen Sie über eine Java-Anwendung auf Teradata zu
Java soll ab heute dabei sein
Von Java zu VB.NET-Writing Kontrastmemo-
Einführung in Ruby (aus anderen Sprachen)
Erste Einführung in Mac (Java-Ingenieur)
Java, Schnittstelle für Anfänger
Von der Einführung bis zur Verwendung von byebug
Java-Basisdatentypen und Referenztypen
Der Weg von JavaScript nach Java