2

こんにちは、JAVA を深く学ぼうとしているので、次の行で JDK ソース コードを掘り下げています。

URL url = new URL("http://www.google.com");
URLConnection tmpConn = url.openConnection();

ソース コードを添付し、2 行目にブレークポイントを設定して、コードにステップ インしました。コード フローは次のとおりです。 URL.openConnection() -> sun.net.www.protocol.http.Handler.openConnection() これについて 2 つの質問があります。

まず URL.openConnection() のコードは次のとおりです。

public URLConnection openConnection() throws java.io.IOException {
        return handler.openConnection(this);
    }

handler は URLStreamHandler のオブジェクトであり、blow として定義します。

transient URLStreamHandler handler;

しかし、URLStreamHandler は抽象クラスであり、メソッド openConnection() は実装されていないため、ハンドラーがこのメソッドを呼び出すと、このメソッドを実装するサブクラスを見つける必要がありますよね? しかし、sun.net.www.protocol (http.Hanlder、ftp.Handler など) にこのメソッドを実装するクラスはたくさんあります。コードはどの「openConnection」メソッドを呼び出す必要があるかをどのように認識すればよいでしょうか? この例では、この handler.openConnection() は http.Handler に入りますが、これは正しいです。(url をftp://www.google.comにすると ftp.Handler に入ります) 仕組みがわかりません。

2番目。JDK にステップインして変数を確認できるようにソース コードを添付しましたが、sun.net.www.protocol.http.Handler などの多くのクラスでは、src.zip にソース コードがありません。このクラスをグーグルで検索したところ、入手できるオンラインのソースコードがありますが、なぜそれ (および他の多くのクラス) を src.zip に入れなかったのですか? 包括的なバージョンのソース コードはどこにありますか?

ありがとう!

4

3 に答える 3

8

最初の簡単な部分:

...私はこのクラスをグーグルで検索し、オンラインで入手できるソースコードがありますが、なぜ彼らはそれ(および他の多くのクラス)をsrc.zipに入れなかったのですか?

2つの理由:

  • Javaコードベースがプロプライエタリであった昔は、これは秘密っぽいものとして扱われていました...そしてには含まれていませんでしたsrc.zip。彼らがGPLの下でJava6を再ライセンスしたとき、彼らはこれを変更することを気にしませんでした。(理由はわかりません。Oracleに問い合わせてください。)

  • ツリー内のコードはすべて、sun.*公式には「実装の詳細は予告なしに変更される可能性がある」ためです。彼らがコードを直接提供した場合、それは顧客がそのアドバイスを無視するのに役立ちます。それは、コードへの予告なしの変更の結果として顧客のコードが壊れたときに、より多くの摩擦/悪い報道につながる可能性がありsun.*ます。

ソースコードの包括的なバージョンはどこにありますか?

OpenJDK6/7/8リポジトリおよび関連するダウンロードバンドルで見つけることができます。


次に、「Javaを深く学ぶ」という部分について説明します。

まず、あなたはおそらくこの学習を「次善の」方法で行っていると思います。Javaクラスライブラリを読むのではなく、Javaとデザインパターンに関する本を読んで、自分でコードを書くべきだと思います。

詳細について:

しかしURLStreamHandler、抽象クラスとメソッドopenConnection()はその中に実装されていないので、ハンドラーがこのメソッドを呼び出すとき、このメソッドを実装するサブクラスを見つける必要がありますよね?

ハンドラーがメソッドよりも呼び出す時点で、ハンドラーはサブクラスのインスタンスでそれを呼び出しています。したがって、適切なメソッドの検索は、他のポリモーフィックディスパッチと同じようにJVMによって処理されます。

トリッキーな部分は、sun.net.www.protocol.*ハンドラークラスのインスタンスを取得する方法です。そして、それは次のように起こります。

  1. URLオブジェクトが作成されるとgetURLStreamHandler(protocol)、ハンドラーインスタンスを取得するために呼び出されます。

  2. このメソッドのコードは、プロトコルのハンドラーインスタンスが既に存在するかどうかを確認し、存在する場合はそれを返します。

  3. それ以外の場合は、プロトコルハンドラファクトリが存在するかどうかを確認し、存在する場合はそれを使用してハンドラインスタンスを作成します。(プロトコルハンドラファクトリオブジェクトは、アプリケーションで設定できます。)

  4. それ以外の場合は、構成可能なJavaパッケージのリストを検索して、FQNがpackage + "." + protocol + "." + "Handler"であるクラスを見つけてロードし、リフレクションを使用してインスタンスを作成します。(構成はSystemプロパティを介して行われます。)

  5. ハンドラーへの参照はURLのハンドラーフィールドに格納され、URLの構築が続行されます。

したがって、後でopenConnection()URLオブジェクトを呼び出すと、メソッドはHandlerのプロトコルに固有のインスタンスを使用URLして接続オブジェクトを作成します。

この複雑なプロセスの目的は、プロトコルのオープンエンドセットのURL接続をサポートし、アプリケーションが新しいプロトコルのハンドラーを提供できるようにし、静的および動的の両方で既存のプロトコルの代わりに独自のハンドラーを使用できるようにすることです。(そして、コードは複数のスレッドに対処する必要があるため、上記で説明したよりも複雑です。)

これは、システムプロパティやリフレクションなどのJava固有のものとともに、多数のデザインパターン(キャッシュ、アダプタ、ファクトリオブジェクトなど)を利用しています。しかし、これらのデザインパターンなどを読んで理解していない場合は、それらを認識できない可能性があり、その結果、コードが完全に竹のようになっていることに気付く可能性があります。したがって、上記の私のアドバイス:最初に基本を学びましょう!!

于 2012-10-06T23:59:37.887 に答える
0

しかし、URLStreamHandler は抽象クラスであり、メソッド openConnection() は実装されていないため、ハンドラーがこのメソッドを呼び出すと、このメソッドを実装するサブクラスを見つける必要がありますよね?

URLStreamHandler で宣言または抽象化または実装する必要があります。次に、タイプ URLStreamHandler で URLStreamHandler を拡張するクラスのインスタンスを指定して openConnection() メソッドを呼び出すと、URLStreamHandler を拡張するクラスのインスタンスでオーバーライドしたものがあれば呼び出され、存在しない場合は呼び出されます。実装されている場合は URLStreamHandler のものであり、実装されていない場合は、おそらく例外または何かがスローされます。

于 2012-10-06T23:31:15.987 に答える
0

URL.javaを見てください。以前に URL オブジェクト自体に設定された をopenConnection使用します。URLStreamHandler

コンストラクターは、クラス名を動的に生成する を呼び出しgetURLStreamHandler、クラス ローダーを使用して適切なクラスをロードし、インスタンス化します。

于 2012-10-06T23:33:30.950 に答える