2

私は Java にまったく慣れていないので、これは基本的な疑問かもしれません。しかし、助けてください。私は以下のようなクラスを持っています:

public class EnterLeaveHandler implements IOtfHandler {
    public void handle(java.lang.Object ... args) {

        long time = (Long) args[0];
        int func = (Integer) args[1];
        int cpuid = (Integer) args[2];
        int source = (Integer) args[3];
}

私は別のクラスを持っています:

public class DefFunctionHandler implements IOtfHandler {

    public void handle(Object... args) {

        int stream = (Integer) args[0];
        int func = (Integer) args[1];
        String name = (String) args[2];
        int funcgroup = (Integer) args[3];
        int source = (Integer) args[4];
    }
}

ご覧のとおり、同じメソッドを持つが異なるデータを受け取る 2 つの異なるクラスがあります。クラスの「文字列名」のユーザーからの入力を取得する必要があり、与えられた名前を私が持っているファイル内の名前で識別します...次に、メソッド内の他のデータとDefFunctionHandler関連付けます. 同じことが他のクラスにもあります。したがって、時間などの他のクラスのデータを取得するには、それらを比較する必要があります。funcgroupfuncfunc

したがって、メソッド内のデータは C のデータ構造と比較できます... Java でそのような構造を実装するにはどうすればよいですか? 構造体はJavaのクラスに似ていると読みました。しかし、私の場合、クラスではなくメソッドにデータがあります。この問題を解決する方法を教えてください。

4

5 に答える 5

3

元の質問に答えるには

簡単に言えば、外部からメソッド変数にアクセスすることはできません。あなたがしたいことは、それらの変数フィールドをクラス内に作成することです。それらをメソッドの外側に置くということは、メソッドが完了した後も残り続けることを意味し、外部からそれらにアクセスできることを意味します。

public class EnterLeaveHandler implements IOtfHandler {
    private long time;
    private int func;
    private int cpuid;
    private int source;

    // Please don't use varargs like this; read the whole answer!!
    public void handle(Object ... args) {
        time = (Long) args[0];
        func = (Integer) args[1];
        cpuid = (Integer) args[2];
        source = (Integer) args[3];
    }
}

次に、 gettersetterを作成してアクセスします。

public long getTime() {
    return time;
}
public void setTime(long t) {
    time = t;
}
// etc...

ただし、いくつかの提案...

あなたのコードは...控えめに言っても奇妙です。また、非常にJavaに似ていません。可能な限り、異なるデータを必要とする複数のオーバーライド メソッドを持たないようにする必要があります。また、通常、他のメソッドではなく、コンストラクターでフィールドを初期化する必要があります。

どの程度のコードにアクセスできるかは明確ではありませんが、インターフェースを書き直すことができるなら、私は間違いなくそうします。Objectインターフェイスの varargs は奇妙です。インターフェイスを使用する理由は、同一のパラメーターでインターフェイス メソッドを呼び出すことができ、その下のオブジェクト タイプに関係なく、何か有用なことが起こるようにするためです。同じメソッドの 2 つの実装がまったく異なる引数を必要とすることは、インターフェイスのポイントを無効にします。次のコードは、この理由を示しています。

IOtfHandler h1 = new EnterLeaveHandler();
IOtfHandler h2 = new DefFunctionHandler();
h1.handle(0, 0, 0, 0);
h2.handle(0, 0, 0, 0); // Crashes with ClassCastException!! :(
                       // And would also crash two lines later with ArrayIndexOutOfBoundsException

それらを完全に異なるメソッドにする方がはるかに優れています。期待している変数がわかっているので、その事実を利用する必要があります。メソッドのシグネチャは、次のように見える方がはるかに優れています。

public class EnterLeaveHandler implements IOtfHandler {
    public void handle(long time, int func, int cpuid, int source) {
    // Do things with your shiny new variables
}
public class DefFunctionHandler implements IOtfHandler {
    public void handle(int stream, int func, String name, int funcgroup, int source) {
        // Do things with your shiny new variables
    }
}

他の人が示唆しているように、「実際の」メソッド署名が同一でない場合は、インターフェイスを使用しないでください。代わりに抽象基本クラスを使用して、それらの間で共通する小さなデータを保持することをお勧めします。

abstract class IOtfHandler {
    private int source;
    private int func;

    public void setSource(int source) {
        this.source = source;
    }
    // etc
}
class EnterLeaverHandler extends IOtfHandler {
    private long time;
    // etc
}
class DefFunctionHandler extends IOtfHandler {
    private String name;
    // etc
}

もちろん、コンストラクターですべての変数を設定すると、基本クラスに抽象メソッドを追加できる場合があります。handle()これは、そのメソッドが同じ署名を持ち、引数をまったくとらないためです!


最終結果

したがって、私が話したすべての変更をまとめると、メソッド変数をフィールドに移動し、ゲッターセッターを使用し、便利なメソッド シグネチャを使用し、コンストラクターを使用し、誤解を招くインターフェイスの代わりに基底クラスを使用すると、最終的には次のようになります。このようなもの:

abstract class IOtfHandler {
    private int source;
    private int func;

    public void setSource(int source) {
        this.source = source;
    }
    public int getSource() {
        return source;
    }
    public void setFunc(int func) {
        this.func = func;
    }
    public int getFunc() {
        return func;
    }

    // abstract handle method
    abstract public void handle();
}

class EnterLeaverHandler extends IOtfHandler {
    private long time;
    private int cpuid;

    // getters and setters
    public void setTime(long time) {
        this.time = time;
    }
    public long getTime() {
        return time;
    }
    public void setCpuId(int cpuid) {
        this.cpuid = cpuid;
    }
    public int getCpuId() {
        return cpuid;
    }

    // constructor
    public EnterLeaverHandler(long time, int cpuid, int source, int func) {
        setTime(time);
        setCpuId(cpuid);
        setSource(source);
        setFunc(func);
    }

    // handle method
    public void handle() {
        System.out.println("EnterLeaverHandler.handle()");
        // Do whatever class-specific handling you might want to do in here.
    }
}

class DefFunctionHandler extends IOtfHandler {
    private String name;
    private int funcGroup;
    private int stream;

    // getters and setters
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setFuncGroup(int funcGroup) {
        this.funcGroup = funcGroup;
    }
    public int getFuncGroup() {
        return funcGroup;
    }
    public void setStream(int stream) {
        this.stream = stream;
    }
    public int getStream() {
        return stream;
    }

    // constructor
    public DefFunctionHandler(String name, int funcGroup, int stream, int source, int func) {
        setName(name);
        setFuncGroup(funcGroup);
        setStream(stream);
        setSource(source);
        setFunc(func);
    }

    // handle method
    public void handle() {
        System.out.println("DefFunctionHandler.handle()");
        // Do whatever class-specific handling you might want to do in here.
    }
}

public class Main {
    public static void main(String[] args) {
        IOtfHandler h1 = new DefFunctionHandler("name", 0, 0, 0, 0);
        IOtfHandler h2 = new EnterLeaverHandler(0, 0, 0, 0);
        h1.handle();
        h2.handle();
    }
}
于 2013-06-06T14:51:01.110 に答える
0

適切なコンストラクターとセッター/ゲッターを持つようにオブジェクトを再構築する必要があります

これにより、すべてのプライベート変数を保護し、他のクラスがセッター/ゲッターおよびコンストラクターを介して内部変数にアクセスすることのみを許可することで、クラスの「契約」に準拠するように強制できるという利点があります。オブジェクトをインスタンス化し、ti のメソッドを使用してそれを操作します。

最初のサンプル クラスの例を次に示します。

public class EnterLeaveHandler implements IOtfHandler {

    private long time;
    private int func, cpuid, source;

    public EnterLeavehandler(long time, int func, int cpuid, int source) {

        this.time = time;
        this.func = func;
        this.cpuid = cpuid;
        this.source = souce;

    }

    public long getTime() {
        return this.time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public int getFunc() {
        return this.func;
    }

    public void setFunc(int func) {
        this.func = func;
    }

    public int getCPUID() {
        return this.cpuid;
    }

    public void setCPUID(int cpuid) {
        this.cpuid = cpuid;
    }

    public int getSource() {
        return this.source;
    }

    public void setSource(int source) {
        this.source = source;
    }

    public void handle(long t, int f, int c, int s) {

        this.setTime(t);
        this.setFunc(f);
        this.setCPUID(c);
        this.setSource(s);
    }
}
于 2013-06-06T14:54:26.257 に答える
0

変数をクラス変数にするには、その宣言をメソッドの外に移動するだけです。つまり、EnterLeaveHandler のコードは次のようになります。

public class EnterLeaveHandler implements IOtfHandler {

    long time;
    int func;
    int cpuid;
    int source;

    public void handle(java.lang.Object ... args) {

        time = (Long) args[0];
        func = (Integer) args[1];
        cpuid = (Integer) args[2];
        source = (Integer) args[3];
        ...
    }
}
于 2013-06-06T14:49:29.197 に答える
-2

私が考えることができる最善の解決策は、ゲッターとセッターを作成することです。

 public void setName(String name) {
       this.name = name;
    }

    public String getName() {
       return name;
    }

http://docs.oracle.com/javaee/6/tutorial/doc/gjbbp.html

2. 個々のメソッドを呼び出す前に、比較を行うラッパー メソッドを作成します。

これがお役に立てば幸いです。

于 2013-06-06T14:51:16.083 に答える