2009-11-26 3 views
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; 
} 
+0

그 부작용은 무엇입니까? – clamp

+0

g는 서브 그래프와 리턴 값이됩니다. –

답변

14

final 수정자는 참조를 다시 할당 할 수 없다는 것을 의미합니다. 객체의 상태가 수정되는 것을 막지는 않습니다.

편집 : 그냥 톰의 경우 : 개체에 메소드를 호출 할 수 두 경우 모두가 그 상태를 수정하는 방법을 포함, arg 가리키는 두 경우 모두

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

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

.

+1

필자는 본질적으로 같은 것을 게시하려고했지만 예제를 제시했습니다. 당신의 예제를 추가하면됩니다 :-). – Tom

+0

다음과 같이 진행합니다. –

+0

ok, 개체의 상태를 변경하지 않으려면 어떻게해야합니까? 복제해야합니까? –

1

댄에게는 최종 결과에 대한 올바른 대답이 있습니다. 당신이하는 일은 Java가 가지고 있지 않은 C++에서 const와 더 비슷합니다.

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

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

꽤하지 않습니다, 그러나 그것은 작동합니다

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; 
    } 
} 

다음을 수행하십시오 당신은이 일을하여 시뮬레이션 할 수 있습니다. 트릭은 상위 클래스 (Foo)의 메소드가 인스턴스 변수를 변경하지 않도록하는 것입니다. MutableFoo만이 상태를 변경할 수있는 메소드를 가질 수 있습니다.

물론 가능한 한 가장 좋은 방법은 변경 불가능한 클래스를 작성하고 (모든 변수를 최종화하는 것) 부작용이있는 인스턴스/클래스 변수의 메소드를 호출하지 말고 변경하지 못하게하는 것입니다.

+0

+ 1 불변 클래스를 생성 할 때 +1하지만, 최종 변수를 최종적으로 가질뿐만 아니라 변경 가능한 속성을 갖지 않거나 변경 메소드를 호출하지 않으며 변경 가능한 속성에 대한 참조를 반환하지 않습니다. –

+0

불변의 좋은 점 - 나는 나의 대답을 업데이트 할 것이다. – TofuBeer

관련 문제