Java에서 포인터를 어떻게 사용할 수 있습니까?


112

Java에 포인터가 없다는 것을 알고 있지만 Java 프로그램은 포인터로 만들 수 있으며 Java 전문가 인 소수만 수행 할 수 있다고 들었습니다. 사실인가요?


1
어쨌든 Sun의 구현에서.
Michael Myers

1
나는 그 포인터 주소를 사용할 수 있습니다

6
자바 객체의 기본 hashCode는 포인터 주소가 아닙니다. hashCode에 대한 계약을주의 깊게 다시 읽으면 메모리에있는 두 개의 개별 객체가 동일한 hashCode 값을 가질 수 있습니다.
Amir Afghani

3
64 비트 및 32 비트 Java에서 32 비트 hashCode는 주소가 아닙니다. hashCode는 고유하지 않을 수 있습니다. 객체의 위치는 공간 사이를 이동하고 메모리가 압축됨에 따라 메모리에서 이동할 수 있지만 hashCode는 변경되지 않습니다.
Peter Lawrey 2009

2
C ++ 포인터로 할 수있는 작업의 90 %는 Java refrences로 할 수 있고 나머지 10 %는 annother 객체 내부에 참조를 패키징하여 얻을 수 있습니다 (내가 그렇게하는 것이 적절하다는 것을 알지 못함)
Richard Tingle

답변:


243

Java의 모든 객체는 참조이며 포인터처럼 사용할 수 있습니다.

abstract class Animal
{...
}

class Lion extends Animal
{...
}

class Tiger extends Animal
{   
public Tiger() {...}
public void growl(){...}
}

Tiger first = null;
Tiger second = new Tiger();
Tiger third;

null 역 참조 :

first.growl();  // ERROR, first is null.    
third.growl(); // ERROR, third has not been initialized.

별칭 문제 :

third = new Tiger();
first = third;

손실 세포 :

second = third; // Possible ERROR. The old value of second is lost.    

먼저 이전 값인 second가 더 이상 필요하지 않음을 먼저 확인하거나 다른 포인터에 second 값을 할당하여이를 안전하게 만들 수 있습니다.

first = second;
second = third; //OK

second에 다른 방식 (NULL, new ...)으로 값을 제공하는 것은 잠재적 인 오류와 마찬가지로 그것이 가리키는 객체를 잃을 수 있습니다.

OutOfMemoryErrornew를 호출하고 할당자가 요청 된 셀을 할당 할 수없는 경우 Java 시스템에서 예외 ( )가 발생합니다. 이는 매우 드물며 일반적으로 폭주 재귀로 인해 발생합니다.

언어 관점에서 가비지 수집기에 개체를 버리는 것은 오류가 아닙니다. 프로그래머가 알아야 할 것입니다. 동일한 변수가 다른 시간에 다른 개체를 가리킬 수 있으며 포인터가 참조하지 않으면 이전 값이 회수됩니다. 그러나 프로그램의 논리가 개체에 대한 참조를 하나 이상 유지해야하는 경우 오류가 발생합니다.

초보자는 종종 다음과 같은 오류를 범합니다.

Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed. 

아마 당신이 말하려는 것은 다음과 같습니다.

Tiger tony = null;
tony = third; // OK.

부적절한 주조 :

Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler. 

Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.

C의 포인터 :

void main() {   
    int*    x;  // Allocate the pointers x and y
    int*    y;  // (but not the pointees)

    x = malloc(sizeof(int));    // Allocate an int pointee,
                                // and set x to point to it

    *x = 42;    // Dereference x to store 42 in its pointee

    *y = 13;    // CRASH -- y does not have a pointee yet

    y = x;      // Pointer assignment sets y to point to x's pointee

    *y = 13;    // Dereference y to store 13 in its (shared) pointee
}

자바의 포인터 :

class IntObj {
    public int value;
}

public class Binky() {
    public static void main(String[] args) {
        IntObj  x;  // Allocate the pointers x and y
        IntObj  y;  // (but not the IntObj pointees)

        x = new IntObj();   // Allocate an IntObj pointee
                            // and set x to point to it

        x.value = 42;   // Dereference x to store 42 in its pointee

        y.value = 13;   // CRASH -- y does not have a pointee yet

        y = x;  // Pointer assignment sets y to point to x's pointee

        y.value = 13;   // Deference y to store 13 in its (shared) pointee
    }
} 

업데이트 : 주석에서 제안했듯이 C에는 포인터 산술이 있다는 점에 유의해야합니다. 그러나 Java에는 없습니다.


16
좋은 대답이지만 한 가지 중요한 차이점을 해결하지 못했습니다. C에는 포인터 산술이 있습니다. (다행히도) Java에서는 그렇게 할 수 없습니다.
R. Martinho Fernandes

10
나는 어떤 대답, 특히 인기있는 대답에 반대 투표하는 것을 싫어하지만 Java에는 포인터가 없으며 단순히 포인터와 같은 참조를 사용할 수 없습니다. 실제 포인터로만 할 수있는 특정 작업이 있습니다. 예를 들어 프로세스 데이터 공간에서 임의의 바이트를 가져 오거나 설정할 수 있습니다. 자바에서는 그렇게 할 수 없습니다. 여기에있는 많은 사람들이 포인터가 실제로 무엇인지 이해하지 못하는 것 같아서 정말 안타깝습니다. imho, 이제 나는 내 폭언 비누 상자에서 벗어나 내 작은 폭발에 대해 용서해 주시기 바랍니다.
Danger

5
안타깝게 생각합니다. Java가 포인터 산술을 지원하지 않는 것이 왜 좋다고 생각합니까?
user3462295

2
@ user3462295 사람들은 일반 대중이 사용하기가 너무 어렵다고 생각하고 컴파일러 또는 장치 드라이버를 작성하는 닌자를 코딩해야만 이해할 수 있기 때문입니다.
iCodeSometime

4
@Danger 첫 번째 답변 "Java의 모든 객체는 참조이며 포인터처럼 사용할 수 있습니다." 이것이 제공 할 수있는 최상의 답변입니다. 유일한 대답이 "아니오, Java에는 포인터가 없습니다."였다면 그 대답은 도움이되지 않았을 것입니다. 이 답변은 대신 할 수있는 작업을 나타냅니다.
csga5000 2015

46

Java에는 포인터가 있습니다. Java로 객체를 생성 할 때마다 실제로 객체에 대한 포인터를 생성합니다. 이 포인터는 다른 객체 또는로 설정 될 수 null있으며 원래 객체는 여전히 존재합니다 (가비지 수집 보류).

Java에서 할 수없는 것은 포인터 산술입니다. 특정 메모리 주소를 역 참조하거나 포인터를 증가시킬 수 없습니다.

저수준을 원한다면 Java Native Interface를 사용하는 것이 유일한 방법입니다 . 그런 다음에도 저수준 부분은 C 또는 C ++로 수행해야합니다.


9
Java에는 단순하고 단순한 포인터가 없으며 여기에 많은 답변이 잘못된 정보를 말하는 이유를 평생 이해할 수 없습니다. 이것은 StackOverlfow 사람들입니다! 컴퓨터 과학에서 포인터의 정의는 다음과 같습니다 (Google에서 가능). "컴퓨터 과학에서 포인터는 프로그래밍 언어 개체이며, 그 값은 다음을 사용하여 컴퓨터 메모리의 다른 곳에 저장된 다른 값을 참조 (또는"가리 키 ")합니다. 주소. " Java의 참조는 포인터가 아닙니다. Java는 가비지 수집을 실행해야하며 실제 포인터가 있으면 잘못된 것입니다!
Danger

3
@Danger 포인터는 메모리 주소를 포함하는 데이터 조각입니다. 자바는 사람들이 잊어 버리는 두 가지입니다. 그것은 언어이자 플랫폼입니다. .NET이 언어라고 말하지 않는 것처럼 'Java에는 포인터가 없습니다'라는 말은 물론 플랫폼이 포인터를 갖고 사용하기 때문에 오해의 소지가 있음을 기억해야합니다. 이러한 포인터는 Java 언어를 통해 프로그래머가 액세스 할 수 없지만 런타임에는 존재합니다. 언어의 참조는 런타임의 실제 포인터 위에 존재합니다.
kingfrito_5005

@ kingfrito_5005 당신이 저와 동의하는 것 같습니다. 나는 당신이 "자바에는 포인터가 없다"는 내 진술과 일치하는 "그 포인터는 자바 언어를 통해 프로그래머가 접근 할 수 없다"고 말했다고 생각한다. 참조는 의미 상 포인터와 상당히 다릅니다.
Danger

1
@Danger 이것은 사실이지만 이러한 경우 플랫폼과 언어를 구별하는 것이 중요하다고 생각합니다. 왜냐하면 처음 시작할 때 당신과 같은 진술을 시작할 때 나를 혼란스럽게 만들었 기 때문입니다.
kingfrito_5005 2015-08-05

1
네, Java는 확실히 변수 뒤에 포인터가 있습니다. 자바가 뒤에서 이것에 대한 마법을 수행하기 때문에 개발자는 그들을 다룰 필요가 없습니다. 이는 개발자가 특정 메모리 주소를 변수로 직접 가리키고 데이터 오프셋 및 항목을 처리 할 수 ​​없음을 의미합니다. 그것은 자바가 깨끗한 메모리 가비지 콜렉션을 유지할 수있게 해주지 만, 모든 변수는 본질적으로 포인터이기 때문에, 더 낮은 수준의 언어에서는 피할 수 있었던 모든 자동 생성 포인터 주소를 갖기 위해 약간의 추가 메모리가 필요합니다.
VulstaR

38

Java에는 포인터 데이터 유형이 없으므로 Java에서 포인터를 사용할 수 없습니다. 소수의 전문가조차도 자바에서 포인터를 사용할 수 없습니다.

마지막 요점 : Java 언어 환경 도 참조하십시오.


3
여기 몇 가지 정답 중 하나는 거의 찬성표가 없습니까?
Danger

포인터와 같은 동작을 시뮬레이트하는 '포인터'객체가 있습니다. 많은 목적을 위해 이것은 동일한 방식으로 사용될 수 있습니다. 질문의 본질을 감안할 때 아무도 이것을 언급하지 않은 것이 이상하다고 느낍니다.
kingfrito_5005

이것이 맨 위에있는 대답이어야합니다. 초보자가 "뒤에서 자바가 포인터를 가지고있다"고 말하는 것은 매우 혼란스러운 상태로 이어질 수 있기 때문입니다. Java가 시작 수준에서 학습 된 경우에도 포인터가 안전하지 않기 때문에 Java에서 사용되지 않습니다. 프로그래머는 무엇을보고 작업 할 수 있는지를 알아야합니다. 참조와 포인터는 실제로 매우 다릅니다.
Neeraj Yadav

링크의 "2.2.3 No Enums"항목에 전적으로 동의하는지 잘 모르겠습니다. 데이터가 오래되었을 수 있지만 Java 열거 형을 지원합니다.
Sometowngeek 19

1
@Sometowngeek에 링크 된 문서는 자바의 첫 번째 버전을 설명하는 1996 년의 백서입니다. 열거 형은 Java 버전 1.5 (2004)에 도입되었습니다
Fortega

11

Java에는 포인터가 있지만 C ++ 또는 C에서 할 수있는 방식으로 포인터를 조작 할 수 없습니다. 객체를 전달할 때 해당 객체에 대한 포인터를 전달하지만 C ++에서와 같은 의미는 아닙니다. 해당 개체는 역 참조 할 수 없습니다. 네이티브 접근자를 사용하여 값을 설정하면 Java가 포인터를 통해 메모리 위치를 알고 있기 때문에 값이 변경됩니다. 그러나 포인터는 변경할 수 없습니다. 포인터를 새 위치로 설정하려고하면 대신 다른 것과 동일한 이름을 가진 새 로컬 개체가 생성됩니다. 원래 개체는 변경되지 않습니다. 다음은 차이점을 보여주는 간단한 프로그램입니다.

import java.util.*;
import java.lang.*;
import java.io.*;

class Ideone {

    public static void main(String[] args) throws java.lang.Exception {
        System.out.println("Expected # = 0 1 2 2 1");
        Cat c = new Cat();
        c.setClaws(0);
        System.out.println("Initial value is " + c.getClaws());
        // prints 0 obviously
        clawsAreOne(c);
        System.out.println("Accessor changes value to " + c.getClaws());
        // prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
        makeNewCat(c);
        System.out.println("Final value is " + c.getClaws());
        // prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
    }

    public static void clawsAreOne(Cat kitty) {
        kitty.setClaws(1);
    }

    public static void makeNewCat(Cat kitty) {
        Cat kitten = new Cat();
        kitten.setClaws(2);
        kitty = kitten;
        System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
        //Prints 2. the value pointed to by 'kitten' is 2
        System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
        //Prints 2. The local copy is being used within the scope of this method.
    }
}

class Cat {

    private int claws;

    public void setClaws(int i) {
        claws = i;
    }

    public int getClaws() {
        return claws;
    }
}

Ideone.com에서 실행할 수 있습니다.


10

Java에는 C와 같은 포인터가 없지만 변수에 의해 "참조되는"힙에 새 개체를 만들 수 있습니다. 포인터가 없다는 것은 Java 프로그램이 메모리 위치를 불법적으로 참조하는 것을 막고, 가비지 수집이 Java Virtual Machine에 의해 자동으로 수행되도록하는 것입니다.


7

Unsafe 클래스를 사용하여 주소와 포인터를 사용할 수 있습니다. 그러나 이름에서 알 수 있듯이 이러한 방법은 안전하지 않으며 일반적으로 나쁜 생각입니다. 잘못된 사용으로 인해 JVM이 무작위로 죽을 수 있습니다 (실제로 C / C ++에서 포인터를 잘못 사용하는 것과 동일한 문제)

포인터에 익숙하고 포인터가 필요하다고 생각할 수 있지만 (다른 방법으로 코딩하는 방법을 모르기 때문에), 그렇지 않다는 것을 알게되고 더 나을 것입니다.


8
포인터는 매우 강력하고 유용합니다. 포인터 (Java)가 없으면 코드의 효율성이 훨씬 떨어지는 경우가 많습니다. 사람들이 포인터 사용을 싫어한다고해서 언어가 포인터를 배제해야한다는 의미는 아닙니다. 다른 사람들 (군대와 같은)이 사람들을 죽이는 데 사용하기 때문에 소총을 가져서는 안됩니까?
Ethan Reesor

1
언어가있는 그대로 Java에서 할 수없는 유용하거나 강력하지 않습니다. 다른 모든 것에는 매우 드물게 사용해야하는 Unsafe 클래스가 있습니다.
Peter Lawrey

2
지난 40 년 동안 작성한 코드의 대부분은 Java로 구현할 수 없었습니다. Java에는 핵심적인 저수준 기능이 없기 때문입니다.
Danger

1
@Danger 이것이 많은 라이브러리가 Unsafe를 사용하는 이유이며이를 제거하는 아이디어는 Java 9에서 많은 논쟁을 불러 일으켰습니다. 계획은 대체품을 제공하는 것이지만 아직 준비되지 않았습니다.
피터 Lawrey

3

기술적으로 모든 Java 객체는 포인터입니다. 모든 기본 유형은 값입니다. 이러한 포인터를 수동으로 제어 할 수있는 방법은 없습니다. Java는 내부적으로 참조에 의한 전달을 사용합니다.


1
JNI를 통해서도? 여기서는 Java 지식이 없지만 저수준의 비트 그루 빙을 그렇게 할 수 있다고 들었습니다.
David Seiler

4 년 동안의 Java 경험과 대답을 직접 찾고있는 한, Java 포인터는 외부에서 액세스 할 수 없습니다.
Poindexter

응답 해 주셔서 감사합니다. 내 강사가 자바는 핸드 헬드 장치에 사용되는 연구 수준에 있다고 말했다 때문에 ,, 그들이 ... 그 포인터를 사용 물었다 내가 물었다이야

@unknown (google) 연구 수준이라면 수행중인 작업에 따라 그러한 기능이 필요했을 수 있으므로 정상적인 관용구를 위반하고 어쨌든 구현했습니다. 일반 Java 기능의 상위 집합 (또는 하위 집합 또는 혼합)을 원할 경우 고유 한 JVM을 구현할 수 있지만 이러한 코드는 다른 Java 플랫폼에서 실행되지 않을 수 있습니다.
San Jacinto

@san : 답변 주셔서 감사합니다. BTW 투표 할 수 없습니다 .. 15 개의 평판이 필요하다고 말합니다

2

아니에요.

Java에는 포인터가 없습니다. 당신이 경우 정말 원하는 당신은 반사 같은 주위를 구축하여 그들을 모방을 시도 할 수 있지만 모든 것 복잡성 의 없음과 포인터의 장점을 .

Java에는 포인터가 필요하지 않기 때문에 포인터가 없습니다. 이 질문에서 어떤 종류의 답변을 원했습니까? 즉, 무언가에 사용할 수 있기를 바랐습니까, 아니면 그냥 호기심 이었습니까?


나는 그것을 알고 싶습니다. 답변 해 주셔서 감사합니다

Java에는 포인터가 필요합니다. 이것이 Java가 JNI를 추가 한 이유입니다. "포인터와 유사한"또는 어떤 코드를 작성하더라도 Java에서 할 수없는 하위 수준의 함수가 부족한 문제를 해결하기 위해.
Danger

2

자바의 모든 객체는 프리미티브를 제외한 참조 복사에 의해 함수로 전달됩니다.

실제로 이것은 개체 자체의 복사본이 아닌 원래 개체에 대한 포인터 복사본을 보내는 것을 의미합니다.

이것을 이해하기위한 예제를 원한다면 코멘트를 남겨주세요.


이것은 명백한 잘못입니다. swap두 개체를 교환하는 Java 함수를 작성할 수 없습니다 .
Michael Tsang

2

Java 참조 유형은 Java에서 포인터에 대한 포인터를 가질 수 없기 때문에 C 포인터와 동일하지 않습니다.


1

다른 사람들이 말했듯이 짧은 대답은 "아니오"입니다.

물론 Java 포인터로 재생되는 JNI 코드를 작성할 수 있습니다. 달성하려는 작업에 따라 어딘가에 도착할 수도 있고 그렇지 않을 수도 있습니다.

배열을 만들고 인덱스를 배열에 사용하여 항상 포인트를 시뮬레이션 할 수 있습니다. 다시 말하지만, 수행하려는 작업에 따라 유용 할 수도 있고 유용하지 않을 수도 있습니다.


1

Godfrey Nolan의 Decompiling Android라는 책에서 발췌

보안은 포인터가 Java에서 사용되지 않기 때문에 해커가 응용 프로그램에서 벗어나 운영 체제로 침입 할 수 없도록 지정합니다. 포인터가 없다는 것은 다른 것이 (이 경우 JVM) 메모리 할당 및 해제를 처리해야 함을 의미합니다. 메모리 누수도 과거의 일이되어야합니다. 그렇지 않으면 이론이 진행됩니다. C 및 C ++로 작성된 일부 응용 프로그램은 프로그래머가 적절한 시간에 원치 않는 메모리를 확보하는 데주의를 기울이지 않기 때문에 체처럼 메모리를 누출하는 것으로 악명이 높습니다.이를 읽는 사람은 그러한 죄를 범하는 것이 아닙니다. 가비지 수집은 또한 메모리 문제를 디버깅하는 데 소요되는 시간을 줄이면서 프로그래머의 생산성을 높여야합니다.


0

리터럴에 대한 포인터도 가질 수 있습니다. 직접 구현해야합니다. 전문가에게는 매우 기본입니다.). int / object / long / byte 배열을 사용하고 포인터를 구현하기위한 기본 사항이 있습니다. 이제 모든 int 값은 해당 배열 int []에 대한 포인터가 될 수 있습니다. 포인터를 증가시킬 수 있고, 포인터를 감소시킬 수 있으며, 포인터를 곱할 수 있습니다. 실제로 포인터 산술이 있습니다! 이것이 1000 개의 int 속성 클래스를 구현하고 모든 속성에 적용되는 일반 메서드를 갖는 유일한 방법입니다. int [] 대신 byte [] 배열을 사용할 수도 있습니다.

그러나 Java가 참조로 리터럴 값을 전달할 수 있기를 바랍니다. 라인을 따라 뭔가

//(* telling you it is a pointer) public void myMethod(int* intValue);


-1

주소를 보유한 변수를 포인터라고하고 객체 보유 주소를 객체라고하므로 모든 자바 객체는 포인터입니다.


1
아니요, Java 개체는 포인터가 아닙니다. 이들은 다른 기능 및 의미 집합을 가진 참조와 동일합니다.
Danger
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.