मैं java.lang.String के पैकेज निजी कन्स्ट्रक्टर को प्रतिबिंबित पहुंच प्राप्त करना चाहता हूं।क्या लैम्ब्डा अभिव्यक्तियां उनके दायरे के बाहर कक्षाओं के निजी तरीकों तक पहुंच सकती हैं?
अर्थात्, यह एक:
/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
एक MethodHandle बनाना यह काफी सरल है के लिए, और इसलिए इसे लागू किया जाता है। वही प्रतिबिंब का उपयोग करने के लिए भी सच है।
लेकिन मुझे उत्सुकता है कि क्या कार्यात्मक इंटरफेस के माध्यम से सीधे निर्माता को कॉल करना संभव है।
27602758 कुछ हद तक इसी तरह के मुद्दे पर छूता है, लेकिन प्रदान किए गए समाधान इस मामले में काम नहीं करते हैं।
नीचे दिए गए टेस्ट केस बिना किसी समस्या के संकलित हैं। असली इंटरफ़ेस आमंत्रण को छोड़कर, सब कुछ काम करता है।
Exception in thread "main" java.lang.IllegalAccessError: tried to access method java.lang.String.<init>([CZ)V from class test.Test$$Lambda$2/989110044 at test.Test.main(Test.java:59)
है क्यों इस त्रुटि अभी भी फेंक दिया जा रहा है, पहुँच के बावजूद जाहिरा तौर पर दिए जाने:
package test;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
public class Test {
// Creates a new String that shares the supplied char[]
private static interface StringCreator {
public String create(char[] value, boolean shared);
}
// Creates a new conventional String
private static String create(char[] value, boolean shared) {
return String.valueOf(value);
}
public static void main(String[] args) throws Throwable {
// Reflectively generate a TRUSTED Lookup for the calling class
Lookup caller = MethodHandles.lookup();
Field modes = Lookup.class.getDeclaredField("allowedModes");
modes.setAccessible(true);
modes.setInt(caller, -1); // -1 == Lookup.TRUSTED
// create handle for #create()
MethodHandle conventional = caller.findStatic(
Test.class, "create", MethodType.methodType(String.class, char[].class, boolean.class)
);
StringCreator normal = getStringCreator(caller, conventional);
System.out.println(
normal.create("foo".toCharArray(), true)
// prints "foo"
);
// create handle for shared String constructor
MethodHandle constructor = caller.findConstructor(
String.class, MethodType.methodType(void.class, char[].class, boolean.class)
);
// test directly if the construcor is correctly accessed
char[] chars = "foo".toCharArray();
String s = (String) constructor.invokeExact(chars, true);
chars[0] = 'b'; // modify array contents
chars[1] = 'a';
chars[2] = 'r';
System.out.println(
s
// prints "bar"
);
// generate interface for constructor
StringCreator shared = getStringCreator(caller, constructor);
System.out.println(
shared.create("foo".toCharArray(), true)
// throws error
);
}
// returns a StringCreator instance
private static StringCreator getStringCreator(Lookup caller, MethodHandle handle) throws Throwable {
CallSite callSite = LambdaMetafactory.metafactory(
caller,
"create",
MethodType.methodType(StringCreator.class),
handle.type(),
handle,
handle.type()
);
return (StringCreator) callSite.getTarget().invokeExact();
}
}
Specficially अनुदेश
shared.create("foo".toCharArray(), true)
निम्न त्रुटि फेंकता है?
क्या कोई भी स्पष्टीकरण के साथ आ सकता है कि जेनरेट किए गए इंटरफ़ेस के पास इस विधि तक पहुंच क्यों नहीं है कि उसके सभी घटकों तक पहुंच है?
क्या कोई समाधान या व्यवहार्य विकल्प है जो वास्तव में शुद्ध प्रतिबिंब या मेथडहैंडल्स पर वापस लौटने के बिना इस विशेष उपयोग मामले के लिए काम करता है?
क्योंकि मैं स्टंप हूं।
निश्चित अपने वास्तविक सवाल का जवाब नहीं कर सकते:
एकमात्र समाधान के लिए लुक-वस्तु
String
के संदर्भ में रहने वाले और मौजूदा सामान्यinterface
रों में से एक, बूटस्ट्रैप वर्ग लोडर से सुलभ को लागू करने का उपयोग करने के लिए है , लेकिन शुद्ध प्रतिबिंब यहां भयानक नहीं है। विधि/निर्माता/आदि। उत्पन्न बाइटकोड के साथ एक एक्सेसर के आसपास अनिवार्य रूप से प्रॉक्सी कक्षाएं हैं। उन्हें बनाना एक हेवीवेट ऑपरेशन है, लेकिन एक आमंत्रण नहीं है। 'बुलियन' बॉक्सिंग हो जाता है, लेकिन यह अन्यथा कम से कम सूर्य/ओपनजेडीके कार्यान्वयन में 'नया' का उपयोग करने जैसा ही है। रिफ्लेक्शन एक्सेसर को उत्पन्न करके एक्सेस त्रुटि के आसपास आता है जैसे कि यह उस क्षेत्र के अंदर था जिसके सदस्य सदस्य हैं, जो मुझे लगता है कि LambdaMetaFactory यहां नहीं कर रहा है। – Radiodef@Radiodef विवरण के लिए धन्यवाद। यदि कोई लैम्ब्डा समाधान नहीं मिल पाता है, तो मैं बस मेथडहैंडल का उपयोग करूंगा। मैं अधिक उत्सुक हूं कि परीक्षा क्यों व्यवहार करती है। –