سؤال

أعتقد أن هناك شيئًا خفيًا يحدث هنا ولا أعرف عنه شيئًا.خذ بعين الاعتبار ما يلي:

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA() {
    return a;
  }
}

لنفترض أن طريقتك الرئيسية تحتوي على ما يلي:

Foo<Double> f = new Foo<Double>();
Double[] d = f.getA();

سوف تحصل على CastClassException مع الرسالة java.lang.Object لا يمكن طرحه java.lang.Double.

يمكن لأحد أن يقول لي لماذا؟فهمي ل ClassCastException هو أنه يتم طرحه عند محاولة إرسال كائن إلى نوع لا يمكن إرساله.أي إلى فئة فرعية ليست مثالًا لها (على حد تعبير الوثائق).على سبيل المثال:

Object o = new Double(3.);
Double d = (Double) o; // Working cast
String s = (String) o; // ClassCastException

ويبدو أنني أستطيع أن أفعل هذا.لو a كان مجرد T بدلا من مصفوفة T[], ، يمكننا الحصول على a ويلقي بها دون مشكلة.لماذا تكسر المصفوفات هذا؟

شكرًا.

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

المحلول

Foo<Double> f = new Foo<Double>();

عند استخدام هذا الإصدار من الفئة العامة Foo، ثم لمتغير العضو a, ، يأخذ المترجم بشكل أساسي هذا السطر:

private T[] a = (T[]) new Object[5];

واستبدال T مع Double للحصول على هذا:

private Double[] a = (Double[]) new Object[5];

لا يمكنك الإرسال من كائن إلى مزدوج، ومن هنا جاء ClassCastException.

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

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    System.out.println(f.getA());
}

المشكلة تحدث عند محاولة التعيين f.getA() إلى مرجع النوع Double[]:

public static void main(String[] args) {
    Foo<Double> f = new Foo<Double>();
    Double[] a2 = f.getA(); // throws ClassCastException
    System.out.println(a2);
}

وذلك لأن معلومات النوع حول متغير العضو a يتم مسحه في وقت التشغيل.الأدوية العامة توفر فقط سلامة النوع في وقت الترجمة (كنت أتجاهل هذا بطريقة أو بأخرى في رسالتي الأولية).لذا فإن المشكلة ليست كذلك

private T[] a = (T[]) new Object[5];

لأنه في وقت التشغيل هذا الرمز هو حقا

private Object[] a = new Object[5];

المشكلة تحدث عندما نتيجة الأسلوب getA(), ، والذي يقوم في وقت التشغيل بإرجاع ملف Object[], ، يتم تعيينه إلى مرجع من النوع Double[] - يطرح هذا البيان ClassCastException لأنه لا يمكن تحويل الكائن إلى Double.

تحديث 2:للإجابة على سؤالك الأخير "لماذا تكسر المصفوفات هذا؟" الجواب هو أن مواصفات اللغة لا تدعم إنشاء مجموعة عامة. انظر هذا المنتدى لمزيد من المعلومات - لكي يكون متوافقًا مع الإصدارات السابقة، لا يُعرف أي شيء عن نوع T في وقت التشغيل.

نصائح أخرى

وربما تكون هناك بعض الأخطاء الصغيرة في التفسير @ mattb ل.

والخطأ هو لا

<اقتباس فقرة>   لا يمكن أن يلقي

وjava.lang.Object إلى java.lang.Double.

ومن:

<اقتباس فقرة>   

[Ljava.lang.Object. لا يمكن أن يلقي ل[Ljava.lang.Double

وو[L يعني صفيف. وهذا هو، والخطأ هو أن <م> مجموعة الأجسام لا يمكن أن يلقي على مجموعة من مزدوجة. هذا هو نفس القضية على النحو التالي:

Object[] oarr = new Object[10];
Double[] darr = (Double[]) oarr;

ومن الواضح أن لا يسمح هذا.

لمشكلتك إنشاء صفائف typesafe، بديل آخر هو ما عدا فئة الكائن في الحرف الأول واستخدام Array.newInstance:

import java.lang.reflect.Array;

class Foo<T> {
  private T[] a ;

  public Foo(Class<T> tclass) {
    a = (T[]) Array.newInstance(tclass, 5);
  }

  public T[] getA() {
    return a;
  }

  public static <T> Foo<T> create(Class<T> tclass) {
    return new Foo<T>(tclass);
  }
}

class Array1
{
  public static final void main(final String[] args) {
    Foo<Double> f = Foo.create(Double.class);
    Double[] d = f.getA();
  }


}

وmatt ب: شكرا للإجابة! مفيدة جدا.

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

public class Foo<T> {
  private T[] a = (T[]) new Object[5];

  public Foo() {
    // Add some elements to a
  }

  public T[] getA(T[] holdA) {
    // Check whether holdA is null and handle it...then:
    holdA = (T[]) Array.newInstance(holdA.getClass().getComponentType(), a.length);
    System.arraycopy(a, 0, holdA, 0, a.length);
    return holdA;
  }
}

وبعد ذلك لطريقة الرئيسي الخاص بك:

public static void main(String[] args) {
  Foo<Double> f = new Foo<Double>();
  Double[] a2 = new Double[1];
  a2 = f.getA(a2);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top