سؤال

class Bouncy<T> extends Throwable {     
}
// Error: the generic class Bouncy<T> may not subclass java.lang.Throwable

لماذا لا يدعم Java عام Throwableس؟

أدرك أن المحو النوع يعقد بعض الأشياء، ولكن من الواضح أن جافا يحصل مع الكثير بالفعل، فلماذا لا تدفعها إلى درجة أخرى وتسمح عام ThrowableS، مع التحقق من وقت التشكيل الشامل للمشاكل المحتملة؟


أشعر أن حجة محو النوع ضعيفة إلى حد ما. حاليا، لا يمكننا القيام به:

void process(List<String> list) {
}

void process(List<Integer> list) {
}

بالطبع، نحن نصل دون ذلك. أنا لا أطلب أن نكون قادرين على القيام به catch Bouncy<T1> و Bouncy<T2> في نفس try Block، ولكن إذا نستخدمها في سياقات Disfoint مع قواعد قابلة للتنفيذ القابلة للتنفيذ القابلة للتنوير الصارمة (والتي هي الطريقة التي تعمل بها الجنراء الآن)، فلن تكون قابلة للتطبيق؟

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

المحلول

مواصفات لغة Java.8.1.2 الفصول العامة ومعلمات الكتابة:

هناك حاجة إلى هذا التقييد لأن آلية الصيد في الجهاز الظاهري Java يعمل فقط مع الطبقات غير العامة.

شخصيا، أعتقد أنه لأنه لا يمكننا الحصول على أي فوائد للأردن داخل catch بند. لا يمكننا الكتابة catch (Bouncy<String> ex) بسبب المحو النوع، ولكن إذا كنا نكتب catch (Bouncy ex), ، سيكون من الفائدة أن تجعلها عامة.

نصائح أخرى

نوع محو. نوع استثناء وقت التشغيل لا يحتوي على معلومات الجنراء. هكذا لا يمكن القيام به

} catch( Mistake<Account> ea) {
  ...
} catch( Mistake<User> eu) {
...
}

كلك يمكن القيام به هو

catch( Mistake ea ) {
  ...
}

والنوع المحو هو كيف تقرر الحفاظ على التوافق المتخلص عندما كان جافا يتحرك من 1.4 إلى 1.5. كثير من الناس كانوا غير راضين إذن، وبالفعل ذلك. ولكن في الاعتبار مقدار التعليمات البرمجية المنتشرة، كان لا يمكن تصوره لكسر التعليمات البرمجية التي عملت بسعادة في 1.4.

إجابة قصيرة: لأنهم أخذوا اختصارات، كما فعلوا مع محو.

الجواب الطويل: كما أشار آخرون بالفعل، بسبب المحو، لا توجد طريقة لإحداث تغيير في وقت التشغيل بين "التقاط myexceptionu003CString> "و" قبض على myExceptionu003CInteger> ".

لكن هذا لا يعني أنه لا توجد حاجة لاستثناءات عامة. وبعد أريد Generics أن تكون قادرا على استخدام الحقول العامة! يمكن أن يسمح لهم ببساطة باستثناءات عامة، ولكن السماح فقط بالقبض عليهم في الحالة الأولية (مثل "قبض على MyException").

منحت، وهذا من شأنه أن يجعل الأجواء أكثر تعقيدا. هذا هو إظهار مدى سوء قرار محو الأجنام. متى سيكون لدينا نسخة جافا تدعم الجنراء الحقيقية (مع RTTI)، وليس السكر النحوي الحالي؟

لا يزال بإمكانك استخدام طرق عامة، مثل هذا:

public class SomeException {
    private final Object target;

    public SomeException(Object target) {
        this.target = target;
    }

    public <T> T getTarget() {
        return (T) target;
    }
}

....

catch (SomeException e) {
    Integer target = e.getTarget();
}

أنا أتفق مع إجابة كريستيان أعلاه. في حين أن الإجابة المقبولة صحيحة تقنيا (بقدر ما تشير إلى مواصفات JVM)، فإن إجابة كريستيان فازيل هي واحدة مؤهلة وحتى تتحدى القيد.

هناك حجتين على الأقل لاحظت إجابات حول هذا السؤال الذي لا أتفق معه وأنني سأحدد. إذا كانت الحجج الموجودة في هذه الإجابات صحيحة، فيمكننا استخدام هذه الحجج لمهاجمة الأطفال في سياقات أخرى حيث يتم استخدامها بنجاح اليوم.


تنص الحجة الأولى على أنه لا يمكننا استخدام هذا:

catch (Exception<T1> e) {}

لأن JVM لا يعرف كيفية العمل مع Exception<T1>. وبعد يبدو أن هذه الحجة تهاجم أيضا استخدام الأجهزة، على أساس أن JVM لا يعرف كيفية استخدام List<T1>:

List<T1> list;

الحجة، بالطبع، تنسى أن المترجم ينفذ محو النوع، وبالتالي لا يحتاج JVM إلى معرفة كيفية التعامل مع Exception<T1>. وبعد يمكن ببساطة التعامل مع Exception, ، تماما مثل مقابض List.

بالطبع، لم نتمكن من التعامل معها catch(Exception<T1> e) و catch(Exception<T2> e) في نفس المحاولة / التقاط بسبب محو النوع، ولكن مرة أخرى، ليس ذلك أسوأ من حجج الأسلوب أو قيم العودة اليوم: نحن لا نتعامل معها myMethod(List<T1>) و myMethod(List<T2>) اليوم إما ... (أؤكد مجددا هذا الجانب في الدهنة الثانية أدناه.)


حجة ثانية يذهب كما يلي. نحن لا نسمح بذلك:

catch (Exception<T1> e) {}

لأن هذا لن يعمل:

catch (Exception<T1> e) {}
catch (Exception<T2> e) {}

حسنا، فلماذا لا تسمح هذا:

interface MyInterface {
    Comparable<Integer> getComparable();
}

لأن هذا لا يعمل:

interface MyInterface {
    Comparable<Integer> getComparable();
    Comparable<String> getComparable();
}

أو هذا:

interface MyInterface {
    void setComparable(Comparable<Integer> comparable);
}

لأن هذا لا يعمل:

interface MyInterface {
    void setComparable(Comparable<Integer> comparable);
    void setComparable(Comparable<String> comparable);
}

وبعبارة أخرى، لماذا لا يسمح للأردن في معظم الحالات؟

هذه الحجة الثانية تنسى أنه، على الرغم من أننا لم نتمكن من السماح بنتائج عامة مختلفة تمحوها إلى نفس البناء غير العام في هذه السياقات، لا يزال بإمكاننا القيام بأفضل أفضل شيء اسمح للأردن طالما أن الأنواع لا تمحو نفس النوع. وبعد هذا ما نقوم به مع المعلمات الطريقة: نسمح لك باستخدام الأجداد، ولكن يشكو بمجرد اكتشافنا توقيعات مكررة بعد محو النوع. حسنا، كان بإمكاننا القيام به حول نفس الشيء مع استثناءات وصيد كتل ...


في الختام، أود أن أتوسع في إجابة كريستيان. بدلا من السماح لفئات الاستثناءات العامة و باستخدام الأنواع الخام في catch كتل:

class MyException<T> {}
...
catch (MyException e) { // raw

كان يمكن أن يذهب جافا الطريق كله دون مشاكل:

class MyException<T> {}
...
catch (MyException<Foo> e) {

وهنا زوجين من الأشياء لك تستطيع فعل:

  1. يمكن أن تقوم Remables بتنفيذ واجهات عامة، طالما أن Readable نفسه ليس لديه معلمات من النوع، على سبيل المثال

    interface Bouncy<E> {
        // ...
    }
    class BouncyString extends Exception implements Bouncy<String> {
        // ...
    }

  2. أ throws يمكن للبند الرجوع إلى نوع المعلمات، على سبيل المثال
    static <X extends Throwable> void
    throwIfInstanceOf(Throwable ex, Class<X> clazz) throws X {
        if (clazz.isInstance(ex)) throw clazz.cast(ex);
    }

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