web-dev-qa-db-ja.com

生の型とは何ですか。なぜ私たちはそれを使用しないのですか?

質問:

  • Javaの生の型は何ですか、そしてなぜ私はそれらが新しいコードで使われるべきではないとしばしば聞くのですか?
  • 生の型を使用できない場合の代替手段は何ですか、そしてそれはどのように優れていますか?
591

Rawタイプとは何ですか?

Java言語仕様では、次のようにrawタイプを定義しています。

JLS 4.8 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>のメンバー型であっても、パラメーター化された型ではありません。

mt1mt2は両方とも実際の型パラメーターで宣言されているため、生の型ではありません。


生の型の何がそんなに特別なのですか?

基本的に、生の型はジェネリックが導入される前と同じように動作します。つまり、以下はコンパイル時に完全に合法です。

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ではないものが含まれているため、実行時に問題が発生します。

おそらく、namesStringのみを含める場合、couldおそらく生のタイプを使用し、手動ですべてをチェックaddを自分で、そして手動でキャスト = Stringのすべての項目をnamesに。 さらに良い、ただし生のタイプを使用することはできませんコンパイラにすべての作業を任せる Javaジェネリックの。

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

もちろん、DOnamesBooleanを許可したい場合は、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>

こちらもご覧ください

697

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 を使用してください

56
josefx

生の型は型引数のない総称クラスまたはインタフェースの名前です。たとえば、一般的な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はあなたにObjectsを与えます。下位互換性のために、パラメータ化された型をその生の型に代入することができます。

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チュートリアル

23
Adelin
 private static List<String> list = new ArrayList<String>();

Type-parameterを指定してください。

この警告は、 generics をサポートするように定義されている型は、その生の形式を使用するのではなく、パラメータ化する必要があることを助言します。

Listは総称をサポートするために定義されています:public class List<E>。これにより、コンパイル時にチェックされる多くの型保証された操作が可能になります。

18
Bozho

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でのみ機能するように事前定義されています。この事実こそがジェネリック医薬品の主な推進要因です。ランタイムエラーの原因をコンパイル時にチェックできるものに変更します。

15
Andy White

コンパイラはあなたにこれを書いてほしい:

private static List<String> list = new ArrayList<String>();

そうでなければ、あなたが好きな型をlistに追加することができ、インスタンス化をnew ArrayList<String>()として無意味にすることができます。 Javaジェネリックはコンパイル時の機能のみであるため、 "raw type" Integerの参照に割り当てられた場合、new ArrayList<String>()で作成されたオブジェクトはJFrame要素またはList要素を喜んで受け入れます。コンパイラが行います。

12

ここで私はあなたが概念を明確にすることができる複数のケースを検討しています

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

ケース1

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)

ケース2

この場合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型参照変数を参照しています。

ケース3

この場合、ArrayList arrは生の型ですが、あなたのObject new ArrayList<String>();はStrict型です。

    arr.add("hello");  
    arr.add(23);  //compiles fine but raise the warning.

arrはRaw型なので、任意の種類のObjectが追加されます。

警告 : - Strict型オブジェクトは、変数を参照するraw型を参照しています。

11
Vikrant Kashyap

生の型とは何ですか。また、新しいコードで使用してはいけないとよく聞きます。

「生の型」とは、パラメータ化された型に対して型の引数を指定せずに総称クラスを使用することです。 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
11
Bert F

raw - typeは typeパラメータの欠如です /ジェネリック型を使用する場合。

Raw型は、doubleSetintとすることになっていたものに挿入するなど、ランタイムエラーを引き起こす可能性があるため使用しないでください。

Set set = new HashSet();
set.add(3.45); //ok

Setからものを取り出すとき、何が出てくるのかわかりません。あなたはそれがすべてintsであることを期待していると仮定しよう。あなたはそれをIntegerにキャストしている。実行時にdouble 3.45が登場すると例外が発生します。

Set typeパラメータ を追加すると、すぐにコンパイルエラーになります。このプリエンプティブエラーを使用すると、実行時に問題が発生する前に問題を解決できます(したがって、時間と労力を節約できます)。

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
8
Lars Andren

生の型が噛み付くような別のケースがあります。

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です)。

6
GuyPaddock

言っているのは、あなたのlistは未指定のオブジェクトのListであるということです。つまり、Javaはどの種類のオブジェクトがリストの中にあるのかを知りません。次に、リストを反復したいときは、その要素のプロパティ(この場合はString)にアクセスできるようにするために、すべての要素をキャストする必要があります。

一般的にコレクションをパラメータ化するためのより良いアイデアです、あなたは変換問題を抱えていません、あなたはパラメータ化されたタイプの要素を追加することができるだけです、そしてあなたのエディタはあなたに選択する適切な方法を提供します。

private static List<String> list = new ArrayList<String>();
5
pakore

チュートリアルページ

生の型は型引数のない総称クラスまたはインタフェースの名前です。たとえば、一般的なBoxクラスがあるとします。

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

Boxのパラメータ化された型を作成するには、仮型パラメータTの実型引数を指定します。

Box<Integer> intBox = new Box<>();

実際の型引数を省略した場合は、生のBox型のBoxを作成します。

Box rawBox = new Box();
4

私はいくつかのサンプル演習をして、まったく同じパズルをした後にこのページを見つけました。

サンプルによって提供として==============私は===============このコードから行ってきました

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時間かかりました...

1
user2442615

生の型を避ける

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

0
ashish

生の型はあなたが表現したいものを表現するときは問題ありません。

例えば、逆シリアル化関数はListを返すかもしれませんが、それはリストの要素型を知りません。そのため、ここではListが適切な戻り型です。

0
Stefan Reich