簡體   English   中英

Java:為什么這種方法有副作用?

[英]Java: Why does this method have side effects?

我有一個產生副作用的方法,即使某些變量標記為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;
}

final修飾符僅表示無法重新分配引用。 它不會阻止對象的狀態被修改。

編輯:只為湯姆:

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

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

在這兩種情況下,您都可以調用arg指向的對象上的方法,包括修改其狀態的方法。

Dan在決賽中有正確的答案。 你所追求的更像是C ++中的const,Java沒有。 您可以通過執行以下操作來模擬它:

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可以使用允許狀態更改的方法。

當然,盡可能做的最好的事情是編寫不可變類(使所有變量最終)並且不要在具有副作用的實例/類變量上調用方法,這樣事情就不會改變

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM