Cet article est une communauté technique interne de Fujitsu Systems Web Technology, "Innovation Promotion Community" Ceci est l'article sur le 14ème jour du calendrier de l'Avent des vacances d'été d'Inobeko 2020, qui est prévu par "Inobeko" pour faire court. Le contenu de cet article est ma propre opinion et ne représente pas l'organisation à laquelle j'appartiens. Promesse à ce jour: wink:
Dans cet article, un programmeur Java qui a démarré Scala recompile le fichier de classe généré par la compilation de Scala. J'ai commencé à penser que je voulais comprendre Scala d'un point de vue Java.
Je voudrais procéder avec le flux de base comme suit.
C'est tout.
Parlons un peu du monde de Scala. Cette fois, je voudrais aborder le monde de Scala en utilisant l'édition "de base" de TOUR OF SCALA. (Il y a quelques problèmes de développement)
Les classes dans scala ont presque la même apparence que Java, mais avec des différences dans les paramètres du constructeur. Voyons également comment implémenter la surcharge en fonction d'un exemple.
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
Il semble qu'il stocke les méta-informations lors de sa compilation. Il y avait un article dans qiita qui confirmait comment mettre en œuvre le scellé. https://qiita.com/ocadaruma/items/93818bd1a5318e71f0d8
Je ne sais pas si c'est quelque chose que vous voulez savoir, mais c'est pour ça. .. ..
Les arguments «prefix: String, suffix: String» ont été définis comme champs «private final».
val
(ne peut pas être changé) par défaut.En guise de test, si vous écrivez le paramètre constructeur en tant que paramètre var
, ce sera comme suit.
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());
}
}
Vous pouvez voir que le final
a disparu et que la méthode getter (prefix (), suffix ()) et la méthode setter ($ eq) sont générées.
Lorsque vous appelez à partir du code scala, il semble que vous puissiez obtenir et définir le préfixe normalement, mais lorsque vous appelez à partir du code Java, cela semble être field name_ $ eq
.
C'est compliqué ...
Dans la méthode greet, les chaînes ont été concaténées avec la méthode +
(dans scala, +
est également traitée comme une méthode!). Cependant, lorsque je regarde le résultat de la compilation inversée, j'utilise StringBuilder pour concaténer les chaînes. Quoi! Intelligent!
Si vous allez combiner des chaînes dans du code Java et le traiter, il ne fait aucun doute que cela sera écrit dans le tableau de révision ** "Veuillez utiliser StringBuilder: angry:", mais dans le cas de Scala c'est Ne t'inquiète pas.
Le résultat de la réécriture en Java et de la décompilation est le suivant.
JavaGreeeter.java
//Code précompilé
//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);
}
}
Il semble qu'il soit conçu pour combiner simplement des chaînes. Peut-être que Scala traite également tous les opérateurs comme des fonctions. J'imagine que la méthode + de String elle-même est probablement en train d'utiliser StringBuilder (peut-être que scalac est censé l'interpréter avec StringBuilder ...).
Même si vous utilisez des littéraux, il semble que StringBuilder sera utilisé de la même manière.
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());
}
*/
Vient ensuite ʻobject`. Ce n'est pas le java.lang.Object de Java. L '«objet» de Scala correspond-il au modèle Singleton en Java? La syntaxe est la suivante.
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();
}
}
Quoi! La classe anonyme est prête.
Probablement, il se compose d'un objet Singleton ʻIdFactory $ et d'une classe ʻIdFactory
qui l'appelle. Y a-t-il une raison d'être séparé? C'est la fin de ce temps, pensant qu'il y a quelque chose à faire dans mon étude.
Le document officiel indique également que plus tard sera traité en détail, donc j'attends cela avec impatience.
trait
Qu'est-ce qu'un trait? C'est comme une interface, mais il semble qu'elle puisse avoir des champs, être implémentée par défaut ou hériter (mixin) de plusieurs traits.
Ici, créons un trait et créons une classe héritée pour voir quel type de classe est créé.
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)
}
}
Cette fois, un total de 3 fichiers de classe ont été créés. Dans le cas de Java, il n'est pas possible de créer plusieurs classes publiques dans un même code source Java, il a donc été divisé en plusieurs.
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());
}
}
le trait est maintenant l'interface
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);
}
}
C'est sous la forme d'appeler l'implémentation par défaut de l'interface.
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());
}
}
Il semble qu'il remplace simplement l'implémentation implémentée. Eh bien, c'est prévu.
mixin
Scala vous permet de synthétiser plusieurs classes en utilisant mixin. Java ne peut pas hériter de plusieurs classes ou interfaces, il peut hériter d'une seule classe parente.
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();
}
Apparemment, définir un champ dans un trait crée implicitement une méthode dans l'interface qui équivaut au nom du champ. Ainsi, il semble que le trait se réalise en définissant l'état réel de la méthode qui acquiert le champ dans la classe de la destination de synthèse.
Le but de la rédaction de l'article était de comprendre le fonctionnement de Scala, mais les programmeurs Java pourraient trouver Scala un peu mieux! J'en suis venu à penser que ce serait l'occasion pour les gens de réfléchir. C'est un langage avec une longue histoire, mais je pense que c'est un langage très attrayant car il a de nombreuses nouvelles fonctionnalités que les programmeurs Java veulent voir.
J'espère créer une opportunité de reconsidérer Scala dans une perspective Java de la même manière que je continue à étudier.
Recommended Posts