Java:为什么这个方法有副作用?
我有一个会产生副作用的方法,即使某些变量被标记为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;
}
I have a method that is producing side effects, even though certain variables are marked final
. Why is this? Perhaps I am confused about what final
does.
@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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
final
修饰符仅意味着引用不能被重新分配。它不会阻止对象的状态被修改。编辑:仅供 Tom:
在这两种情况下,您都可以调用
arg
指向的对象上的方法,包括修改其状态的方法。The
final
modifier only means that the reference cannot be reassigned. It does not prevent the object's state from being modified.EDIT: Just for Tom:
In both cases you can invoke methods on the object pointed to by
arg
, including methods that modify its state.丹在决赛中给出了正确答案。你所追求的更像是C++中的const,而Java没有。您可以通过执行以下操作来模拟它:
然后执行:
不太漂亮,但它有效。诀窍是确保父类 (Foo) 中的任何方法都不会对实例变量进行任何更改 - 只有 MutableFoo 可以具有允许状态更改的方法。
当然,最好的办法是尽可能编写不可变类(将所有变量设为最终变量),并且不要对具有副作用的实例/类变量调用方法,这样事情就不会改变
Dan has the right answer on final. What you are after is more like const in C++, which Java does not have. You can simulate it by doing this:
then do:
Not pretty, but it works. The trick is to make sure that none of the methods in the parent class (Foo) make any changes to the instance variables - only MutableFoo can have methods that allow the state to change.
Of course the best thing to do, as much as possible, is to write immutable classes (make all the variables final) and do not call methods on instance/class variables that have side effects, so that things cannot change