Java言語仕様では、次のように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番目の箇条書きによる生の型もあります。
MyType.Nested
は、static
であるため、パラメーター化された型MyType<E>
のメンバー型であっても、パラメーター化された型ではありません。
mt1
とmt2
は両方とも実際の型パラメーターで宣言されているため、生の型ではありません。
基本的に、生の型はジェネリックが導入される前と同じように動作します。つまり、以下はコンパイル時に完全に合法です。
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
のみを含める場合、couldおそらく生のタイプを使用し、手動ですべてをチェックadd
を自分で、そして手動でキャスト = String
のすべての項目をnames
に。 さらに良い、ただし生のタイプを使用することはできませんコンパイラにすべての作業を任せる Javaジェネリックの。
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
もちろん、DOnames
でBoolean
を許可したい場合は、List<Object> names
として宣言すれば、上記のコードがコンパイルされます。
<Object>
を型パラメーターとして使用することとどう違うのですか?以下は、Effective Java 2nd Edition、Item 23:新しいコードで生のタイプを使用しないからの引用です。
生のタイプ
List
とパラメーター化されたタイプList<Object>
の違いは何ですか?大まかに言って、前者はジェネリック型チェックをオプトアウトしましたが、後者はコンパイラに任意の型のオブジェクトを保持できることを明示的に伝えました。List<String>
をList
型のパラメーターに渡すことはできますが、List<Object>
型のパラメーターに渡すことはできません。ジェネリックにはサブタイプ規則があり、List<String>
は生のタイプList
のサブタイプですが、パラメーター化されたタイプList<Object>
のサブタイプではありません。結果として、List
のような生の型を使用する場合、型の安全性が失われますが、List<Object>
のようなパラメータ化された型を使用する場合はそうではありません。
ポイントを説明するために、List<Object>
を取り、new Object()
を追加する次のメソッドを検討してください。
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Javaのジェネリックは不変です。 List<String>
はList<Object>
ではないため、次のコードはコンパイラの警告を生成します。
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
appendNewObject
を宣言して生のタイプList
をパラメーターとして使用すると、これはコンパイルされ、ジェネリックから得られるタイプセーフティが失われます。
<?>
を型パラメーターとして使用することとどう違うのですか?List<Object>
、List<String>
などはすべてList<?>
であるため、単にList
であると言いたくなるかもしれません。ただし、大きな違いがあります。List<E>
はadd(E)
のみを定義するため、任意のオブジェクトをList<?>
に追加することはできません。一方、生の型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<?>
!の型の不変性に潜在的に違反することからあなたを保護する素晴らしい仕事をしました!パラメーターを未加工の型List list
として宣言した場合、コードがコンパイルされ、List<String> names
の型不変式に違反します。
JLS 4.8に戻る:
型として、パラメータ化された型の消去または要素型がパラメータ化された型である配列型の消去を使用することができます。 そのようなタイプはraw type。と呼ばれます
[...]
未加工の型のスーパークラス(それぞれスーパーインターフェース)は、ジェネリック型のパラメーター化のいずれかのスーパークラス(スーパーインターフェース)の消去です。
スーパークラスまたはスーパーインターフェースから継承されない生のタイプ
static
のコンストラクター、インスタンスメソッド、または非C
フィールドのタイプは、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);
}
}
生のMyType
を使用すると、getNames
も消去されるため、生のList
が返されます。
JLS 4.6 は引き続き以下を説明します:
型消去は、コンストラクターまたはメソッドのシグネチャを、パラメーター化された型または型変数を持たないシグネチャにマッピングします。コンストラクターまたはメソッドシグネチャの消去
s
は、s
と同じ名前と、s
で指定されたすべての仮パラメーター型の消去で構成される署名です。メソッドまたはコンストラクターの署名が消去されると、メソッドの戻り値の型およびジェネリックメソッドまたはコンストラクターの型パラメーターも消去されます。
ジェネリックメソッドの署名の消去には、型パラメーターはありません。
次のバグレポートには、コンパイラ開発者のMaurizio Cimadamoreと、JLSの作者の1人であるAlex Buckleyによる、このような動作が発生する理由についての考えが含まれています。 https://bugs.openjdk.Java .net/browse/JDK-6400189 。 (要するに、仕様がより簡単になります。)
JLS 4.8からの別の引用文を次に示します。
生の型の使用は、レガシーコードの互換性の譲歩としてのみ許可されています。 Javaプログラミング言語への汎用性の導入後に記述されたコードで生の型を使用することは強く推奨されません。 Javaプログラミング言語の将来のバージョンでは、rawタイプの使用が禁止される可能性があります。
Effective Java 2nd Editionには以下を追加することもできます。
生の型を使用すべきではないのに、言語設計者がそれらを許可したのはなぜですか?互換性を提供するため。
Javaプラットフォームは、ジェネリックが導入されてから20年を迎えようとしており、ジェネリックを使用しないJavaコードが大量に存在していました。このすべてのコードが合法であり、ジェネリックを使用する新しいコードと相互運用可能であることが重要であると見なされました。パラメーター化された型のインスタンスを、通常の型で使用するように設計されたメソッドに渡すこと、およびその逆の場合は合法でなければなりませんでした。 移行の互換性として知られるこの要件により、生のタイプをサポートするという決定が下されました。
要約すると、新しいコードでは生の型を使用しないでください。 パラメータ化された型を常に使用する必要があります。
残念ながら、Javaジェネリックは非具体化されているため、新しいコードで生の型を使用する必要がある2つの例外があります。
List.class
ではなく、List<String>.class
instanceof
オペランド、例: o instanceof Set
ではなく、o instanceof Set<String>
Javaの生の型は何ですか、そしてなぜ私はそれらが新しいコードで使われるべきではないとしばしば聞くのですか?
生の型は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;}
}
生の型でcompareTo(MyCompareAble)
とCompareAble
インターフェースを実装することは不可能であることに注意してください。なぜあなたはそれらを使うべきではない:
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
関数が作成され、一方はMyCompareAble
を取り、もう一方はObject
を取り、それをキャストした後に最初のものに渡します。
生の型に代わるものは何ですか: generics を使用してください
生の型は型引数のない総称クラスまたはインタフェースの名前です。たとえば、一般的な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
はジェネリック型Box<T>
の生の型です。ただし、非ジェネリッククラスまたはインタフェース型は生の型ではありません。
多くのAPIクラス(Collectionsクラスなど)はJDK 5.0より前は汎用的ではなかったため、生の型はレガシーコードで表示されます。生の型を使うとき、あなたは本質的に前ジェネリックの振舞いを得ます - Box
はあなたにObject
sを与えます。下位互換性のために、パラメータ化された型をその生の型に代入することができます。
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
対応するジェネリック型で定義されているジェネリックメソッドを生の型で呼び出すと、警告も表示されます。
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
この警告は、生の型が一般的な型チェックを迂回し、危険なコードの捕捉を実行時に延期することを示しています。したがって、生の型を使わないでください。
「型の消去」セクションには、Javaコンパイラが生の型をどのように使用するかについてのより多くの情報があります。
前述のように、従来のコードと一般的なコードを混在させると、次のような警告メッセージが表示されることがあります。
注意:Example.Javaでは、未チェックまたは危険な操作が使用されています。
注:詳細については、-Xlint:チェックなしで再コンパイルしてください。
次の例に示すように、これは生の型で動作する古い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チュートリアル
private static List<String> list = new ArrayList<String>();
Type-parameterを指定してください。
この警告は、 generics をサポートするように定義されている型は、その生の形式を使用するのではなく、パラメータ化する必要があることを助言します。
List
は総称をサポートするために定義されています:public class List<E>
。これにより、コンパイル時にチェックされる多くの型保証された操作が可能になります。
Javaの "raw"型は、型保証されたジェネリック型パラメータではなく、非ジェネリックで "raw"オブジェクトを扱うクラスです。
たとえば、Javaジェネリックスが利用可能になる前は、次のようなコレクションクラスを使用していました。
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
オブジェクトをリストに追加するとき、それがどのタイプのオブジェクトであるかは関係ありません。また、リストから取得するときには、期待しているタイプに明示的にキャストする必要があります。
ジェネリックスを使用すると、リストに入れることができるオブジェクトの種類を明示的に指定する必要があるため、 "unknown"ファクタを削除します。
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>();
そうでなければ、あなたが好きな型をlist
に追加することができ、インスタンス化をnew ArrayList<String>()
として無意味にすることができます。 Javaジェネリックはコンパイル時の機能のみであるため、 "raw type" Integer
の参照に割り当てられた場合、new ArrayList<String>()
で作成されたオブジェクトは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
は厳密な型ですが、あなたのObject 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
は厳密型です。そのため、integer
を追加するとコンパイル時エラーが発生します。
警告 : -
Raw
型オブジェクトは、Strict
型のArrayList
型参照変数を参照しています。
この場合、ArrayList arr
は生の型ですが、あなたのObject new ArrayList<String>();
はStrict型です。
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
arr
はRaw型なので、任意の種類のObjectが追加されます。
警告 : -
Strict
型オブジェクトは、変数を参照するraw
型を参照しています。
生の型とは何ですか。また、新しいコードで使用してはいけないとよく聞きます。
「生の型」とは、パラメータ化された型に対して型の引数を指定せずに総称クラスを使用することです。 List<String>
の代わりにList
を使用する。総称がJavaに導入されたとき、いくつかのクラスが総称を使用するように更新されました。 (型引数を指定せずに)これらのクラスを「生の型」として使用すると、従来のコードをコンパイルできます。
「生の型」は後方互換性のために使用されます。新しいクラスでの使用は推奨されません。ジェネリッククラスをtype引数と一緒に使用するとより強い型付けが可能になるため、コードの理解性が向上し、潜在的な問題を早期に捉えることができるためです。
生の型を使用できない場合の代替手段は何ですか。また、それはどのように優れていますか?
推奨される代替方法は、適切な型引数(例:List<String>
)を付けて、意図したとおりに総称クラスを使用することです。これはプログラマが型をより具体的に指定することを可能にし、変数またはデータ構造の意図された使用について将来の保守担当者により多くの意味を伝え、コンパイラがより良い型安全性を強制することを可能にします。これらの利点を組み合わせると、コード品質が向上し、一部のコーディングエラーの発生を防ぐのに役立ちます。
例えば、プログラマーが 'names'という名前のList変数にStringだけが含まれるようにしたいメソッドの場合は、次のようになります。
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
raw - typeは typeパラメータの欠如です /ジェネリック型を使用する場合。
Raw型は、double
をSet
のint
とすることになっていたものに挿入するなど、ランタイムエラーを引き起こす可能性があるため使用しないでください。
Set set = new HashSet();
set.add(3.45); //ok
Set
からものを取り出すとき、何が出てくるのかわかりません。あなたはそれがすべてint
sであることを期待していると仮定しよう。あなたはそれをInteger
にキャストしている。実行時にdouble
3.45が登場すると例外が発生します。
Set
に typeパラメータ を追加すると、すぐにコンパイルエラーになります。このプリエンプティブエラーを使用すると、実行時に問題が発生する前に問題を解決できます(したがって、時間と労力を節約できます)。
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はどの種類のオブジェクトがリストの中にあるのかを知りません。次に、リストを反復したいときは、その要素のプロパティ(この場合はString)にアクセスできるようにするために、すべての要素をキャストする必要があります。
一般的にコレクションをパラメータ化するためのより良いアイデアです、あなたは変換問題を抱えていません、あなたはパラメータ化されたタイプの要素を追加することができるだけです、そしてあなたのエディタはあなたに選択する適切な方法を提供します。
private static List<String> list = new ArrayList<String>();
生の型は型引数のない総称クラスまたはインタフェースの名前です。たとえば、一般的なBoxクラスがあるとします。
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Boxのパラメータ化された型を作成するには、仮型パラメータTの実型引数を指定します。
Box<Integer> intBox = new Box<>();
実際の型引数を省略した場合は、生のBox型のBoxを作成します。
Box rawBox = new Box();
私はいくつかのサンプル演習をして、まったく同じパズルをした後にこのページを見つけました。
サンプルによって提供として==============私は===============このコードから行ってきました
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時間かかりました...
生の型を避ける
RAW型は、型パラメータを指定せずにジェネリック型を使用することを意味します。
例えば、
リストは生の型ですが、List<String>
はパラメータ化された型です。
総称がJDK 1.5で導入されたとき、生の型は古いバージョンのJavaとの後方互換性を維持するためだけに保持されました。生の型を使うことはまだ可能ですが、
それらは避けるべきです :
これらは表現力が少なく、パラメータ化された型と同じように自己文書化しません 例
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
生の型はあなたが表現したいものを表現するときは問題ありません。
例えば、逆シリアル化関数はList
を返すかもしれませんが、それはリストの要素型を知りません。そのため、ここではList
が適切な戻り型です。