3

インターフェイスで静的な最終値の奇妙な動作があります。

public interface IDictionaryErrorTypes {

    final static int ERROR_UNKNOWN      = 0;
    final static int ERROR_XML      = 1;
    final static int ERROR_CONNECTION   = 3;

}

public interface IDictionaryListModel extends IDictionaryErrorTypes,
                                                    //... and other interfaces
{

}

public class DictionaryListModel implements IDictionaryListModel {

// ... some code ...

private int getErrorCode(Exception error) {
    // determinate the error code
    if (error instanceof ParserConfigurationException
            || error instanceof SAXException
            || error instanceof SAXParseException) {
        return ERROR_XML;
    } else if (error instanceof UnknownHostException
            || error instanceof MalformedURLException
            || error instanceof IOException) {
        return ERROR_CONNECTION;
    } 
    return ERROR_UNKNOWN;
}

そして今、アプリケーション ERROR_XML を実行すると、ERROR_CONNECTION と ERROR_UNKNOWN の値が ZERO - 0 になります。私には非常に奇妙に思えます。添付画像をご覧ください

Java 静的フィールド インターフェイスのバグ

私のモデルIDictionaryErrorTypes.ERROR_CONNECTIONで使用しても、同じ動作をします。しかし、を削除して"implements IDictionaryErrorTypes"から使用すると、IDictionaryErrorTypes.ERROR_CONNECTION定数値はまさにそのように聞こえます。

インターフェイスの代わりにクラスを使用すると、正常に動作します。

誰かがこの動作を説明できますか? (ps私はAndroidプラットフォームを使用しています)

ps(2) また、「final」、「static」、「public」キーワードを追加/削除して実験しました (そのため、イメージとコードのインターフェイス宣言が少し異なります)。でも行動は同じ

WORKING VERSION の smali コード (インターフェイスの代わりにクラスを使用):

.method private getErrorCode(Ljava/lang/Exception;)I
    .registers 3
    .parameter "error"

    .prologue
    .line 145
    instance-of v0, p1, Ljavax/xml/parsers/ParserConfigurationException;

    if-nez v0, :cond_c

    .line 146
    instance-of v0, p1, Lorg/xml/sax/SAXException;

    if-nez v0, :cond_c

    .line 147
    instance-of v0, p1, Lorg/xml/sax/SAXParseException;

    if-eqz v0, :cond_e

    .line 148
    :cond_c
    const/4 v0, 0x1

    .line 154
    :goto_d
    return v0

    .line 149
    :cond_e
    instance-of v0, p1, Ljava/net/UnknownHostException;

    if-nez v0, :cond_1a

    .line 150
    instance-of v0, p1, Ljava/net/MalformedURLException;

    if-nez v0, :cond_1a

    .line 151
    instance-of v0, p1, Ljava/io/IOException;

    if-eqz v0, :cond_1c

    .line 152
    :cond_1a
    const/4 v0, 0x3

    goto :goto_d

    .line 154
    :cond_1c
    const/4 v0, 0x0

    goto :goto_d
.end method

// class instead of interface

.class public Ltj/zar/projects/kathtranslator/interfaces/common/IDictionaryErrorTypes;
.super Ljava/lang/Object;
.source "IDictionaryErrorTypes.java"


# static fields
.field public static final ERROR_CONNECTION:I = 0x3

.field public static final ERROR_UNKNOWN:I = 0x0

.field public static final ERROR_XML:I = 0x1


# direct methods
.method public constructor <init>()V
    .registers 1

    .prologue
    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

UNWORKING VERSIONのsmaliコード:

.method private getErrorCode(Ljava/lang/Exception;)I
    .registers 3
.parameter "error"

.prologue
.line 145
instance-of v0, p1, Ljavax/xml/parsers/ParserConfigurationException;

if-nez v0, :cond_c

.line 146
instance-of v0, p1, Lorg/xml/sax/SAXException;

if-nez v0, :cond_c

.line 147
instance-of v0, p1, Lorg/xml/sax/SAXParseException;

if-eqz v0, :cond_e

.line 148
:cond_c
const/4 v0, 0x1

.line 154
:goto_d
return v0

.line 149
:cond_e
instance-of v0, p1, Ljava/net/UnknownHostException;

if-nez v0, :cond_1a

.line 150
instance-of v0, p1, Ljava/net/MalformedURLException;

if-nez v0, :cond_1a

.line 151
instance-of v0, p1, Ljava/io/IOException;

if-eqz v0, :cond_1c

.line 152
:cond_1a
const/4 v0, 0x3

goto :goto_d

.line 154
:cond_1c
const/4 v0, 0x0

goto :goto_d
.end method

// interface

.class public interface abstract Ltj/zar/projects/kathtranslator/interfaces/common/IDictionaryErrorTypes;
.super Ljava/lang/Object;
.source "IDictionaryErrorTypes.java"


# static fields
.field public static final ERROR_CONNECTION:I = 0x3

.field public static final ERROR_UNKNOWN:I = 0x0

.field public static final ERROR_XML:I = 0x1

解決する

プロジェクトをクリーンアップし、エミュレータを実際のデバイスに変更し、いくつかのテストを作成しました。

結果

デバッガーの問題のようです:

画像でわかるように、エラーは「3」で、ERROR_CONNECTION は「0」です。デバイスは実際に次の文字列 (緑の文字列) を実行します。つまり、デバッガーは 3 == 0 と考えていますが、実際には 3 == 3 です。

結論

デバッガーのバグ。

ここに画像の説明を入力

4

2 に答える 2

1

考えられる唯一の説明は、編集/ビルド/実行/デバッグ手順で何かが壊れていて、実際には自分が思っているよりも異なるバージョンのコードを実行しているということだと思います。

これの証拠は、実行していると思われるクラスの 2 つのバージョンを逆コンパイルしたことです。逆コンパイルされたコードは、次のことを明確に示しています。

  1. インライン化された定数値を使用しており、
  2. 定数値は、期待どおりの値です。

しかし、コードを実行すると (おそらく)、それらのバイトコードが示すものとは明らかに異なる動作をします。

もっともらしい説明は 1 つしかありません。それらのバイトコードを実行していないということです。代わりに、別のバージョンのバイトコードを実行しています。要するに、必要なすべてのことを再コンパイル/再構築/再デプロイしていません...完了します。

デバッガーの出力は、この仮説を裏付ける傾向があるため興味深いものです。実行可能ファイルには、ソース コードとは異なる定数を持つインターフェイスのコピーがあると思われるからです。(デバッガーのバグである可能性もあります...しかし、それはあまりにも大きな偶然です。)ただし、アプリはこれらの値を使用していないため、デバッガーの出力自体はアプリの動作を説明していません。

于 2012-10-15T03:22:00.823 に答える
1

使用しているデバッガーがトローリングしている (ほとんどの場合、答え) か、これは使用している Android SDK のバグです。そのメソッドによって実際に何が返されるかを調べようと思いましたか?

また、何をしても、インターフェースのフィールドはデフォルトで常に static finalpublic であることに注意してください - コンパイラがそうします。

public interface MyInterface
{
    public static final int TEST = 3;
}

public interface MyInterface2 extends MyInterface
{
    public final static int TEST2 = 5;
}

public class InterfaceTest implements MyInterface2
{
    public void printInterfaceConstants()
    {
        System.out.println(TEST);
        System.out.println(TEST2);
    }

    public static void main(String[] args)
    {
        InterfaceTest it = new InterfaceTest();
        it.printInterfaceConstants();
    }
}

出力:

3
5

前述したように、最初からこれを行わないでください。実装の詳細はインターフェイスに含めるべきではありません。

于 2012-10-15T01:46:19.887 に答える