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:
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)
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.
class Greeter(prefix: String, suffix: String) {
def greet(name: String): Unit =
println(prefix + name + suffix)
}
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. .. ..
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 ...
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());
}
*/
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.
object IdFactory {
private var counter = 0
def create(): Int = {
counter += 1
counter
}
}
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.
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)
}
}
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.
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"
}
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.
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