アプリ版:「スタンプのみでお礼する」機能のリリースについて

InputStreamの関数
public abstract int read()throws IOException
サブクラスはこの関数をオーバーライドする。

ところがFilterInputStreamはInputStreamを変数にもちread()を呼び出している。(↓を参照)
http://java.sun.com/javase/ja/6/docs/ja/api/java …
サブクラスでオーバーライドするなら、そもそも変数でInputStreamがもてる時点でおかしいわけです。

他にも同じようなものに
Socket sock;
InputStream is = sock.getInputStream();
これでなぜかis.read()が使える。

A 回答 (5件)

>いや、しかし、


>Socketでは
>public InputStream getInputStream()throws IOException
>
> その説明では
>public HogeStream getInputStream()
>
> で無ければならず。

引数の時と同じ理屈です。
getInputStream() は InputStream の何かの派生クラスのインスタンスを「実行時に状況に応じて」戻します。

コードを書く時には、実行時に戻ってくる具体的な型はわからないけれど、
InputStream の派生クラスであることはわかっています。

そのため、InputStream 型の変数 in を宣言して、これで InputStream の派生クラスのオブジェクトを受け取っているのです。

InputStream には read() が仮想関数として宣言されているので、その派生クラスは read() を実装しているはずです。
これによって in.read() に必ず意味があることが保証され、
「実行時に」getInputStream() から戻されたインスタンスが実装している read() が呼び出されます。
    • good
    • 0

koko_u_さん,大変ですね。



質問者というより,このサイトを利用するJava/オブジェクト指向言語学習者のために回答を書きます。

本質的には継承に関する理解の問題だと思います。

> Socket sock;
> InputStream is = sock.getInputStream();
> これでなぜかis.read()が使える。

こちらの例の方が説明が簡単なのでこっちを使いますが,このとき変数isに入っているのは,InputStreamクラスそのもののインスタンスである必要はなく,その派生クラス(例えばByteArrayInputStreamやFileInputStream)のインスタンスであってもいい(*注),というのが継承の持つ機能の一つです。

注: 実際はInputStreamの派生クラスのうちのコンクリートクラスのどれかが入っていると考えるのが普通。

以下のようなコードを書いて動かしてみれば理解できるかもしれません。

abstract class AA
{
abstract void aMethod();
}

class BB extends AA
{
void aMethod()
{
System.out.println("BB");
}
}

class CC
{
AA getAA()
{
return new BB();
}
}

class DD
{
public static void main(String[] args)
{
CC cc = new CC();
AA aa = cc.getAA();
aa.aMethod();
}
}
    • good
    • 0

>>「実装を移動する」とはどのようなコトを指しているのですか?


>これの実際の処理内容はどこに書いてますか?
>public abstract int read() throws IOException;

うーん。会話が成立していない。抽象メソッドだから、その派生クラスで read() は実装される。
ここまではいいですよね。


>>InputStream は抽象クラスなので、これは「InputStream の派生クラスをコンストラクタに渡せ」という意味です。
>同じ名前で派生クラスを作ろうとするとエラー(ループ)になるのでは?どうやってその派生クラスを作ったのか?
>class InputStream extends InputStream()

だから class HogeStream extends InputStream { ... } と「派生クラスを」定義するのです。
FilterStream のコンストラクタの引数は InputStream 型ですが、これは InputStream の派生クラスのすべてを
引数として受け取ることができることを意味しています。
これは OK?

この回答への補足

いや、しかし、
Socketでは
public InputStream getInputStream()throws IOException

その説明では
public HogeStream getInputStream()

で無ければならず。

補足日時:2008/01/27 15:18
    • good
    • 0

>全然違うと思う。

(またはその実装はどこにありますか?)
実装は InputStream の派生クラスの中。

>実装まで移動できない。
「実装を移動する」とはどのようなコトを指しているのですか?再度補足して下さい。

FilterInputStream のコンストラクタは InputStream を引数としていますね?
InputStream は抽象クラスなので、これは「InputStream の派生クラスをコンストラクタに渡せ」という意味です。

InputStream の派生クラス HogeStream のインスタンス hoge をもって

stream = new FilterStream(hoge);

すると、stream の保持するメンバ変数 in は hoge です。
実行時にどこかで in.read() したときに、polymorphism が発動して、hoge に実装された read() が呼び出されます。

この回答への補足

>「実装を移動する」とはどのようなコトを指しているのですか?
これの実際の処理内容はどこに書いてますか?
public abstract int read() throws IOException;


>InputStream は抽象クラスなので、これは「InputStream の派生クラスをコンストラクタに渡せ」という意味です。

同じ名前で派生クラスを作ろうとするとエラー(ループ)になるのでは?どうやってその派生クラスを作ったのか?
class InputStream extends InputStream()

補足日時:2008/01/26 21:39
    • good
    • 0

>ところがFilterInputStreamはInputStreamを変数にもちread()を呼び出している。


リンク先はまったく見てませんが、それが polymorphism というやつでしょう。

FilterInputStream は InputStream の「派生クラスとなる何か」をメンバーとして保持することができ、
インスタンス毎に様々な InputStream の派生クラスのインスタンスをそのメンバー変数として持てる。

そして、read() を呼び出すと、その派生クラスに応じた read() の実装が実行時に呼び出される。


そんな感じだと思う。

>Socket sock;
>InputStream is = sock.getInputStream();
> これでなぜかis.read()が使える。
これも getInputStream() が InputStream の派生クラスの何かを戻しているはずです。

この回答への補足

>そして、read() を呼び出すと、その派生クラスに応じた read() の実装が実行時に呼び出される。

全然違うと思う。(またはその実装はどこにありますか?)
実装まで移動できない。
プログラムにはread(byte b[])を使ったので
実際にread(byte b[])を使って移動してみると
read(byte b[])

read(b, 0, b.length)
を呼び出す。

read(b, 0, b.length)
はread()を呼び出す。

read()は
public abstract int read() throws IOException;
となっていてこれ以上移動できない。

補足日時:2008/01/26 00:45
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!