우리는 이전에도 "객체"라는 개념을 사용해왔지만 객체가 메모리에 저장되는 구체적인 방식에 대해서는 논의하지 않았습니다. 이 논의는 "객체 참조"라는 중요한 개념으로 이어질 것입니다.
객체 참조
이전에 정의한 Human 클래스를 계속 사용하고 Test 클래스도 있습니다.
다음과 같이 코드 코드를 복사합니다.
공개 수업 테스트
{
공개 정적 무효 메인(문자열[] 인수)
{
인간 aPerson = 새로운 인간(160);
}
}
수업인간
{
/**
* 생성자
*/
공개 인간(int h)
{
this.높이 = h;
}
/**
*접속자
*/
공개 int getHeight()
{
this.height를 반환합니다.
}
/**
* 돌연변이
*/
공공 무효 성장 높이(int h)
{
this.height = this.height + h;
}
개인 정수 높이;
}
Test 클래스에서 위와 같이 클래스를 외부에서 호출하여 객체를 생성할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
인간 aPerson = 새로운 인간(160);
Human 클래스의 aPerson 객체가 생성됩니다.
위의 내용은 매우 간단한 설명이지만 자세히 설명해야 할 내용이 많이 있습니다.
1. 먼저 등호의 오른쪽을 보세요. new는 메모리에 객체를 위한 공간을 열어줍니다. 특히 new는 메모리 힙에 객체를 위한 공간을 열어줍니다. 이 공간에는 객체의 데이터와 메소드가 저장됩니다.
2. 등호의 왼쪽을 보세요. aPerson은 개체 참조라고 하는 인간 개체를 나타냅니다. 실제로 aPerson은 객체 자체는 아니지만 객체에 대한 포인터와 유사합니다. aPerson은 메모리의 스택에 존재합니다.
3. 등호를 사용하여 값을 할당하면 오른쪽의 new에 의해 힙에 생성된 객체의 주소가 객체 참조에 할당됩니다.
여기서 메모리란 JVM(Java Virtual Machine)에 의해 가상화된 자바 프로세스 메모리 공간을 의미한다. 메모리의 힙과 스택 개념에 대해서는 Linux From Program to Process를 참조하세요.
스택은 힙보다 빠르게 읽을 수 있지만 스택에 저장되는 데이터는 유효한 범위에 의해 제한됩니다. C 언어에서는 함수 호출이 끝나면 해당 스택 프레임이 삭제되고, 스택 프레임에 저장된 매개변수와 자동 변수도 사라진다. Java의 스택에도 동일한 제한이 적용됩니다. 메서드 호출이 끝나면 해당 메서드에 의해 스택에 저장된 데이터가 지워집니다. Java에서는 모든 (일반) 객체가 힙에 저장됩니다. 따라서 new 키워드의 전체 의미는 힙에 개체를 만드는 것입니다.
int 및 double과 같은 기본 유형의 객체는 스택에 저장됩니다. 기본 유형을 선언하면 new가 필요하지 않습니다. 일단 선언되면 Java는 기본 유형의 데이터를 스택에 직접 저장합니다. 따라서 기본형의 변수명은 참조가 아닌 데이터 자체를 나타낸다.
참조와 대상의 관계는 연과 사람과 같습니다. 우리가 하늘을 볼 때(프로그램에 쓰여 있음) 우리가 보는 것은 연(참조)이지만, 연에 해당하는 것은 사람(객체)입니다.
참조와 개체의 분리 참조는 개체를 가리킵니다.
참조와 객체는 분리되어 있지만 reference.method()를 통해 객체 메서드에 액세스하는 것과 같이 객체에 대한 모든 액세스는 참조의 "문"을 통과해야 합니다. Java에서는 참조를 건너뛰고 객체를 직접 터치할 수 없습니다. 또 다른 예로, 객체 a의 데이터 멤버가 일반 객체 b인 경우 a의 데이터 멤버는 객체 b에 대한 참조를 저장합니다(기본 유형 변수인 경우 a의 데이터 멤버는 기본 유형 변수 자체를 저장합니다). .
Java에서는 참조가 포인터 역할을 하지만 C 언어처럼 포인터 값에 1을 더하는 등 포인터의 값을 직접 수정할 수는 없습니다. 참조를 통해서만 객체에 대한 작업을 수행할 수 있습니다. 이 디자인은 포인터로 인해 발생할 수 있는 많은 오류를 방지합니다.
참조 할당
참조를 다른 참조에 할당하면 실제로 개체의 주소가 복사됩니다. 두 참조 모두 동일한 개체를 가리킵니다. 예를 들어 dummyPerson=aPerson의 결과는 다음과 같습니다.
객체는 여러 참조를 가질 수 있습니다(한 사람이 여러 개의 연을 날릴 수 있음). 프로그램이 하나의 참조를 통해 개체를 수정하면 수정 사항은 다른 참조를 통해 표시됩니다. 다음 Test 클래스를 사용하여 실제 효과를 테스트할 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
공개 수업 테스트
{
공개 정적 무효 메인(문자열[] 인수)
{
인간 aPerson = 새로운 인간(160);
인간 dummyPerson = aPerson;
System.out.println(dummyPerson.getHeight());
aPerson.growHeight(20);
System.out.println(dummyPerson.getHeight());
}
}
aPerson에 대한 수정 사항은 dummyPerson에 영향을 미칩니다. 이 두 참조는 실제로 동일한 개체를 가리킵니다.
따라서 다른 참조에 참조를 할당해도 개체 자체는 복사되지 않습니다. 객체를 복사하는 다른 메커니즘을 찾아야 합니다.
쓰레기 수거
메서드 호출이 끝나면 참조 및 기본 유형 변수가 지워집니다. 개체는 힙에 있으므로 메서드 호출이 종료될 때 개체가 차지하는 메모리는 지워지지 않습니다. 프로세스 공간은 생성되는 개체로 빠르게 채워질 수 있습니다. Java에는 메모리 공간을 회수하는 데 더 이상 사용되지 않는 객체를 제거하기 위한 내장형 가비지 수집 메커니즘이 있습니다.
가비지 수집의 기본 원칙은 객체를 가리키는 참조가 있으면 객체가 재활용되지 않고 객체를 가리키는 참조가 없으면 객체가 지워지는 것입니다. 차지하는 공간이 회수됩니다.
위 그림은 특정 시점의 JVM의 메모리 상태를 가정한 것입니다. Human 개체에는 스택의 aPerson 및 dummyPerson과 다른 개체의 데이터 멤버인 President라는 세 가지 참조가 있습니다. 클럽 개체에 참조가 없습니다. 이때 가비지 컬렉션이 시작되면 클럽 개체가 비워지고, 클럽 개체에서 휴먼 개체의 참조(회장)도 삭제됩니다.
가비지 수집은 Java의 운영 효율성에 직접적인 영향을 미치는 Java의 중요한 메커니즘입니다. 자세한 내용은 나중에 다루겠습니다.
매개변수 전달
참조와 객체의 개념을 분리하면 Java 메소드의 매개변수 전달 메커니즘은 실제로 매우 명확합니다. 즉, Java 매개변수 전달은 값을 기준으로 이루어집니다. 즉, 매개변수를 전달하면 메서드가 매개변수의 복사본을 가져옵니다.
실제로 우리가 전달하는 매개변수 중 하나는 기본 유형의 변수이고 다른 하나는 객체에 대한 참조입니다.
기본 유형 변수의 값별 전달은 변수 자체가 복사되어 Java 메소드에 전달됨을 의미합니다. Java 메소드에 의한 변수 수정은 원래 변수에 영향을 주지 않습니다.
값으로 전달한다는 것은 객체의 주소가 복사되어 Java 메소드에 전달된다는 의미입니다. 이 참조를 기반으로 하는 Java 메소드 액세스는 객체에 영향을 미칩니다.
여기서 언급할 만한 또 다른 상황이 있습니다. 메소드 내에서 new를 사용하여 객체를 생성하고 객체에 대한 참조를 반환합니다. 참조에 의해 반환이 수신되면 개체의 참조가 0이 아니므로 개체는 여전히 존재하며 가비지 수집되지 않습니다.
요약
새로운
참조, 객체
가비지 수집 조건
매개변수: 값으로 전달됨