回答:
Java言語仕様では、raw型を次のように定義しています。
rawタイプは次のいずれかとして定義されます。
型引数リストを伴わないジェネリック型宣言の名前をとることによって形成される参照型。
要素型がraw型である配列型。
のスーパークラスまたはスーパーインターフェースから継承されていない
static
未加工の型の非メンバー型。R
R
以下に例を示します。
public class MyType<E> {
class Inner { }
static class Nested { }
public static void main(String[] args) {
MyType mt; // warning: MyType is a raw type
MyType.Inner inn; // warning: MyType.Inner is a raw type
MyType.Nested nest; // no warning: not parameterized type
MyType<Object> mt1; // no warning: type parameter given
MyType<?> mt2; // no warning: type parameter given (wildcard OK!)
}
}
これMyType<E>
は、パラメータ化されたタイプ(JLS 4.5)です。このタイプを単にMyType
略して口語的に呼ぶことは一般的ですが、技術的には名前はMyType<E>
です。
mt
上記の定義の最初の箇条書きによる生の型(およびコンパイル警告を生成)。inn
また、3番目の箇条書きでrawタイプがあります。
MyType.Nested
はパラメーター化された型のメンバー型ですが、パラメーター化された型MyType<E>
ではありませんstatic
。
mt1
、およびmt2
どちらも実際の型パラメーターで宣言されているため、生の型ではありません。
基本的に、raw型はジェネリックが導入される前と同じように動作します。つまり、以下はコンパイル時に完全に合法です。
List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!
上記のコードは問題なく実行されますが、次のコードもあるとします。
for (Object o : names) {
String name = (String) o;
System.out.println(name);
} // throws ClassCastException!
// java.lang.Boolean cannot be cast to java.lang.String
実行names
できない問題が発生したのは、以外のものが含まれているためinstanceof String
です。
あなたがしたい場合はおそらく、names
唯一含むようにString
、あなたは可能性があり、おそらく、まだ生の型を使用して、手動ですべてのチェック add
を自分で、その後、手動でキャストへString
のすべてのアイテムnames
。さらに良いのは、生の型を使用せず、 Javaジェネリックの力を利用してコンパイラーにすべての作業を任せることです。
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
もちろん、あなたがあればDOたいnames
できるようにBoolean
、あなたのようにそれを宣言することができList<Object> names
、そして上記のコードはコンパイルします。
<Object>
は型パラメーターとして使用する場合とどう違うのですか?以下は、Effective Java 2nd Edition、Item 23:Do n't use raw types in new code:
rawタイプ
List
とパラメーター化されたタイプの違いは何List<Object>
ですか?大まかに言えば、前者はジェネリック型チェックをオプトアウトしましたが、後者はコンパイラにあらゆる型のオブジェクトを保持できることを明示的に伝えました。あなたが渡すことができますがList<String>
種類のパラメータにList
は、タイプのパラメータにそれを渡すことはできませんList<Object>
。ジェネリックスにはサブタイプ規則がありList<String>
、生の型のサブタイプですList
が、パラメーター化された型のサブタイプではありませんList<Object>
。結果として、のようなraw型を使用する場合は型の安全性が失われList
ますが、のようなパラメーター化された型を使用する場合は失われませんList<Object>
。
ポイントを説明するために、を取り、List<Object>
を追加する次のメソッドを考えますnew Object()
。
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Javaのジェネリックスは不変です。A List<String>
はでないList<Object>
ため、次の場合はコンパイラ警告が生成されます。
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
appendNewObject
生の型List
をパラメーターとして取るように宣言した場合、これはコンパイルされ、ジェネリックから得られる型の安全性が失われます。
<?>
は、型パラメーターとして使用する場合とどのように異なりますか?List<Object>
、List<String>
などが全てですList<?>
、ちょうど彼らがちょうどだと言って誘惑することができるので、List
代わりに。ただし、大きな違いがありますList<E>
。aはのみを定義するため、add(E)
任意のオブジェクトだけをに追加することはできませんList<?>
。一方、raw型にList
は型の安全性がないため、add
ほぼ何でもにできますList
。
前のスニペットの次のバリエーションを検討してください。
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
コンパイラーは、List<?>
!の型の不変性に違反する可能性からユーザーを保護するというすばらしい仕事をしました。パラメータをraw型として宣言した場合List list
、コードはコンパイルされ、の型不変に違反しますList<String> names
。
JLS 4.8に戻る:
型として、パラメーター化された型の消去、または要素型がパラメーター化された型である配列型の消去を使用できます。このような型は、raw型と呼ばれます。
[...]
生の型のスーパークラス(それぞれ、スーパーインターフェイス)は、ジェネリック型のパラメーター化のスーパークラス(スーパーインターフェイス)の消去です。
スーパークラスまたはスーパーインターフェースから継承されていない
static
raw型のコンストラクター、インスタンスメソッド、または非フィールドのC
型は、に対応するジェネリック宣言でその型の消去に対応するraw型ですC
。
簡単に言うと、生の型が使用されると、コンストラクター、インスタンスメソッド、および非static
フィールドも消去されます。
次の例を見てください。
class MyType<E> {
List<String> getNames() {
return Arrays.asList("John", "Mary");
}
public static void main(String[] args) {
MyType rawType = new MyType();
// unchecked warning!
// required: List<String> found: List
List<String> names = rawType.getNames();
// compilation error!
// incompatible types: Object cannot be converted to String
for (String str : rawType.getNames())
System.out.print(str);
}
}
rawを使用するとMyType
、getNames
同様に消去され、rawが返されますList
。
JLS 4.6は引き続き次のことを説明します。
型消去は、コンストラクターまたはメソッドのシグニチャーを、パラメーター化された型または型変数を持たないシグニチャーにマップします。コンストラクターまたはメソッドシグネチャの消去は
s
、と同じ名前とs
で指定されたすべての仮パラメータータイプの消去で構成されるシグネチャですs
。メソッドまたはコンストラクターのシグニチャーが消去されると、メソッドの戻りタイプおよびジェネリックメソッドまたはコンストラクターのタイプパラメーターも消去されます。
ジェネリックメソッドのシグネチャの消去には、型パラメーターはありません。
:なぜ行動のこの種が発生するはずで、次のバグレポートは、マウリツィオCimadamore、コンパイラDEV、とアレックス・バックリー、JLSの著者の一人から、いくつかの考えが含まれていますhttps://bugs.openjdk.java.net/browse / JDK-6400189。(つまり、仕様が単純になります。)
JLS 4.8からの別の引用は次のとおりです。
生の型の使用は、レガシーコードの互換性への譲歩としてのみ許可されています。Javaプログラミング言語への総称の導入後に記述されたコードでは、生の型を使用しないことを強くお勧めします。Javaプログラミング言語の将来のバージョンでは、生の型を使用できなくなる可能性があります。
効果的なJava 2nd Editionには、これを追加する機能もあります。
生の型を使用するべきではないのに、なぜ言語デザイナーはそれらを許可したのですか?互換性を提供するため。
Javaプラットフォームは、ジェネリックが導入されてから20年を迎えようとしており、ジェネリックを使用しない膨大な量のJavaコードが存在していました。このすべてのコードが合法であり、ジェネリックを使用する新しいコードと相互運用可能であることが重要であると見なされました。パラメータ化された型のインスタンスを、通常の型で使用するように設計されたメソッドに渡すこと、およびその逆も可能です。移行の互換性と呼ばれるこの要件により、rawタイプをサポートする決定が下されました。
要約すると、生の型は決して新しいコードで使用すべきではありません。常にパラメータ化された型を使用する必要があります。
残念ながら、Javaジェネリックは具体化されていないため、新しいコードでraw型を使用する必要がある例外が2つあります。
List.class
、ないList<String>.class
instanceof
オペランド、例えばo instanceof Set
、ないo instanceof Set<String>
o instanceof Set<?>
、生の型を回避する構文も許可されています(この場合は表面的なものです)。
n
、同じコードを持つ実装クラスごとにリモートBean を作成する必要がなくなります。
Javaのraw型とは何ですか?なぜそれらが新しいコードで使用されるべきではないとしばしば聞かれるのですか?
Raw型はJava言語の古代の歴史です。初めはありましたCollections
、そして彼らはObjects
それ以上何も持っていませんでした。Collections
からObject
目的の型への必要なキャストに対するすべての操作。
List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);
これはほとんどの場合機能しましたが、エラーが発生しました
List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
古いタイプレスコレクションはタイプセーフを適用できなかったため、プログラマはコレクション内に何を格納したかを覚える必要がありました。
ジェネリックスはこの制限を回避するために発明されたため、開発者は格納された型を1回宣言し、コンパイラは代わりにそれを行います。
List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine
比較のため:
// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings
Compareableインターフェースをより複雑に:
//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
int id;
public int compareTo(Object other)
{return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
int id;
public int compareTo(MyCompareAble other)
{return this.id - other.id;}
}
生の型でCompareAble
インターフェイスを実装することは不可能であることに注意してくださいcompareTo(MyCompareAble)
。それらを使用すべきでない理由:
Object
保存されてCollection
いるものは、使用する前にキャストする必要がありますObject
コンパイラの機能:ジェネリックスは下位互換性があり、生の型と同じJavaクラスを使用します。魔法は主にコンパイル時に発生します。
List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);
次のようにコンパイルされます:
List someStrings = new ArrayList();
someStrings.add("one");
String one = (String)someStrings.get(0);
これは、生の型を直接使用した場合と同じコードです。思想私は何が起こるかわからないんだけどCompareAble
インターフェース、私はそれが2つの作成していることを推測compareTo
1を取って、機能をMyCompareAble
、その他の撮影をAN Object
し、それを鋳造後最初にそれを渡します。
生の型に代わるものは何ですか:ジェネリックを使用してください
raw型は、型引数のないジェネリッククラスまたはインターフェースの名前です。たとえば、一般的なBoxクラスが与えられた場合:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
のパラメーター化された型を作成するにBox<T>
は、仮型パラメーターの実際の型引数を指定しますT
。
Box<Integer> intBox = new Box<>();
実際の型引数を省略した場合は、次のような生の型を作成しますBox<T>
。
Box rawBox = new Box();
したがって、Box
はジェネリック型のraw型ですBox<T>
。ただし、非ジェネリッククラスまたはインターフェイス型はraw型ではありません。
多くのAPIクラス(Collectionsクラスなど)はJDK 5.0より前のジェネリックではなかったため、生の型はレガシーコードに表示されます。rawタイプを使用すると、基本的にジェネリック前の動作がBox
得られます-a はObject
s を提供します。下位互換性のために、パラメーター化された型をraw型に割り当てることができます。
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
ただし、生の型をパラメーター化された型に割り当てると、警告が表示されます。
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
また、raw型を使用して、対応するジェネリック型で定義されたジェネリックメソッドを呼び出すと、警告が表示されます。
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
警告は、生の型がジェネリック型チェックをバイパスし、安全でないコードのキャッチをランタイムに延期することを示しています。したがって、生の型の使用は避けてください。
Type Erasureセクションには、Javaコンパイラがraw型を使用する方法に関する詳細情報があります。
前述のように、レガシーコードとジェネリックコードを混在させると、次のような警告メッセージが表示される場合があります。
注:Example.javaは、チェックされていない、または安全でない操作を使用します。
注:詳細については、-Xlint:uncheckedを指定して再コンパイルしてください。
これは、次の例に示すように、raw型を操作する古いAPIを使用している場合に発生する可能性があります。
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
「チェックされていない」という用語は、型の安全性を確保するために必要なすべての型チェックを実行するのに十分な型情報がコンパイラにないことを意味します。「チェックされていない」警告はデフォルトで無効になっていますが、コンパイラからヒントが得られます。「チェックされていない」警告をすべて表示するには、-Xlint:uncheckedを指定して再コンパイルします。
前の例を-Xlint:uncheckedで再コンパイルすると、次の追加情報が表示されます。
WarningDemo.java:4: warning: [unchecked] unchecked conversion
found : Box
required: Box<java.lang.Integer>
bi = createBox();
^
1 warning
未チェックの警告を完全に無効にするには、-Xlint:-uncheckedフラグを使用します。@SuppressWarnings("unchecked")
注釈は、未チェックの警告を抑制します。@SuppressWarnings
構文に慣れていない場合は、注釈を参照してください。
元のソース:Javaチュートリアル
Javaの「raw」型は、ジェネリックではなく、タイプセーフなジェネリック型パラメーターではなく「raw」オブジェクトを処理するクラスです。
たとえば、Javaジェネリックが利用可能になる前は、次のようなコレクションクラスを使用します。
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
オブジェクトをリストに追加するとき、オブジェクトのタイプは関係ありません。リストからオブジェクトを取得するときは、期待するタイプに明示的にキャストする必要があります。
リストに入れることができるオブジェクトのタイプを明示的に指定する必要があるため、ジェネリックスを使用して、「不明な」要素を削除します。
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
ジェネリックでは、get呼び出しからのオブジェクトをキャストする必要がないことに注意してください。コレクションは、MyObjectでのみ機能するように事前定義されています。これこそがジェネリック医薬品の主な原動力です。ランタイムエラーの原因を、コンパイル時にチェックできるものに変更します。
?
まだ使用するとタイプセーフティが提供されます。私はそれを私の答えでカバーしました。
private static List<String> list = new ArrayList<String>();
type-parameterを指定する必要があります。
警告は、ジェネリックをサポートするように定義されている型は、生の形式を使用するのではなく、パラメーター化する必要があることを示しています。
List
ジェネリックをサポートするように定義されていpublic class List<E>
ます:。これにより、コンパイル時にチェックされる多くのタイプセーフな操作が可能になります。
private static List<String> list = new ArrayList<>();
rawタイプとは何ですか?なぜそれらが新しいコードで使用されるべきではないとしばしば聞かれるのですか?
「生の型」とは、パラメータ化された型の型引数を指定せずにジェネリッククラスを使用するList
ことですList<String>
。たとえば、の代わりに使用します。ジェネリックがJavaに導入されたとき、ジェネリックを使用するようにいくつかのクラスが更新されました。これらのクラスを(生の型)として(型引数を指定せずに)使用すると、レガシーコードをコンパイルできます。
「Rawタイプ」は、下位互換性のために使用されます。type引数を指定したジェネリッククラスを使用すると、より強力な型指定が可能になるため、新しいコードでの使用はお勧めできません。これにより、コードの理解しやすさが向上し、潜在的な問題を早期に発見できる場合があります。
生の型を使用できない場合の代替策は何ですか?
推奨される代替策は、適切な型引数(などList<String>
)を使用して、意図したとおりにジェネリッククラスを使用することです。これにより、プログラマーはタイプをより具体的に指定でき、変数またはデータ構造の使用目的について将来のメンテナーにより多くの意味を伝え、コンパイラーはより優れたタイプセーフを実施できます。これらの利点により、コードの品質が向上し、コーディングエラーの発生を防ぐことができます。
たとえば、プログラマが 'names'という名前のList変数に文字列のみが含まれていることを確認するメソッドの場合:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
polygenelubricants
からの「生の型」参照を自分の回答にコピーしたくなったのですが、自分の回答で使用するために残しておきます。
コンパイラはあなたにこれを書くことを望みます:
private static List<String> list = new ArrayList<String>();
それ以外の場合は、好きなタイプをに追加しlist
て、インスタンス化をnew ArrayList<String>()
無意味なものにすることができます。Javaジェネリックはコンパイル時の機能のみであるため、「生の型」の参照に割り当てられている場合、で作成されたオブジェクトは要素または要素new ArrayList<String>()
を喜んで受け入れます。オブジェクト自体は、どの型を含むかについて何も知らず、コンパイラのみが認識します。Integer
JFrame
List
ここで、コンセプトを明確にできる複数のケースを検討しています
1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();
ArrayList<String> arr
それはArrayList
型の参照変数String
に参照ArralyList
型のオブジェクトString
。つまり、String型のオブジェクトのみを保持できます。
String
Rawタイプではないので厳密であり、警告を発することはありません。
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23); //prone to compile time error.
//error: no suitable method found for add(int)
この場合ArrayList<String> arr
は厳密な型ですが、オブジェクトnew ArrayList();
は生の型です。
arr.add("hello"); //alone this compile but raise the warning.
arr.add(23); //again prone to compile time error.
//error: no suitable method found for add(int)
こちらarr
はStrictタイプです。したがって、を追加すると、コンパイル時エラーが発生しますinteger
。
警告:-
Raw
タイプオブジェクトは、Strict
タイプの参照変数に参照されていArrayList
ます。
この場合ArrayList arr
はrawタイプですが、オブジェクトnew ArrayList<String>();
はStrictタイプです。
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
arr
Rawタイプであるため、任意のタイプのオブジェクトが追加されます。
警告:-
Strict
タイプオブジェクトは、raw
タイプ参照変数に参照されています。
生型は、の欠如であるtypeパラメータジェネリック型を使用しました。
rawタイプは、sのdouble
a Set
であると想定されていたものにa を挿入するなどのランタイムエラーを引き起こす可能性があるため、使用しないでくださいint
。
Set set = new HashSet();
set.add(3.45); //ok
からのものを取得するとき、Set
何が出てくるのかわかりません。それがすべてであると想定しint
、それをにキャストするとしInteger
ます。double
3.45が登場する実行時の例外。
ではtypeパラメータあなたに追加しSet
、一度にコンパイルエラーが発生します。このプリエンプティブエラーにより、ランタイム中に何かが爆発する前に問題を修正できます(したがって、時間と労力を節約できます)。
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
生の型があなたを噛む別のケースがあります:
public class StrangeClass<T> {
@SuppressWarnings("unchecked")
public <X> X getSomethingElse() {
return (X)"Testing something else!";
}
public static void main(String[] args) {
final StrangeClass<String> withGeneric = new StrangeClass<>();
final StrangeClass withoutGeneric = new StrangeClass();
final String value1,
value2;
// Compiles
value1 = withGeneric.getSomethingElse();
// Produces compile error:
// incompatible types: java.lang.Object cannot be converted to java.lang.String
value2 = withoutGeneric.getSomethingElse();
}
}
受け入れられた回答で述べたように、生の型のコード内のジェネリックのサポートはすべて失われます。すべての型パラメーターは、消去(上記の例ではObject
)に変換されます。
言っていることはあなたlist
がList
特定されていないオブジェクトのことです。つまり、Javaはリスト内にどのようなオブジェクトがあるかを認識していません。次に、リストを反復処理する場合は、すべての要素をキャストして、その要素(この場合は文字列)のプロパティにアクセスできるようにする必要があります。
一般に、コレクションをパラメーター化することをお勧めします。変換の問題は発生せず、パラメーター化された型の要素のみを追加でき、エディターは選択する適切なメソッドを提供します。
private static List<String> list = new ArrayList<String>();
raw型は、型引数のないジェネリッククラスまたはインターフェースの名前です。たとえば、一般的なBoxクラスが与えられた場合:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Boxのパラメーター化された型を作成するには、仮型パラメーターTに実際の型引数を指定します。
Box<Integer> intBox = new Box<>();
実際の型引数が省略されている場合は、ボックスの生の型を作成します。
Box rawBox = new Box();
生の型を避ける
生の型とは、型パラメーターを指定せずにジェネリック型を使用することを指します。
たとえば、
リストは生の型List<String>
ですが、パラメーター化された型です。
ジェネリックがJDK 1.5で導入されたとき、生の型は古いバージョンのJavaとの下位互換性を維持するためにのみ保持されていました。rawタイプを使用することも可能ですが、
彼らは避けるべきです:
彼らはあまり表現力で、パラメータ化された型と同じように自己文書をない 例
import java.util.*;
public final class AvoidRawTypes {
void withRawType() {
//Raw List doesn't self-document,
//doesn't state explicitly what it can contain
List stars = Arrays.asList("Arcturus", "Vega", "Altair");
Iterator iter = stars.iterator();
while (iter.hasNext()) {
String star = (String) iter.next(); //cast needed
log(star);
}
}
void withParameterizedType() {
List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
for (String star: stars) {
log(star);
}
}
private void log(Object message) {
System.out.println(Objects.toString(message));
}
}
参照用:https : //docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
このページは、いくつかのサンプル演習を行ってまったく同じ困惑した後に見つかりました。
==============サンプルから提供されたように、このコードから移行しました===============
public static void main(String[] args) throws IOException {
Map wordMap = new HashMap();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
======================このコードへ========================
public static void main(String[] args) throws IOException {
// replace with TreeMap to get them sorted by name
Map<String, Integer> wordMap = new HashMap<String, Integer>();
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
countWord(wordMap, args[i]);
}
} else {
getWordFrequency(System.in, wordMap);
}
for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
Entry<String, Integer> entry = i.next();
System.out.println(entry.getKey() + " :\t" + entry.getValue());
}
}
================================================== =============================
安全かもしれませんが、哲学を混乱させるのに4時間かかりました...
生の型は、表現したいものを表現するときに問題ありません。
たとえば、逆シリアル化関数はを返す可能性List
がありますが、リストの要素の型はわかりません。だから、List
ここでは、適切な戻り値の型があります。