/ / स्कैला लक्षण जावा बाइटकोड में कैसे संकलित हैं? - स्केला, बायटेकोड

जावा बाइटकोड में संकलित स्केल लक्षण कैसे हैं? - स्कैला, बाइटकोड

मैंने अभी कुछ समय तक स्काला के साथ खेला है, और मुझे पता है कि लक्षण स्कैला के रूप में दोनों इंटरफेस और अमूर्त कक्षाओं के बराबर कार्य कर सकते हैं। वास्तव में कैसे लक्षण जावा बाइटकोड में संकलित किए जाते हैं?

मैंने कहा कि कुछ छोटे स्पष्टीकरण मिलेलक्षण बिल्कुल जावा इंटरफेस की तरह संकलित किए जाते हैं, और अन्यथा एक अतिरिक्त वर्ग के साथ इंटरफेस। मैं अब भी नहीं समझता, कि स्केला वर्ग रेखीयकरण कैसे प्राप्त करता है, जावा में एक सुविधा उपलब्ध नहीं है।

वहाँ एक अच्छा स्रोत बता रहा है कि कैसे लक्षण जावा बाइटकोड को संकलित करते हैं?

उत्तर:

उत्तर № 1 के लिए 64

मैं एक विशेषज्ञ नहीं हूँ, लेकिन यहाँ मेरी समझ है:

लक्षण एक अंतरफलक और इसी वर्ग में संकलित किए जाते हैं।

trait Foo {
def bar = { println("bar!") }
}

के बराबर हो जाता है ...

public interface Foo {
public void bar();
}

public class Foo$class {
public static void bar(Foo self) { println("bar!"); }
}

जो सवाल छोड़ देता है: फू $ क्लास में स्टेटिक बार पद्धति को कैसे कहा जाता है? इस मैजिक को कंपाइलर द्वारा उस वर्ग में किया जाता है जिसमें फू ट्रेट को मिलाया जाता है।

class Baz extends Foo

कुछ ऐसा हो जाता है ...

public class Baz implements Foo {
public void bar() { Foo$class.bar(this); }
}

कक्षा रैखिककरण सिर्फ लागू करता हैभाषा विनिर्देश में परिभाषित रैखिककरण नियमों के अनुसार विधि का उपयुक्त संस्करण (Xxxx $ वर्ग वर्ग में स्थैतिक विधि को कॉल करना)।


जवाब के लिए 4 № 2

चर्चा के लिए, आइए निम्न स्केल उदाहरण को अमूर्त और ठोस दोनों तरीकों के साथ कई लक्षणों का उपयोग करते हुए देखें:

trait A {
def foo(i: Int) = ???
def abstractBar(i: Int): Int
}

trait B {
def baz(i: Int) = ???
}

class C extends A with B {
override def abstractBar(i: Int) = ???
}

फिलहाल (यानी स्केला 2.11 के रूप में), एक एकल विशेषता के रूप में एन्कोड किया गया है:

  • एक interface के लिए सार घोषणाओं से युक्त सब विशेषता के तरीके (अमूर्त और ठोस दोनों)
  • एक सार स्थिर वर्ग जिसमें सभी लक्षणों के ठोस तरीके हैं, एक अतिरिक्त पैरामीटर ले रहे हैं $this (स्काला के पुराने संस्करणों में, यह वर्ग "टी एब्सट्रैक्ट" नहीं था, लेकिन यह इसे तात्कालिक बनाने के लिए कोई मतलब नहीं है)
  • वंशानुक्रम पदानुक्रम के प्रत्येक बिंदु पर जहां विशेषता को मिलाया जाता है, विशेषता में सभी ठोस तरीकों के लिए सिंथेटिक फारवर्डर विधियों जो स्थैतिक वर्ग के स्थिर तरीकों के लिए आगे हैं

इस एन्कोडिंग का प्राथमिक लाभ यह है कि ठोस सदस्यों के बिना एक विशेषता (जो एक इंटरफ़ेस के लिए आइसोमॉर्फिक है) वास्तव में है एक अंतरफलक के लिए संकलित।

interface A {
int foo(int i);
int abstractBar(int i);
}

abstract class A$class {
static void $init$(A $this) {}
static int foo(A $this, int i) { return ???; }
}

interface B {
int baz(int i);
}

abstract class B$class {
static void $init$(B $this) {}
static int baz(B $this, int i) { return ???; }
}

class C implements A, B {
public C() {
A$class.$init$(this);
B$class.$init$(this);
}

@Override public int baz(int i) { return B$class.baz(this, i); }
@Override public int foo(int i) { return A$class.foo(this, i); }
@Override public int abstractBar(int i) { return ???; }
}

हालाँकि, Scala 2.12 के लिए Java 8 की आवश्यकता होती है, और इस प्रकार इंटरफेस में डिफ़ॉल्ट विधियों और स्थिर विधियों का उपयोग करने में सक्षम होता है, और परिणाम इस तरह दिखता है:

interface A {
static void $init$(A $this) {}
static int foo$(A $this, int i) { return ???; }
default int foo(int i) { return A.foo$(this, i); };
int abstractBar(int i);
}

interface B {
static void $init$(B $this) {}
static int baz$(B $this, int i) { return ???; }
default int baz(int i) { return B.baz$(this, i); }
}

class C implements A, B {
public C() {
A.$init$(this);
B.$init$(this);
}

@Override public int abstractBar(int i) { return ???; }
}

जैसा कि आप देख सकते हैं, स्थैतिक के साथ पुराने डिजाइनविधियों और फ़ॉरवर्डरों को बनाए रखा गया है, वे केवल इंटरफ़ेस में बदल जाते हैं। विशेषता के ठोस तरीकों को अब इंटरफ़ेस में ही ले जाया गया है static तरीकों, फारवर्डर तरीकों से हर वर्ग में संश्लेषित नहीं किया जाता है लेकिन एक बार के रूप में परिभाषित किया गया है default विधियाँ, और स्थैतिक $init$ विधि (जो विशेषता शरीर में कोड का प्रतिनिधित्व करती है) को इंटरफ़ेस में भी स्थानांतरित कर दिया गया है, जिससे साथी स्थिर वर्ग अनावश्यक हो गया है।

इसे शायद इस तरह सरल बनाया जा सकता है:

interface A {
static void $init$(A $this) {}
default int foo(int i) { return ???; };
int abstractBar(int i);
}

interface B {
static void $init$(B $this) {}
default int baz(int i) { return ???; }
}

class C implements A, B {
public C() {
A.$init$(this);
B.$init$(this);
}

@Override public int abstractBar(int i) { return ???; }
}

मुझे यकीन नहीं है कि यह क्यों नहीं किया गया। पहली नज़र में, वर्तमान एन्कोडिंग हमें थोड़ा आगे-संगतता दे सकती है: आप एक पुराने संकलक द्वारा संकलित कक्षाओं के साथ एक नए संकलक के साथ संकलित लक्षणों का उपयोग कर सकते हैं, उन पुरानी कक्षाएं बस ओवरराइड कर सकती हैं। default फारवर्डर विधियां वे इंटरफ़ेस से विरासत में मिलते-जुलते हैं। सिवाय, फारवर्डर विधियों पर स्थिर विधियों को कॉल करने का प्रयास करेंगे A$class तथा B$class जो अब अस्तित्व में नहीं है, ताकि काल्पनिक आगे-संगतता अनुकूलता वास्तव में काम न करे।


उत्तर № 3 के लिए 1

इसकी एक बहुत अच्छी व्याख्या इस प्रकार है:

व्यस्त जावा डेवलपर के स्काला के लिए गाइड: लक्षण और व्यवहार - जेवीएम में लक्षण

उद्धरण:

इस मामले में, यह [संकलक] विशेषता कार्यान्वयन और फ़ील्ड घोषणाओं को विशेषता में वर्ग में परिभाषित करता है जो विशेषता को लागू करता है


जवाब के लिए 0 № 4

स्केल 12 और जावा 8 के संदर्भ में, आप एक और स्पष्टीकरण देख सकते हैं 8020cd6 कमिट करें:

2.12 विशेषता एन्कोडिंग के लिए बेहतर इनलाइनर समर्थन

विशेषता एन्कोडिंग में कुछ बदलाव देर से 2.12 चक्र में आए, और इनलाइनर को सर्वोत्तम संभव तरीके से समर्थन करने के लिए अनुकूलित नहीं किया गया था।

2.12.0 में ठोस विशेषता विधियों को इनकोड किया गया है

interface T {
default int m() { return 1 }
static int m$(T $this) { <invokespecial $this.m()> }
}
class C implements T {
public int m() { return T.m$(this) }
}

यदि एक विशेषता विधि को इनलाइनिंग के लिए चुना जाता है, तो 2.12.0 इनलाइनर होगा अपने शरीर को स्थिर सुपर एक्सेसर में कॉपी करें T.m$, और वहाँ से में मिश्रण फारवर्डर C.m.

यह विशेष मामलों के इनलाइनर को प्रतिबद्ध करता है:

  • हम स्टैटिक सुपर एक्सेसर्स और मिक्स्ड फ़ॉर्वर्ड में "इन इनलाइन" नहीं करते हैं।
  • इसके बजाय, जब एक मिक्सिन फारवर्डर के एक आह्वान को इनलाइन करते हुए, इनलाइनर भी दो फ़ॉरवर्डर्स के माध्यम से पीछा करता है और विशेषता विधि शरीर को इनलाइन करता है।