なぜ配列の長さを属性としてarray.length
持っているのstr.length()
か、そしてStringについてはメソッドを持っているのか?
何か理由はありますか?
なぜ配列の長さを属性としてarray.length
持っているのstr.length()
か、そしてStringについてはメソッドを持っているのか?
何か理由はありますか?
回答:
最初に、同じ目的で3つの方法を紹介します。
length
- 配列(int[]
、double[]
、String[]
) -配列の長さを知ります
length()
- 文字列の関連するオブジェクト(String
、StringBuilder
など) -文字列の長さを知ります
size()
- コレクションオブジェクト(ArrayList
、Set
など) -コレクションのサイズを知ります
今すぐ忘れるlength()
だけで考えるlength
とsize()
。
length
はメソッドではないため、オブジェクトに対して機能しないことは完全に理にかなっています。配列でのみ機能します。
size()
その名前はそれをよりよく説明しており、メソッドなので、私がそこで述べたように、コレクション(コレクションフレームワーク)で動作するオブジェクトの場合に使用されます。
今度
はlength()
:
文字列はプリミティブ配列ではないため(使用できないため.length
)、コレクションでもないため(使用できないため).size()
、別のものが必要ですlength()
(違いを維持して目的を果たす)。
答えとして、なぜ?
私はそれが便利で、覚えやすく、使いやすく、フレンドリーだと思います。
少し単純化すると、配列は特殊なケースであり、通常のクラスではない(プリミティブに少し似ていますが、そうではない)と考えることができます。文字列とすべてのコレクションはクラスなので、サイズ、長さなどを取得するメソッドです。
設計時の理由はパフォーマンスだったと思います。もし彼らが今日それを作成したなら、おそらく彼らは代わりに配列支援のコレクションクラスのようなものを思いついたでしょう。
興味のある方は、生成されたコードの2つの違いを説明する小さなコードスニペットを以下に示します。最初にソースを示します。
public class LengthTest {
public static void main(String[] args) {
int[] array = {12,1,4};
String string = "Hoo";
System.out.println(array.length);
System.out.println(string.length());
}
}
バイトコードのそれほど重要ではない部分を切り取り、javap -c
クラスで実行すると、最後の2行が次のようになります。
20: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: arraylength
25: invokevirtual #4; //Method java/io/PrintStream.println:(I)V
28: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
31: aload_2
32: invokevirtual #5; //Method java/lang/String.length:()I
35: invokevirtual #4; //Method java/io/PrintStream.println:(I)V
最初のケース(20-25)では、コードはJVMに配列のサイズを要求するだけです(JNIでは、これはGetArrayLength()への呼び出しでした)が、ストリングのケース(28-35)では、長さを取得するメソッド呼び出し。
1990年代の半ば、優れたJITなどがなければ、java.util.Vector(または類似の何か)のみがあり、クラスのように実際には動作しないが高速な言語構成要素がないと、完全にパフォーマンスが低下していました。もちろん、プロパティコールをメソッド呼び出しとしてマスクしてコンパイラで処理することもできますが、実際のクラスではないものにメソッドがあると、さらに混乱するでしょう。
Vector
Java言語が配列をサポートしていない場合、どのように実装しますか?
検討してください:
int[] myArray = new int[10];
String myString = "hello world!";
List<int> myList = new ArrayList<int>();
myArray.length // Gives the length of the array
myString.length() // Gives the length of the string
myList.size() // Gives the length of the list
文字列と配列は異なる時期に設計されたため、異なる規則を使用することになった可能性が非常に高いです。正当化の理由の1つは、文字列は内部で配列length()
を使用するため、同じ情報の重複を避けるためにメソッドが使用されたことです。もう1つは、メソッドを使用するlength()
と、配列のサイズも変更できない場合でも、文字列の不変性を強調するのに役立ちます。
結局のところ、これは進化した矛盾であり、言語がゼロから再設計された場合には間違いなく修正されます。私が知る限り、他の言語(C#、Python、Scalaなど)が同じことを行うことはないので、これは言語の一部として最終的に発生したわずかな欠陥である可能性があります。
とにかく間違ったものを使用すると、エラーが発生します。
Javaでは、配列は実際にデータを保持する構造とは別に長さを格納します。配列を作成するときに、その長さを指定すると、それが配列の定義属性になります。長さNの配列に対して何をしても(値を変更したり、nullを出力したりするなど)、常に長さNの配列になります。
文字列の長さは偶発的です。これは文字列の属性ではなく、副産物です。Java文字列は実際には不変ですが、内容を変更できる場合は、長さを変更できます。最後の文字をノックオフすると(可能な場合)、長さが短くなります。
これは細かい違いであることを理解しており、反対票が投じられることもありますが、それは事実です。長さ4の配列を作成する場合、その4つの長さは配列の定義的な特性であり、何が保持されているかに関係なくtrueです。「犬」を含む文字列を作成すると、たまたま4つの文字が含まれるため、その文字列の長さは4になります。
これは、1つを属性で、もう1つをメソッドで行う正当な理由だと思います。実は、それは意図しない不整合に過ぎないかもしれませんが、私には常に理にかなっており、これは常に私がそれについて考えてきた方法です。
配列の場合、次の恐れがあるため、メソッドを介して長さを取得できないと教えられました:プログラマーは、ループに入る前にローカル変数に長さを割り当てるだけです(条件付きで配列の長さを使用するforループを考えてください)。関数呼び出しを削減するためにそうするでしょう(それによってパフォーマンスが向上します)。問題は、ループ中に長さが変更される可能性があり、変数が変更されないことです。
配列が作成されるたびに、そのサイズが指定されます。したがって、長さは構築属性と見なすことができます。Stringの場合、基本的にはchar配列です。長さはchar配列のプロパティです。すべてがこのフィールドを必要とするわけではないため、フィールドとして長さを指定する必要はありません。 http://www.programcreek.com/2013/11/start-from-length-length-in-java/
私は偉大にいくつかの発言を追加したいの答えによってフレドリック。
オブジェクトは、あるクラスのインスタンスまたはアレイ。
そのため、配列は確かにJavaで非常に特別な役割を果たします。なぜだろう。
現在の実装配列は、パフォーマンス向上のために重要である、またはそうであったと主張することができます。しかしそれは内部構造であり、公開されるべきではありません。
もちろん、プロパティコールをメソッド呼び出しとしてマスクしてコンパイラで処理することもできますが、実際のクラスではないものにメソッドがあると、さらに混乱するでしょう。
スマートコンパイラーの最適化がより良い選択であったと私はFredrikに同意します。これは問題も解決します。配列にプロパティを使用しても、文字列やその他の(不変の)コレクション型の問題は解決されていません。たとえば、クラス定義で確認できるようstring
に、char
配列に基づいているためです。のString
:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; // ...
また、配列はからすべてのメソッドをjava.lang.Object
継承するので、さらに混乱することには同意しません。
エンジニアとして、私は「いつもこのようになってきたから」という答えが本当に好きではありません。そしてもっと良い答えがあればいいのに。しかし、この場合はそうです。
tl; dr
私の意見では、これはJavaの設計上の欠陥であり、この方法で実装すべきではありませんでした。