فشلت اكتب الصب بصمت مع الوكيل الديناميكي و generics جافا

StackOverflow https://stackoverflow.com/questions/19849208

سؤال

يتعلق سؤال IMY بسلوك النوع المصبوب مع الوكيل الديناميكي وجوائز Java. وبشكل أكثر تحديداً ، أريد أن أقوم بتكوين كائن Servelet باستخدام الوكيل الديناميكي. من أجل إعادة استخدام أفضل ، اعتمدت بعض قالب التعليمات البرمجية العامة لإنشاء كائنات وكيل على النحو التالي.

@SuppressWarnings("unchecked")
public static <T> T instrument(final T aT) {
    T proxy = (T) Proxy.newProxyInstance(aT.getClass().getClassLoader(), new Class[]{MyServelet.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object aProxy, Method aMethod, Object[] aArgs) throws Throwable {
        ..... instrumentation logic goes here
        }
    });
     System.out.println("proxy class " + proxy.getClass());
     System.out.println("input class " + aT.getClass());
     return proxy;
}

هنا T هي فئة تنفيذ Servelet الملموسة التي تنفذ واجهة MySerVelet. ومع ذلك ، إذا قمت بتشغيل الطريقة أعلاه ، فإنه يطبع

proxy class class com.sun.proxy.$Proxy0
input class class MyServeletImplementation

لذلك أتساءل عما حدث لبيان الصب في مقتطف الكود. يبدو أنه فشل بهدوء لأن الوكيل لم يتم إلقاؤه إلى MySerVeletImplementation ، لكنه لم يرمي أيضًا. هل يمكن لأحد أن يلقيني بعض الضوء على هذا؟ شكرًا!

هل كانت مفيدة؟

المحلول

لم يحدث أي ممثلين في رمز Bytecode الفعلي للطريقة ، بسبب اكتب المحو.

عند إنشاء رمز bytecode ، يعامل برنامج التحويل البرمجي أي متغير لنوع المعلمة بأنه يحتوي على نفس النوع العلوي لنوع المعلمة ، أو Object إذا كان النوع غير محدود. حتى إذا T في طريقتك كان القيد <T extends MyServelet>, ، كان المترجم قد عالج proxy كمتغير من النوع MyServelet, ، وأدخلت طاقم. ولكن كما T غير محدود ، يتم التعامل معه كمتغير من النوع Object - وهكذا ، لا يلقي.

نصائح أخرى

الهدف من الوكيل الديناميكي هو أنك لا تهتم بالفئة الفعلية للوكالة التي يتم إرجاعها. أنت فقط تهتم بأنه ينفذ جميع الواجهات المرغوبة والمحددة.

جافادوك ل newProxyInstance حالة:

عائدات:

مثيل وكيل مع معالج الاحتجاج المحدد لفئة الوكيل التي يتم تعريفها بواسطة محمل الفئة المحدد وتنفيذ الواجهات المحددة

لذا، newProxyInstance أعاد مثيل com.sun.proxy.$Proxy0 (مهما كان هذا ، نحن لا نهتم حقًا) ، لكنه تأكد أيضًا من أنه MyServelet. يجب أن تكون قادرًا على إلقاءها على MyServelet بدون ClassCastException, ، لان newProxyInstance أنشأت الفصل لتنفيذ تلك الواجهة ، وقمت بتحديد أنه ينبغي أن يمر بالمرور new Class[]{MyServelet.class}.

لكي لا يفشل النوع من التقليل ، يجب أن تستنتج جافا جيرلايس ذلك T هو MyServelet, ، ليس MyServeletImplementation. ربما عندما اتصلت instrument, ، لقد فعلت ذلك مثل هذا:

MyServelet proxy = YourClass.instrument(new MyServeletImplementation());

لذلك كان فريق الممثلين MyServelet التي يجب أن تنجح ، وليس ل MyServeletImplementation, ، والتي يجب أن تفشل.

السبب الذي تجعلك بحاجة إلى إضافة @SuppressWarnings("unchecked") لأن المترجم كان يحاول تحذيرك من أنك تفعل شيئًا خاطئًا. بإضافة القمع ، أخبرت المترجم أنك لم تهتم لأنك تعرف ما الذي تفعله. ربما لم يكن يجب عليك إضافة التعليق التوضيحي إذا لم تقم بتوضيح لماذا كنت تحصل على التحذير في المقام الأول؟

تلميح: الممثل العام T proxy = (T) يتحول إلى Object proxy = (Object) بواسطة المترجم. ("النوع محو" كما هو مذكور في إجابة أخرى).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top