1

이렇게 비슷한 질문이 많이 있지만 알리아싱의 차이점을 명확하게 나열한 대답을 찾을 수 없어서 여기에서 묻습니다.배열 및 참조 형식이있는 Java의 별칭

내가 알고있는 간단한 기본 할당 문을 복사 값 :

int x = 1; 
int y = x; 
x = 2; 
StdOut.print(x); // prints 2 
StdOut.print(y); // prints 1 

가 그럼이 배열이 할당 문 중 '별칭'하는 말을 들었다. 그래서 : 당신이 변수 중 하나가 완전히 다른 배열을 할당하면

int[] x = {1, 2, 3, 4, 5}; 
int[] y = x; 
x[0] = 6; 
StdOut.print(x[0]); // prints 6 
StdOut.print(y[0]); // prints 6 

그러나,이 별명은 '사라'

int[] x = {1, 2, 3, 4, 5}; 
int[] y = x; 
x = new int[]{1, 2, 3, 4, 5}; 
x[0] = 6; 
StdOut.print(x[0]); // prints 1 
StdOut.print(y[0]); // prints 6 

그 이유는 무엇입니까?

그런 다음 유형을 참조하겠습니다. 대입 문을 사용하는 경우 값은 복사되지 않고 참조 만 복사됩니다. 그래서 :

Counter c1 = new Counter("ones"); 
Counter c1.incrememnt(); // 0 -> 1 
Counter c2 = c1; 
c2.increment(); 
StdOut.print(c1); // prints 2 
StdOut.print(c2); // prints 2 

하지만 그때 새로운 Counter 객체에 c1를 할당하는 경우는 어떻습니까? 무슨 일이 생길까요 c2; 원래 Counter 또는 새 Counter을 참조하는 이유는 무엇입니까?

원래는 참조 유형이 배열처럼 작동한다고 생각했기 때문에 물어 보았습니다. 새 Counter을 만들고 c1에 할당하면 Counter을 가리키며 c1c2을 모두 가리 킵니다. 그러나 몇 가지 연습을 거친 후, 나는이 가정을 위반하는 것으로 보이는 반복 가능한 Stack ADT를 만들었습니다. 내 코드는 다음과 같습니다.

import java.util.Iterator; 

public class MyStack<Item> implements Iterable<Item> { 

    private Node first; // top of stack 
    private int N; // number of items 

    private class Node { 
     Item item; 
     Node next; 
    } 

    public MyStack() {} 

    public Iterator<Item> iterator() { 
     return new ListIterator(); 
    } 

    private class ListIterator implements Iterator<Item> { 

     private Node current = first; 

     public boolean hasNext() { 
      return current != null; 
     } 

     public Item next() { 
      Item item = current.item; 
      current = current.next; 
      return item; 
     } 

    } 

    public void push(Item item) { 
     Node oldfirst = first; 
     first = new Node(); 
     first.item = item; 
     first.next = oldfirst; 
     N++; 
    } 

    public Item pop() { 
     if(!isEmpty()) { 
      Node oldfirst = first; 
      first = first.next; 
      return oldfirst.item; 
     } else throw new RuntimeException("Stack underflow"); 
    } 

    public boolean isEmpty() { return size() == 0; } 

    public int size() { return N; } 

    public static void main(String[] args) { 
     MyStack<Integer> stack = new MyStack<>(); 
     stack.push(5); 
     stack.push(6); 
     stack.push(7); 
     stack.push(8); 
     stack.push(9); 
     for(int i : stack) { 
      StdOut.println(i); 
     } 
    } 

} 

이것은 항목에 대한 연결 목록 데이터 구조를 사용하는 간단한 구현입니다. 기본 인스턴스 변수는 first이며 링크 된 목록 (스택 맨 위)의 첫 번째 노드를 보유합니다. 중첩 된 ListIterator 클래스를 보면 first에 할당 된 인스턴스 변수 current이 있습니다. 이제 push 메서드에서 first이 새로 생성 된 Node으로 다시 할당됩니다. 확실히 current 변수는 이전의 first 노드에 여전히 할당되어 있습니까? 그런데 왜이 구현이 작동합니까?

내 직감은 a) 참조 값이 전달되는 방법을 이해할 수 없거나 (설명하십시오) b) 주 방법에서 for 루프를 실행할 때 암시 적으로 새로운 ListIterator을 만듭니다. 그 점은 first의 현재 값이 무엇이든간에 current을 할당합니다. 이것이 진짜 이유라면, 클래스 내에서 메소드가 호출 될 때마다 새로운 반복자가 만들어 져야한다는 것을 의미합니까? 예를 들어 반복자를 명시 적으로 만든 다음 스택에 몇 가지 항목을 밀어 넣은 다음 다시 초기화하지 않고 반복자를 다시 사용합니다. 의도 한대로 작동합니까?

설명해주세요!

+0

배열 유형 **은 ** 참조 유형입니다. 용어 _alias_는 Java에서 일반적으로 사용되지 않습니다. 참조, 변수 및 객체를 구별해야합니다. –

답변

6

왜 그럴까요?

변수 x와 y는 배열이 아닙니다. 그것들은 배열 참조입니다.배열은 객체이고, x와 y가 다른 배열을 참조하도록 x를 재 할당했습니다. 따라서 x가 변경되었으므로 두 개의 다른 배열에서 다른 값을 갖게됩니다.

c2는 어떻게됩니까? 원래 카운터 또는 새 카운터를 참조하는 이유는 무엇입니까?

당신의 예에서이 아무 원본이 없습니다, 당신은 (C1)가 참조하는 것과 같은 인스턴스를 참조 C2 카운터 참조를 만든, 그래서 그들은 같은를 가리키고, 당신이 new Counter라는 단 하나 개의 카운터 객체 생성이 있었다 맡은 일.

확실하게 현재 변수는 이전의 첫 번째 노드에 할당됩니까? 그런데 왜이 구현이 작동합니까?

귀하의 각 루프에 대한

은 당신의 스택 first의 최신 값을 가리키는 current 자신의 인스턴스 새로운 ListIterator을 반환 iterator()를 호출합니다.

+0

두 번째 질문에서, 저는 @Keir이 주어진 코드 블록 다음에 새로운 카운터가 생성되어 c1에 할당되었다는 것을 의미한다고 생각합니다. 즉, 주어진 코드 예제를'c1 = new Counter ("two"); ' '줄에 추가합니다.이 경우 c2는 여전히 "ones"카운터를 참조하지만 c1은 "two"카운터를 참조합니다. c2에 추가 할당이 없으므로 c2에 의해 참조 된 개체는 변경되지 않습니다. – Tim

1

Java 입문에 대한 나의 관심 중 하나는 종종 앨리어싱이 거의 언급되지 않는다는 것입니다. 자바가 의미하는 바를 깨닫기 위해서는 자바를 이해하는 것이 중요합니다. 그러므로 제 견해로는 입문 Java 과정의 주요 측면이되어야합니다. 종종 자바가 완전히 가르쳐지지 않는다고 생각하는 학생들을 자주 발견합니다. 제대로 가르쳐주지 못했기 때문입니다.

정말 어렵지 않습니다. v1과 v2가 객체 유형의 두 변수 인 경우 할당 v2 = v1은 "v2가 참조하는 데 사용한 참조를 중지하고 참조를 시작한다는 것을 의미합니다 v1은 무엇을 가리키는가?

개체 유형이 v3 인 다른 변수가 있고 v2 = v1을 수행 한 후에 v1 = v3을 수행하면 "v1이 참조했던 것을 참조하는 것을 중지하고 v3에서 참조하는 것을 참조하기 시작합니다 ". 그렇다고 v2가 v1이 참조했던 것을 참조하는 것을 v2가 중단하지 않는다는 것을 의미하지는 않습니다. 당신의 오해는 그것을 생각하는 것으로 떨어집니다.