次のコードの実行結果は?
------------------------------------------------------------------------------
01 : import java.io.*;
02 :
03 : public class CodeWalkSeven {
04 : public static void main(String[] args) {
05 : Car c = new Car("Nissan", 1500, "blue");
06 :
07 : System.out.println("before:" + c.make + " " + c.weight);
08 :
09 : try {
10 : FileOutputStream fs = new FileOutputStream("Car.ser");
11 : ObjectOutputStream os = new ObjectOutputStream(fs);
12 : os.writeObject(c);
13 : os.close();
14 : } catch (Exception e) {
15 : e.printStackTrace();
16 : }
17 :
18 : try {
19 : FileInputStream fis = new FileInputStream("Car.ser");
20 : ObjectInputStream ois = new ObjectInputStream(fis);
21 : c = (Car) ois.readObject();
22 : ois.close();
23 : } catch (Exception e) {
24 : e.printStackTrace();
25 : }
26 :
27 : System.out.println("after:" + c.make + " " + c.weight);
28 :
29 : }
30 : }
31 :
32 : class NonLiving {
33 :
34 : }
35 :
36 : class Vehicle extends NonLiving {
37 : String make = "Lexus";
38 : String color = "Brown";
39 : }
40 :
41 : class Car extends Vehicle implements Serializable {
42 :
43 : protected int weight = 1000;
44 :
45 : Car(String n, int w, String c) {
46 : color = c;
47 : make = n;
48 : weight = w;
49 : }
50 : }
------------------------------------------------------------------------------
実行結果
before:Nissan 1500
after:Lexus 1500
上記問題の解説でよくわからないとこがありますので、質問しました。
解説では、「書き込む前にCarオブジェクトに"Nissan"をセットしているが、Vehicleのコンストラクタにより初期化され、変数makeには初期値の"Lexus"がセットされる。」となっています。
私はコンストラクタはインスタンス化した際に実行される認識ですが、
この解説の記述ですと、21行目のCarクラスへのキャスト処理時にVehicleのコンストラクタが実行されているように受け取りました。
コンストラクタはキャスト時にも実行されるものなのでしょうか?
もしそうであるならば、Javaの仕様書等に記載がある場合は、そのソースも教えていただけないでしょうか?
解説を読んでも納得いかずもやもやしています。
どなたかご回答お願いします。
No.2ベストアンサー
- 回答日時:
中々面白い問題を解いていらっしゃいますね。
Javaで直列化を扱う場合、誰もが一度は通る道です。今回のソースですと、10-13行目で対象オブジェクトの直列化(Serialize)、19-22行目で直列化の復元(deserialize)を行っています。直列化を行う場合、以下の要件を満たすことが必要です(かなり簡略化して書いてます)。
1. 対象オブジェクトのクラスがjava.io.Serializableインターフェースを実装していること
(java.io.Serializableインターフェースを実装することにより「直列化可能なクラス」になります)
2. 対象オブジェクトが保持するフィールドのクラスも、java.io.Serializableインターフェースを実装していること
3. 親クラスが直列化不可能なクラスであってもサブクラスが直列化可能なクラスであれば、直列化は可能。但し、親クラスのデフォルト・コンストラクタが外部から呼び出せること。
今回の場合は、「3」が当てはまりますね。(Vehicleクラスは直列化不可能、その子供であるCarクラスは直列化可能なクラスになります。)で、この「3」の場合なのですが、復元時にちょっと困った(?)動きをします。それは、復元時に親クラスのデフォルト・コンストラクタを呼ぶという動作をするのです。よって、親クラスで保持しているフィールドは親クラスの定義にて初期化されます。ですので、フィールドcolorとmakeは親クラスの定義に紐付く値で、weightは直列化されたCarクラスの値そのままで復元されます。
質問主様は、「キャスト時にコンストラクタが実行される」と思われているようですが、実際は上記のように直列化から復元する時に行っているのです。ちなみに、Vehicleクラスもjava.io.Serializableインターフェースを実装している場合は、上記処理は行われず直列化時そのままの状態で復元されます。
この辺りの情報ですが、Java SE APIのjava.io.Serializableインターフェースの項をご参照ください。非常に判りづらい書き方をしていますが、上記のようなことが記載されています。
以上、ご参考になりましたら。
参考URL:http://java.sun.com/javase/ja/6/docs/ja/api/java …
takepan_toki様
ご丁寧な解説ありがとうございます。
キャスト時にコンストラクタが実行されているのではなく、親クラスがSerializableインターフェースを実装していない場合、デシリアライズの際に親のデフォルトコンストラクタが動いているのですね。
とても参考になりました。
ありがとうございました。
No.1
- 回答日時:
>To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class's state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime.
>During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable. The fields of serializable subclasses will be restored from the stream.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- Java java final 1 2022/06/10 22:49
- 英語 私の車は、購入してから7年目になるが、これまでに車検を3回受けた。の英訳 11 2022/06/13 03:39
- Java Java プログラム public class Main { public static void 3 2023/08/10 23:46
- C言語・C++・C# C# DatagridviewにExcelシートを反映するとエラーが出る 2 2023/05/06 17:12
- Ruby 【JAVA】数字をひし形に出力するプログラムについて 2 2022/07/11 23:32
- C言語・C++・C# 大量のデータを読み込んで表示する速度を改善したい 8 2023/05/07 13:29
- C言語・C++・C# C# で、あるフォルダー内にあるすべてのテキストファイルを別のフォルダーにコピーする。 4 2022/11/21 13:23
- Java Java 配列<選挙> 4 2023/07/31 15:07
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
構造 他のクラスの構造体を別...
-
アップキャスト、ダウンキャス...
-
クラス間でのデータ参照
-
例えば、以下のようなクラスでm...
-
範囲外の数値を代入したらエラ...
-
関数内の変数に<summary>コメン...
-
a href="..." とServlet
-
super.paint(g)を呼び出す意...
-
デシリアライズでオブジェクト...
-
import と extends について
-
C++でfriendクラスにしているの...
-
FilterReader クラスのカスタム...
-
違うクラスからの変数の共有化
-
無名パッケージからのインポート
-
プログラムの変数名にするとど...
-
クラスについての基本的な質問です
-
Frameクラスにアクセスできない...
-
C++/C#間での構造体の引き渡し...
-
C#にて別クラスの関数を使いたい
-
c# Undo/Redo 関係
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
関数内の変数に<summary>コメン...
-
クラス間でのデータ参照
-
c++,ある関数のクラスから別の...
-
範囲外の数値を代入したらエラ...
-
C#にて別クラスの関数を使いたい
-
C#でほかのファイルにある自作...
-
C++でfriendクラスにしているの...
-
java-別クラスの変数の使い方を...
-
親クラスから子クラスへアクセス。
-
構造 他のクラスの構造体を別...
-
ひとつのファイルにクラスは1つ?
-
Java
-
import と extends について
-
継承したクラス側のクラス名の取得
-
SwingでgetContentPaneのエラー...
-
Java リフレクションについて
-
C#のクラスライブラリでメッセ...
-
アップキャスト、ダウンキャス...
-
C# インターフェイスの実装
-
visual studioのデザイナ画面で...
おすすめ情報