2012-06-25 2 views
14
public class Test2 { 

    public static void main(String[] args) { 
     Test2 obj=new Test2(); 
     String a=obj.go(); 

     System.out.print(a); 
    } 


    public String go() { 
     String q="hii"; 
     try { 
      return q; 
     } 
     finally { 
      q="hello"; 
      System.out.println("finally value of q is "+q); 
     } 
    } 

go()에서 돌아온 후 hii이 인쇄되는 이유는 왜 finally 블록에서 값이 "hello"로 변경 되었습니까?결국 이상한 행동?

프로그램의 출력은 당신이 마지막으로 차단하려면에 q의 값을 변경하기 전에 q에서 평가 된 값을 반환하기 때문입니다

finally value of q is hello 
hii 
+1

다음을 읽는 것이 좋습니다. http://stackoverflow.com/questions/65035/in-java-does-return-trump-finally –

+2

로컬 변수'q'의 값이 'hello'로 변경되었습니다. 예. 하지만 당신이 반환 한 것은 "hii"였습니다. – maksimov

+0

제 새로운 대답을보세요 ...이 개념을 더 상세하게하려고합시다 .. – Ahmad

답변

27

입니다. 값이 계산 된 q을 반환했습니다. 로드 된 값에 영향을주지 않은 finally 블록의 q을 변경했습니다. 평가 된 값을 사용하여 리턴이 완료됩니다.

이렇게 까다로운 코드를 작성하지 마십시오. 그것이 그것을 쓴 사람을 혼란스럽게한다면, 당신이 다른 곳에있을 때 다음 녀석을 일으킬 문제를 상상해보십시오.

+0

하지만 finally 블록이 실행 된 후에 값이 반환됩니다. so – Harinder

+1

@Dennis finally 블록이 실행되기 전에 반환 할 값이로드되었습니다. 벌써 말했어. – EJP

+1

@Dennis 네,하지만'finally'에서 이미'return' 명령어가 _past_가 아니라 바로 앞에 있습니다. – maksimov

0

[EJP의 의견을 통해 편집 한 후 첫 번째 응답에서 질문에 답변하지 않았고 잘못되었습니다.]
이제 내 대답은 try 블록과 finally 블록이 정상적으로 완료되면 q가 반환된다는 것을 설명해야합니다. 그리고 "hii"값이 반환되는 이유는 EJP 답변에 설명되어 있습니다. 나는 아직도 JLS에서 설명을 찾고있다.

JLS 14.20.2 Execution of try-catch-finally

살펴 최종적으로 블록을 가진 try 문이 먼저 try 블록을 실행하여 실행 되세요.

try 블록의 실행이 정상적으로 완료되면 finally 블록이 실행 된 다음 선택 항목이 있습니다.
finally 블록이 정상적으로 완료되면 try 문이 정상적으로 완료됩니다.
[...]

JLS 14.17 The return Statement

식을 리턴 명령문을 포함하는 방법의 호출자로 제어를 전달하려고; 표현식의 값은 메소드 호출의 값이됩니다. 보다 정확하게는, return 문을 실행하면 먼저 Expression을 평가합니다. 표현식의 평가가 어떤 이유로 갑자기 완료되면 return 문은 그 이유로 인해 갑자기 완료됩니다.

위의 설명은 말은 "전송을 시도 : 식의 평가 값 V를 생산, 정상적으로 완료되면, return 문은 이유는

그리고이 값 V와 반환되고, 갑자기 완료 try 블록에 return 문이 포함 된 try 문 (14.20 절)이 있으면 해당 try 문의 finally 절이 순서대로 실행되므로 "제어를 전달합니다"가 아니라 "control" 컨트롤이 메서드 또는 생성자의 호출자에게 전달되기 전에 가장 바깥 쪽입니다. finally 절이 갑자기 완료되면 return 문에서 시작된 제어 전송이 중단 될 수 있습니다.

+1

이 답변에 정확히 어떻게 대답합니까? – EJP

+0

여전히 질문에 대답하지 않습니다. 'q'는 반환되지 않습니다. return 문이 실행될 때 q의 * 값이 반환됩니다. – EJP

4

return은 참조가 아닙니다. return q;이 실행되면 의 현재 값 q의 참조가 결과로 메소드에 의해 캐시됩니다. 따라서 finally 블록에서 q을 새 값으로 재 할당해도 메서드에 의해 이미 캐시 된 값에는 영향을 미치지 않습니다. 당신이 반환 된 값에 영향을 미치는

} finally { 
    q = "hello"; 
    System.out.println("finally value of q is " + q); 

    return q;//here you set other value in return 
} 

다른 방법처럼 finally 블록에 또 다른 return을 사용해야합니다 반환해야 값을 업데이트하려면

상태 캐시 된 개체의을 변경하는 것입니다. 예를 들어 qList 인 경우 새 요소를 추가 할 수 있습니다 (상태 변경은 final 변수를 변경할 수있는 것처럼 새 인스턴스를 다시 할당하는 것과 같지 않지만 재 할당 할 수는 없습니다).

} finally { 
    q.add(new Element); //this will place new element (update) in List 
    //object stored by return because it is same object from q reference 
    System.out.println("finally value of q is " + q); 
} 
+0

'값 (개체) + 참조 + 기준, 정확한 참조가 아닌', '참조에서 개체 읽기/저장'및 '반환 된 개체'는 의미가 없습니다. 대답이 아닙니다. 나가기 위해 고심하고있는 여기에 대답이 있을지 모르지만 용어가 너무 혼란되어 의미가 전달되지 않습니다. – EJP

2

마지막으로 리턴 후 메소드가 실제로 호출자에게 리턴되기 전에 실행됩니다. 이것은 던지기와 유사합니다. 그것은 던지기 후에 블록을 나가기 전에 발생합니다. 반환 값은 변수 q를 읽음으로써 이미 일부 레지스터에 설정되어 있습니다. q가 변경 가능하면 마지막으로 변경 될 수 있고 호출자의 변경 사항을 볼 수 있습니다. 왜 이런 방식으로 작동합니까? 하나는 구현하기가 가장 복잡하지 않은 것 같습니다. 둘째, 유연성이 극대화됩니다. 마지막으로 리턴 값을 명시 적 리턴으로 겹쳐 쓸 수 있습니다. 기본적으로이를 유지하면 두 동작 중 하나를 선택할 수 있습니다.

0

String 대신 StringBuffer를 사용하면 변경 내용이 표시됩니다. 반환 문이 반환되는 객체를 차단하고 참조가 아닌 것처럼 보입니다. 또한의 해시 코드 인쇄하여이를 확인을 시도 할 수 있습니다 :에 이동()

  • 객체에서 반환되는

    • 개체를 마지막으로
    • 객체

      공공 정적 무효) (주 인쇄중인

    • 메인 (문자열 []에 args) {

      Test obj=new Test(); 
           StringBuffer a=obj.go(); 
           System.out.print(a); 
          } 
          public StringBuffer go() { 
           StringBuffer q=new StringBuffer("hii"); 
           try { 
            return q; 
           } 
           finally { 
            q=q.append("hello"); 
            System.out.println("finally value of q is "+q); 
           } 
          } 
      
  • +0

    '반환 할 개체 차단'은 의미가 없습니다. 대답이 아닙니다. – EJP

    -1

    음, 제가 발견 한 것은입니다

    반환 값은 실제로 String a=obj.go();으로 복사되고 실행은 최종적으로이됩니다.

    다음 실험을 통해 확인하십시오.

    public class Test2 { 
    
        public static void main(String[] args) { 
        Test2 obj=new Test2(); 
        String a=obj.go(); 
    
        System.out.print(a); 
        } 
    
    
        public String go() { 
        String q="hii"; 
        try { 
         return q; 
        } 
        finally { 
         q="hello"; 
         System.out.println("finally value of q is "+q); 
        } 
    } 
    

    프로그램의 출력은

    마침내 Q의 값이 인사

    HII

    입니다 이며, 우리가 대신 문자열의 StringBuffer를이 걸릴 경우,

    다음과 같이
    public class Test2 { 
    
        public static void main(String[] args) { 
         // TODO Auto-generated method stub 
    
         Test2 obj=new Test2(); 
         StringBuffer a=obj.go(); 
    
         System.out.print(a); 
        } 
    
    
        public StringBuffer go(){ 
         StringBuffer q=new StringBuffer("hii"); 
         try{ 
    
          return q; 
         } 
         finally{ 
    
          q.replace(0, q.length(), "hello"); 
          System.out.println("finally value of q is "+q); 
          /*return q1;*/ 
    
         } 
    
        } 
    } 
    

    출력 comesout이 되려면

    결국 Q 값 헬로

    헬로

    우리는 INT 대신 문자열 취하여 경우 최종적으로 다음과 ,

    public class Test2 { 
    
        public static void main(String[] args) { 
         // TODO Auto-generated method stub 
    
         Test2 obj=new Test2(); 
         int a=obj.go(); 
    
         System.out.print(a); 
        } 
    
    
        public int go(){ 
         int q=1; 
         try{ 
    
          return q; 
         } 
         finally{ 
    
          q=2; 
          System.out.println("finally value of q is "+q); 
          /*return q1;*/ 
    
         } 
    
        } 
    } 
    

    의 출력이

    마지막의 Q 값이 2

    1

           **Ananlysis** 
    

    1.In 첫번째 경우와, 가변 다음 excecution에서 문자열의 복사 ADRESS를 반환 마지막으로 String이 변경되는 곳으로 이동합니다. 그러나 문자열의 경우 새로운 문자열이 생성 된 문자열을 조작 할 수 없습니다. 따라서 변수 원래 문자열의 주소가 저장되어 인쇄됩니다.

    2. 두 번째 경우에는 변수의 StringBuffer 사본 주소를 반환하고 마지막으로이 StringBuffer 객체가 조작되어 새로운 객체를 만듭니다. 그래서 변수 에 저장된 값은이되고, print 문에서 볼 수 있습니다.

    3. 마지막으로 실행하기 전에 변수 에 int 값이 복사됩니다. 따라서 은 1의 값을 얻습니다. 마지막으로 q의 값을 변경했는데, 의 값은이 아닙니다.

    +0

    답을 읽지 않았습니까? – Ahmad

    +0

    처음 두 예는 모두 부적합합니다. 첫 번째 코드는 String.repace()가 값을 변경하지 않으므로 일반 코드가 잘못되었습니다. 새 값을 반환합니다. 두 번째는 값을 변경하지만, OP가 수행하지 않는 것이므로 그 점을 보지 못합니다. 세 번째 것은 OP가 요구하는 것을 반복하고, 이미 주어진 답을 반복합니다. – EJP

    0

    finally 블록은 무엇입니까?

    -By definition from Java "try 블록이 종료 될 때 finally 블록이 항상 실행되므로 예기치 않은 예외가 발생하더라도 finally 블록이 실행됩니다."

    따라서 try 블록이 존재하고 "System.out.print (a)"행으로 이동하면 "q 값은 안녕하세요"입니다. 메소드 go()에 의해 리턴 된 값을 인쇄합니다.

    netbeans 또는 eclipse와 같은 디버거가있는 경우 중단 점을 유지하고 코드를 깨우면 분석 할 수 있습니다.