سؤال

طريقة ObjectOutputStream.writeStreamHeader() يمكن تجاوزه لإعداد البيانات أو إلحاقها إلى الرأس. ومع ذلك، إذا كانت هذه البيانات تستند إلى حجة مرت إلى منشئ الفئة المشتقة مثل:

public class MyObjectOutputStream extends ObjectOutputStream {

    public MyObjectOutputStream( int myData, OutputStream out ) throws IOException {
        super( out );
        m_myData = myData;
    }

    protected void writeStreamHeader() throws IOException {
        write( m_myData );            // WRONG: m_myData not initialized yet
        super.writeStreamHeader();
    }

    private final int m_myData;
}

لا يعمل بسبب super() يسمى قبل m_myData يتم تهيئة و super() المكالمات writeStreamHeader(). وبعد الطريقة الوحيدة التي يمكنني التفكير فيها في العمل من خلال استخدام ThreadLocal مثل:

public class MyObjectOutputStream extends ObjectOutputStream {

    public MyObjectOutputStream( int myData, OutputStream out ) throws IOException {
        super( thunk( myData, out ) );
    }

    protected void writeStreamHeader() throws IOException {
        write( m_myData.get().intValue() );
        super.writeStreamHeader();
    }

    private static OutputStream thunk( int myData, OutputStream out ) {
        m_myData.set( myData );
        return out;
    }

    private static final ThreadLocal<Integer> m_myData = new ThreadLocal<Integer>();
}

يبدو أن هذا يعمل، ولكن هل هناك طريقة أفضل (أقل clunky)؟

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

المحلول

هناك طريقة عامة لحل هذا النوع من المشكلة. جعل الفصل والطبقة الداخلية والرجوع إلى متغير في النطاق الخارجي. (ملاحظة، هذا يعمل فقط مع -target 1.4 أو المتناكبين، وهو الافتراضي في الإصدارات الحالية من Javac. مع -target 1.3 سوف تحصل على NPE.)

public static ObjectOutputStream newInstance(
    final int myData, final OutputStream out
) throws IOException {
    return new ObjectOutputStream(out) {
        @Override
        protected void writeStreamHeader() throws IOException {
            write(myData);
            super.writeStreamHeader();
        }
    };
}

ولكن من المحتمل أن تكون أسهل فقط لكتابة البيانات قبل بناء ObjectOuputStream.

نصائح أخرى

لا يمكن أن تفعل ذلك مثل هذا. تجاهل مكالمة WriteReMHEADER من منشئ السوبر والقيام بنفسك، عندما قمت بتهيئة الحقل المطلوب:

public class MyObjectOutputStream extends ObjectOutputStream {

private boolean initalized = false;
private final int m_myData;

protected MyObjectOutputStream(int myData, OutputStream out) throws IOException, SecurityException {
    super(out);
    m_myData = myData;
    initalized = true;
    writeStreamHeader();
}

protected void writeStreamHeader() throws IOException {

    if(!initalized){
        return;
    }

    write( m_myData );
    super.writeStreamHeader();
}
}

تعديل:

أو، كما اقترح من قبل ثيلو, ، يمكن أن تكون مكتوبة مثل:

public class MyObjectOutputStream extends ObjectOutputStream {

    private final int m_myData;

    protected MyObjectOutputStream(int myData, OutputStream out) throws IOException, SecurityException {
        super(out);
        m_myData = myData;
        write( m_myData );
        super.writeStreamHeader();
    }

    protected void writeStreamHeader() throws IOException {
        // work is done in the constructor
    }
}

إنها بالفعل فكرة سيئة استدعاء الأساليب غير النهائية من المنشئ (بالضبط السبب الذي قدمته).

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

   out.write(myExtraHeader);
   ObjectOutputStream oos = new ObjectOutputStream(out);

إذا كنت ترغب في ذلك، يمكنك التفاف هذا كل شيء بشكل جيد وراء واجهة ObjectoutPut كما اقترف Stu Thompson في إجابته، بحيث يمكن أن ننظر إلى الخارج تقريبا مثل ObjectoutPuttream.

تحديث:

بالنظر إلى Javadocs والمصدر للأعشاد، هناك منشئ ثان (محمي)، وهذا لا يدعو writeStreamHeader().

ومع ذلك، فإن هذا المنشئ أيضا لا تهيئة الهياكل الداخلية الأخرى. إلى اقتباس المستندات، من المقصود "بالنسبة لعلم الفئات الفئة الفرعية التي تعيد توحيد ObjectoutSttream تماما لعدم امتثال البيانات الخاصة المستخدمة فقط من خلال تطبيق ObjectOutstream". في هذه الحالة، يدعو أيضا إلى بعض الأساليب الأخرى، مثل "foritobjectolide". فوضوي...

استخدام التكوين بدلا من الميراث.

public class MyObjOutStream implements DataOutput, ObjectOutput, ObjectStreamConstants {
    //same interfaces that ObjectOutputStream implements

    private ObjectOutputStream objOutStream;

    //implement all the methods below
}

مثيل ObjectoutPuttream فقط عندما تكون مستعدا للقيام بذلك. يمكن للطرق المتبقية التي تحتاجها إلى تطبيقها في الواجهات فقط استدعاء الأساليب نفسها objOutStream

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