27

Square以下の例(私のコースパックから)では、インスタンスc1に他のオブジェクトの参照を与えたいと思いますp1が、それらの2つが互換性のあるタイプである場合に限ります。

if (p1 instanceof Square) {c1 = (Square) p1;}

ここで私が理解していないのは、最初にそれp1が実際にであることを確認してSquareから、それをキャストしているということです。それがSquare、なぜキャストするのですか?

答えは見かけのタイプと実際のタイプの違いにあると思いますが、それでも混乱しています...

編集:
コンパイラはどのように処理しますか:

if (p1 instanceof Square) {c1 = p1;}

Edit2:見かけのタイプではなく実際のタイプをチェック
する問題ですか?そして、キャストが見かけのタイプを変更するということですか?instanceof

4

12 に答える 12

13

Squareのインスタンスは、継承チェーンの上位のタイプにいつでも割り当てることができることに注意してください。次に、より具体的でないタイプをより具体的なタイプにキャストすることができます。その場合、キャストが有効であることを確認する必要があります。

Object p1 = new Square();
Square c1;

if(p1 instanceof Square)
    c1 = (Square) p1;
于 2010-11-15T16:15:44.020 に答える
12

コンパイラーは、ユーザーがブロック内にいるため、オブジェクトのタイプのチェックに成功したとは推測しません。オブジェクトを別の型として参照することをコンパイラーに通知するには、明示的なキャストが引き続き必要です。

if (p1 instanceof Square) {
    // if we are in here, we (programmer) know it's an instance of Square
    // Here, we explicitly tell the compiler that p1 is a Square
    c1 = (Square) p1;
}

C#では、1回の呼び出しでチェックとキャストを行うことができます。

c1 = p1 as Square;

これはp1正方形にキャストされ、キャストが失敗した場合、c1はに設定されnullます。

于 2010-11-15T16:15:20.793 に答える
12

古いコードは正しく機能しません

暗黙のキャスト機能は結局のところ正当化されますが、下位互換性のためにこのFRをJavaに実装するのに問題があります。

これを参照してください:

public class A {
    public static void draw(Square s){...} // with implied cast
    public static void draw(Object o){...} // without implied cast
    public static void main(String[] args) {
        final Object foo = new Square();
        if (foo instanceof Square) {
            draw(foo);
        }
    }
}

現在のJDKは、2番目に宣言されたメソッドの使用法をコンパイルします。このFRをJavaで実装すると、最初のメソッドを使用するようにコンパイルされます。

JDK 14

最終的に、この機能をJDK 14に実装しました。お気づきかもしれませんが、instanceof-linkage内で新しい変数を宣言できます。この新しい変数は、指定されたタイプに自動的にアップキャストされた値によって定義されています。

if (any instanceof String s) {
  System.out.println(s);
}
于 2015-08-09T09:28:06.527 に答える
5

ある物体が箱に収まるかどうかを測定することと、実際にそれを箱に入れることには違いがあります。 instanceof前者は前者、鋳造は後者です。

于 2010-11-15T16:27:17.497 に答える
4

この特定の構文糖衣はまだ言語に追加されていないためです。Java 7向けに提案されたと思いますが、プロジェクトコインに入っていないようです

于 2010-11-15T16:15:18.950 に答える
2

これに関する更新を提供するために、Java 14はinstanceofのパターンマッチングを提供するようになりました。これにより、一挙にチェックしてキャストすることができます。

これ(古い方法):

void outputValue(Object obj) {
    if (obj instanceof String) {                      // Compare
        String aString = (String) obj;                // New variable & explicit casting
        System.out.println(aString.toUpperCase());    // Access member
    }
}

これに簡略化できます:

void outputValue(Object obj) {
    if (obj instanceof String aString) {              // Compare and cast (if true)
        System.out.println(aString.toUpperCase());    // Access member
    }
}

参照:https ://jaxenter.com/pattern-matching-for-instanceof-in-java-14-169830.html

于 2020-05-29T10:54:37.827 に答える
1

たとえば、Object型としてp1を渡すと、コンパイラはそれが実際にはSquareのインスタンスであることを認識しないため、メソッドなどにアクセスできなくなります。ifは、特定の型をチェックしてtrue / falseを返すだけですが、変数p1の型は変更されません。

于 2010-11-15T16:16:58.933 に答える
1

変数p1には、それが開始したタイプが何であれ、たとえばShapeとしましょう。p1はシェイプであり、現在のコンテンツがたまたま正方形であるかどうかに関係なく、シェイプのみです。Squareではside()を呼び出すことができますが、Shapeでは呼び出すことができません。タイプがShapeである変数p1を介して問題のエンティティを識別している限り、変数のタイプが原因で、そのエンティティでside()を呼び出すことはできません。Javaの型システムの仕組みでは、Squareであることがわかったときにp1.side()を呼び出すことができれば、いつでもp1.side()を呼び出すことができます。ただし、p1はSquare Shapesだけでなく、(たとえば)Circle Shapesも保持できます。また、p1がCircleを保持しているときにp1.side()を呼び出すとエラーになります。したがって、Shapeを表すために、たまたま知っている別の変数がSquareである必要があります。これは、タイプがSquareである変数です。それか'

于 2010-11-15T16:26:02.900 に答える
1

Leroyが述べたように、Java14はinstanceofのパターンマッチングを導入しています。したがって、instanceofcheckとtypecastの両方を1つの式にまとめて組み合わせることができます。

if (p1 instanceof Square) { c1 = (Square) p1; }次のように書き直すことができます

if (p1 instanceof Square c1) { // use c1 }

この機能は、Java 16(JEP 394)で完成しました。以下のバージョンについては、このリンクを参照して、IntelliJ、Eclipse、STSなどのIDEからこのプレビュー機能を有効にしてください。

于 2021-10-26T09:11:21.213 に答える
0

不快ではありませんが、コンパイラに何をしたいのかを伝える必要があります。これは、コンパイラが何をしようとしているのかを推測するための代替手段となるためです。確かに、「オブジェクトのタイプをチェックしている場合、明らかに、それはそのタイプにキャストしたいという意味であるに違いありません」と思うかもしれません。しかし、誰が言いますか?多分それはあなたがしていることであり、多分そうではありません。

確かに、次のような単純なケースでは

if (x instanceof Integer)
{
  Integer ix=(Integer) x;
  ...

私の意図はかなり明白です。またはそれは?多分私が本当に欲しいのは:

if (x instanceof Integer || x instanceof Double)
{
  Number n=(Number) x;
... work with n ...

または私が書いた場合はどうなりますか:

if (x instanceof Integer || x instanceof String)

コンパイラが次に何をすることを期待しますか?xに対してどのタイプを想定する必要がありますか?

instanceofは廃止されている、またはそうでなければ悪い考えであるというコメントを再確認してください。それは確かに誤用される可能性があります。私は最近、元の作成者が6つのクラスを作成し、それらがすべてページとページの長さであるが、互いに同一であることが判明したプログラムに取り組みました。それらを使用する唯一の明白な理由は、「xinstanceofclassA」と「 x instanceof classB "など。つまり、彼はクラスを型フラグとして使用しました。クラスを1つだけにして、さまざまなタイプの列挙型を追加する方がよいでしょう。しかし、非常に良い使い方もたくさんあります。おそらく最も明白なのは次のようなものです:

public MyClass
{
  int foo;
  String bar;
  public boolean equals(Object othat)
  {
    if (!(othat instanceof MyClass))
      return false;
    MyClass that=(MyClass) othat;
    return this.foo==that.foo && this.bar.equals(that.bar); 
  }
  ... etc ...
}

instanceofを使用せずにそれをどのように行いますか?パラメータをObjectではなくMyClassタイプにすることができます。しかし、それを汎用オブジェクトで呼び出す方法すらありません。これは多くの場合非常に望ましいことです。実際、たとえば、文字列と整数の両方をコレクションに含めたい場合や、異なる型の比較で単純にfalseを返したい場合があります。

于 2010-11-15T17:59:49.647 に答える
0

c1のタイプとして宣言されている場合はSquare、キャストが必要です。それがthenとして宣言されている場合Object、キャストは必要ありません。

于 2010-11-15T16:15:06.467 に答える
0

テストは、実行時に防止するためClassCastExceptionsに実行されます。

Square c1 = null;
if (p1 instanceof Square) {
   c1 = (Square) p1;
} else {
   // we have a p1 that is not a subclass of Square
}

あなたが絶対に肯定的であるならp1Squareそれはあなたがテストする必要はありません。しかし、これはプライベートメソッドに任せてください...

于 2010-11-15T16:17:44.703 に答える