144

Java でクラスが final として宣言されていることを知ったときから、java.lang.Stringそれはなぜなのか疑問に思っていました。当時は答えが見つかりませんでしたが、この投稿: How to create a replica of String class in Java? 私の質問を思い出しました。

確かに、String は私が今まで必要としていたすべての機能を提供します。また、String クラスの拡張を必要とする操作については考えたこともありませんでしたが、それでも、誰かが何を必要としているかはわかりません!

では、デザイナーが最終的なものにすることを決定したときの意図を知っている人はいますか?

4

16 に答える 16

89

文字列を不変オブジェクトとして実装すると非常に便利です。不変性についてさらに理解するには、不変性について読む必要があります。

不変オブジェクトの利点の 1 つは、

複製を単一のインスタンスにポイントすることで、複製を共有できます。

ここから)。

String が final でない場合は、サブクラスを作成して、「String として見た場合」に似ている 2 つの文字列を持つことができますが、実際には異なります。

于 2010-01-15T01:17:46.710 に答える
60

これは、上記の回答で既に言及されている2つの理由を概説する素晴らしい記事です。

  1. セキュリティ: システムは、変更されることを心配することなく、読み取り専用情報の機密ビットを配布できます
  2. パフォーマンス: 不変データは、スレッドセーフにするのに非常に役立ちます。

そして、これはおそらくその記事の中で最も詳細なコメントです。これは、Java の文字列プールとセキュリティの問題に関係しています。文字列プールに入れるものを決定する方法についてです。文字のシーケンスが同じである場合に両方の文字列が等しいと仮定すると、誰が最初にそこに到達するかという競合状態とそれに伴うセキュリティの問題があります。そうでない場合、文字列プールには冗長な文字列が含まれるため、最初にそれを持つ利点が失われます。自分で読んでみませんか?


String を拡張すると、equals と intern に大混乱が生じます。JavaDoc は等しいと言います:

この文字列を指定されたオブジェクトと比較します。引数が null ではなく、このオブジェクトと同じ文字シーケンスを表す String オブジェクトである場合にのみ、結果は true になります。

java.lang.Stringfinal ではないと仮定すると、 aSafeStringは a と等しくなる可能性がStringあり、その逆も成り立ちます。これらは同じ文字列を表すためです。

--に申し込んだ場合intern、JVM の文字列プールに入りますか? 保持されている参照先およびすべてのオブジェクトは、JVM の存続期間中その場でロックされます。一連の文字を最初にインターンするのは誰になるかについて競合状態が発生します。おそらくあなたが勝つか、 a 、または別のクラスローダー (したがって別のクラス) によってロードされる a かもしれません。SafeStringSafeStringClassLoaderSafeStringSafeStringStringSafeString

プールへの競争に勝った場合、これは真のシングルトンとなり、人々はリフレクションとsecretKey.intern().getClass().getClassLoader().

または、JVM は、具体的な String オブジェクトのみ (およびサブクラスなし) がプールに追加されるようにすることで、この穴を塞ぐことができます。

SafeStringequals が!= Stringthen SafeString.intern!=String.internのように実装されている場合SafeString、プールに追加する必要があります。プールは<Class, String>代わりにのプールになり、プール<String>に入る必要があるのは新しいクラスローダーだけです。

于 2010-01-15T02:14:59.020 に答える
27

String が immutable または final である絶対的に最も重要な理由は、それがクラス ローディング メカニズムによって使用され、したがって深遠で基本的なセキュリティ面を備えていることです。

String が変更可能または final でない場合、「java.io.Writer」をロードする要求が「mil.vogoon.DiskErasingWriter」をロードするように変更された可能性があります。

参照 : Java で文字列が不変である理由

于 2011-05-21T03:55:31.987 に答える
15

Stringは Java の非常にコアなクラスであり、多くのことが、不変であるなど、特定の方法で動作することに依存しています。

クラスを作成するfinalことで、これらの仮定を破る可能性のあるサブクラスを防ぎます。

現在でも、リフレクションを使用すると、文字列を壊す(値またはハッシュコードを変更する) ことができることに注意してください。リフレクションは、セキュリティ マネージャで停止できます。もしそうStringでなければfinal、誰もがそれを行うことができました。

宣言されていない他のクラスをfinal使用すると、多少壊れたサブクラスを定義できます (Listたとえば、間違った位置に を追加する可能性があります) が、少なくとも JVM はコア操作のためにそれらに依存しません。

于 2010-01-15T01:23:18.953 に答える
6

ブルーノが言ったように、それは不変性についてです。文字列だけでなく、Double、Integer、Characterなどのラッパーについても同様です。これには多くの理由があります。

  • スレッドセーフ
  • 安全
  • Java自体によって管理されるヒープ(ガベージコレクションが異なる方法で収集される通常のヒープとは異なります)
  • メモリ管理

基本的には、プログラマーとして、文字列が変更されないことを確認できるようにするためです。それがどのように機能するかを知っていれば、メモリ管理を改善することもできます。「hello」のように、2つの同じ文字列を次々に作成してみてください。デバッグすると、それらが同一のIDを持っていることに気付くでしょう。これは、それらがまったく同じオブジェクトであることを意味します。これは、Javaで実行できるためです。文字列が可変である場合、これは不可能です。彼らは決して変わらないので、彼らは私と同じようにすることができます。したがって、1,000,000個の文字列「hello」を作成することにした場合、実際に行うことは、「hello」への1,000,000個のポインタを作成することです。同様に、文字列の関数、またはその理由のラッパーをすべて使用すると、別のオブジェクトが作成されます(オブジェクトIDをもう一度見てください-変更されます)。

さらに、Javaでのfinalは、必ずしもオブジェクトが変更できないことを意味するわけではありません(たとえば、C ++とは異なります)。これは、それが指すアドレスは変更できないが、そのプロパティや属性は変更できることを意味します。したがって、場合によっては不変性と最終の違いを理解することが非常に重要になる場合があります。

HTH

参照:

于 2010-01-15T01:36:53.593 に答える
2

実装を簡素化するためだったのかもしれません。クラスのユーザーが継承できるクラスを設計すると、設計で考慮すべきまったく新しい一連のユースケースが得られます。X 保護フィールドでこれまたはあれを行うとどうなりますか? それを最終的にすることで、彼らは公開インターフェースを正しく機能させることに集中し、それがしっかりしていることを確認できます。

于 2010-01-15T01:19:51.850 に答える
2

より良い実装が得られないようにするためです。もちろん、それはインターフェースである必要があります。

[編集] ああ、無知な反対票が増えています。答えは完全に深刻です。愚かな String 実装を何度か回避するようにプログラムする必要があり、パフォーマンスと生産性が大幅に低下しました。

于 2011-03-07T21:45:03.687 に答える
2

他の回答 (セキュリティ、不変性、パフォーマンス) で言及されている理由に加えて、String特別な言語サポートがあることに注意する必要があります。Stringリテラルを書くことができ、+演算子がサポートされています。プログラマが をサブクラスString化できるようにすると、次のようなハックが助長されます。

class MyComplex extends String { ... }

MyComplex a = new MyComplex("5+3i");
MyComplex b = new MyComplex("7+4i");
MyComplex c = new MyComplex(a + b);   // would work since a and b are strings,
                                      // and a string + a string is a string.
于 2010-04-22T12:51:46.720 に答える
1

ストリングのファイナリティも標準としてそれらを守ります。C++ では文字列のサブクラスを作成できるため、すべてのプログラミング ショップが独自のバージョンの文字列を持つことができます。これは、強力な基準の欠如につながります。

于 2012-12-10T18:05:50.773 に答える
1

まあ、私はいくつかの異なる考えを持っています。私が正しいかどうかはわかりませんが、Java String はプリミティブデータ型として扱うことができる唯一のオブジェクトです。つまり、String オブジェクトをString name="javaとして作成できます。 " . 現在、参照によるコピーではなく値によるコピーである他のプリミティブデータ型と同様に、文字列は同じ動作をすることが期待されるため、文字列は最終的なものです。それは私がそれを考えたことです。完全に非論理的である場合は無視してください。

于 2010-12-08T20:08:45.610 に答える
-2

一度文字列を作成すると、それはオブジェクトであると見なされ、それを変更したい場合は不可能であり、新しいオブジェクトが作成されます。

于 2016-02-24T14:00:21.707 に答える