3

特定の変数がマークされているにもかかわらず、副作用を生成しているメソッドがありますfinal。どうしてこれなの?おそらく私は何をするのか混乱してfinalいます。

@Test
public void testSubGraph() {
    WeightedGraph<String, DefaultWeightedEdge> g = generateSimpleCaseGraph();

    Graph<String, DefaultWeightedEdge> sub = ChooseRoot.subgraphInDirection(g, "alpha", "l");

    assertEquals(g, generateSimpleCaseGraph()); //fails 
}

public static <V, E extends DefaultEdge> Graph<V, E> subgraphInDirection(final Graph<V, E> g, final V start, final V sink) {
    Graph<V, E> sub = removeEdges(g, start, sink);
    return removeUnconnectedNodes(sub, start);
}

private static <Vertex, Edge extends DefaultEdge> Graph<Vertex, Edge> removeEdges(final Graph<Vertex, Edge> g, Vertex start, Vertex sink) {
    final Set<Edge> outEdges = new HashSet<Edge>(g.edgesOf(start));
    boolean removedEdge;

    for (Edge e : outEdges) {
        if (! (g.getEdgeTarget(e).equals(sink) || g.getEdgeSource(e).equals(sink))) {
            removedEdge = g.removeEdge(e);
            assert removedEdge;
        }
    }
    return g;
}

private static <Vertex, Edge> Graph<Vertex, Edge> removeUnconnectedNodes(Graph<Vertex, Edge> g, Vertex start) {
    ConnectivityInspector<Vertex, Edge> conn = new ConnectivityInspector<Vertex, Edge>((UndirectedGraph<Vertex, Edge>) g);
    boolean removedVertex;

    final Set<Vertex> nodes = new HashSet<Vertex>(g.vertexSet());
    for (Vertex v : nodes) {
        if (! conn.pathExists(start, v)) {
            removedVertex = g.removeVertex(v);
            assert removedVertex;
        }
    }
    return g;
}
4

2 に答える 2

14

修飾子はfinal、参照を再割り当てできないことを意味するだけです。オブジェクトの状態が変更されるのを防ぐことはできません。

編集:トムのためだけに:

public void doSomething1(Object arg)
{
    arg = new Object(); // OK.
}

public void doSomething2(final Object arg)
{
    arg = new Object(); // Compile error.
}

どちらの場合もarg、状態を変更するメソッドを含め、が指すオブジェクトのメソッドを呼び出すことができます。

于 2009-11-26T23:16:20.487 に答える
1

ダンは決勝で正しい答えを持っています。あなたが求めているのは、JavaにはないC++のconstに似ています。これを行うことでそれをシミュレートできます:

public class Foo
{
    protected int x;

    public Foo(final int val)
    {
        x = val;
    }

    public int getX()
    {
        return (x);
    }
}

public class MutableFoo 
    extends Foo
{
    public MutableFoo(final int val)
    {
        super(val);
    }

    public void setX(final int val)
    {
        x = val;
    }
}

次に行います:

void bar(final Foo foo)
{
    foo.setX(5); // will not compile
}

void bar(final MutableFoo foo)
{
    foo.setX(5); // will compile
}

きれいではありませんが、動作します。秘訣は、親クラス(Foo)のどのメソッドもインスタンス変数に変更を加えないようにすることです。MutableFooだけが状態の変更を許可するメソッドを持つことができます。

もちろん、可能な限り最善の方法は、不変のクラスを作成し(すべての変数を最終的にする)、副作用のあるインスタンス/クラス変数のメソッドを呼び出さないことです。これにより、状況が変わることはありません。

于 2009-11-27T00:22:18.987 に答える