Java에는 C #의 ref 및 out 키워드와 같은 것이 있습니까?


113

다음과 같은 것 :

참조 예 :

void changeString(ref String str) {
    str = "def";
}

void main() {
    String abc = "abc";
    changeString(ref abc);
    System.out.println(abc); //prints "def"
}

아웃 예 :

void changeString(out String str) {
    str = "def";
}

void main() {
    String abc;
    changeString(out abc);
    System.out.println(abc); //prints "def"
}


5
IMO 당신은 많이 그리워하지 않습니다. 내가 사용하는 유일한 시간 ref또는 out내가 같은 패턴을 사용하고 때 C #에서이다 TryParse()방법은 부울 결과를 반환하고, 그것에서 구문 분석 된 값을 얻을 수있는 유일한 방법을 사용하는 것입니다 refout.
Robert Harvey

3
내가 사용해야하는 것이 옳은지 맞춰보세요! ;)
삼켜 진 elysium

다른 방법은 상태와 nullable 값이 모두 포함 된 복합 객체를 반환하는 것입니다. 그러나 나는 그것이 약간 Rube Goldberg-ish임을 인정합니다.
Robert Harvey

1
미리 정의 된 사용 가능한 객체 (예 : 튜플) 만 있으면 복합 객체를 반환하는 데 문제가 없습니다. 그러나 잠깐, 그것은 효율적이기 위해 원시 유형으로 작업하는 삭제되지 않은 제네릭이 필요합니다. :)
Pavel Minaev

답변:


102

아니요, Java에는 참조로 전달하기위한 C # refout키워드 와 같은 것이 없습니다 .

Java에서는 값으로 만 전달할 수 있습니다. 참조조차도 값으로 전달됩니다. 자세한 내용 은 Java에서 매개 변수 전달에 대한 Jon Skeet 의 페이지 를 참조하십시오.

비슷한 수행 ref또는 out다른 개체 내부에 매개 변수를 포장하고 매개 변수로 해당 개체의 참조를 전달해야합니다.


5
이것은 일부에서 확장되어야합니다. 기본 요소 (int, short, char 등) 만 값으로 전달할 수 있습니다. 그리고 아니, 아웃이 없습니다.
Corey Sunwold

14
그것은 100 % 사실이 아닙니다. 배열이나 클래스에 전달하면 배열이나 객체에 대한 참조가 값으로 전달됩니다. 내부를 배열이나 객체로 변경할 수 있으며 호출자에게 반영됩니다.
Romain Hippeau

12
@fearofawhackplanet : 음, ref.
Robert Harvey

2
@fearofawhackplanet : Reference parameters need the ref modifier as part of both the declaration and the invocation - that means it's always clear when you're passing something by reference. yoda.arachsys.com/csharp/parameters.html
Mark Byers

5
CLR 관점에서 T&값 으로 관리 참조 ( )를 전달합니다 . 그러나 C #에는 고유 한 용어가 있으며 ref TC # 관점에서 보면 유형의 값과 같은 것을 포함하지 않고 ref엄격하게 매개 변수 수정 자이며 이에 대해 "값으로 참조 전달"이라고 말하는 것은 의미가 없습니다. .
Pavel Minaev

30

직접 답변 : 아니요

그러나 래퍼로 참조를 시뮬레이션 할 수 있습니다 .

그리고 다음을 수행하십시오.

void changeString( _<String> str ) {
    str.s("def");
}

void testRef() {
     _<String> abc = new _<String>("abc");
     changeString( abc );
     out.println( abc ); // prints def
}

void setString( _<String> ref ) {
    str.s( "def" );
}
void testOut(){
    _<String> abc = _<String>();
    setString( abc );
    out.println(abc); // prints def
}

그리고 기본적으로 다음과 같은 다른 유형 :

_<Integer> one = new <Integer>(1);
addOneTo( one );

out.println( one ); // May print 2

28
아야. 그것은 못 생겼다.
삼켜 진 elysium

46
나는 결코 말하지 않았다, 당신은 이렇게 우아한 방식으로 그것을 할 수있다 : P
OscarRyz

그래서 왜 다음은 작동하지 않습니다 : private static void ParseLine (String newline, String [] aWrapper, Integer [] bWrapper) {StringTokenizer st = new StringTokenizer (newline); aWrapper [0] = st.nextToken (); bWrapper [0] = new Integer (st.nextToken ()); } ParseLine (newline, new String [] {a}, new Integer [] {b});
Elad Benda

3
@ user311130 코드는 읽기 어려운,하지만 당신은 뭔가를 말하는 새로운 질문을 만들 수 있습니다 : 나는 <내 대답에 링크>이 대답을 발견을 "하지만 다음은 <여기에 코드>하지 작업을 수행
OscarRyz

그것은 끔찍한 일이지만, 지금이 순간에 Java에 대해 생각할 수있는 "가장 깨끗한"방식으로 문제를 해결하기 때문에 여전히 좋아요를 표시하고 있습니다.
Pangamma

8

실제로 내가 아는 한 Java 언어 에는 ref 또는 out 키워드 가 없습니다 . 그러나 저는 매개 변수 를 사용 하는 JavaC # 코드를 변환했으며 방금 수행 한 작업을 조언합니다. 어떤 객체 든 래퍼 클래스로 래핑하고 다음과 같이 래퍼 객체 인스턴스에 래핑 된 값을 전달해야합니다.

래퍼 사용에 대한 간단한 예

다음은 래퍼 클래스입니다 .

public class Wrapper {
    public Object ref1; // use this as ref
    public Object ref2; // use this as out

    public Wrapper(Object ref1) {
        this.ref1 = ref1;
    }
}

그리고 여기에 테스트 코드가 있습니다.

public class Test {

    public static void main(String[] args) {
        String abc = "abc";
        changeString(abc);
        System.out.println("Initial object: " + abc); //wont print "def"

        Wrapper w = new Wrapper(abc);
        changeStringWithWrapper(w);
        System.out.println("Updated object: " + w.ref1);
        System.out.println("Out     object: " + w.ref2);
    }

    // This won't work
    public static void changeString(String str) {
        str = "def";
    }

    // This will work
    public static void changeStringWithWrapper(Wrapper w) {
        w.ref1 = "def";
        w.ref2 = "And this should be used as out!";
    }

}

실제 사례

out 매개 변수를 사용하는 AC # .NET 메서드

여기에 out 키워드를 사용 하는 C # .NET 메서드가 있습니다 .

public bool Contains(T value)
{
    BinaryTreeNode<T> parent;
    return FindWithParent(value, out parent) != null;
}

private BinaryTreeNode<T> FindWithParent(T value, out BinaryTreeNode<T> parent)
{
    BinaryTreeNode<T> current = _head;
    parent = null;

    while(current != null)
    {
        int result = current.CompareTo(value);

        if (result > 0)
        {
            parent = current;
            current = current.Left;
        }
        else if (result < 0)
        {
            parent = current;
            current = current.Right;
        }
        else
        {
            break;
        }
    }

    return current;
}

out 매개 변수를 사용하는 C # 코드에 해당하는 Java

그리고 래퍼 클래스 의 도움으로이 메서드에 해당 하는 Java 는 다음과 같습니다.

public boolean contains(T value) {
    BinaryTreeNodeGeneration<T> result = findWithParent(value);

    return (result != null);
}

private BinaryTreeNodeGeneration<T> findWithParent(T value) {
    BinaryTreeNode<T> current = head;
    BinaryTreeNode<T> parent = null;
    BinaryTreeNodeGeneration<T> resultGeneration = new BinaryTreeNodeGeneration<T>();
    resultGeneration.setParentNode(null);

    while(current != null) {
        int result = current.compareTo(value);

        if(result >0) {
            parent = current;
            current = current.left;
        } else if(result < 0) {
            parent = current;
            current = current.right;
        } else {
            break;
        }
    }

    resultGeneration.setChildNode(current);
    resultGeneration.setParentNode(parent);

    return resultGeneration;
}

래퍼 클래스

그리고이 자바 코드에서 사용되는 래퍼 클래스 는 다음과 같습니다.

public class BinaryTreeNodeGeneration<TNode extends Comparable<TNode>>  {

    private BinaryTreeNode<TNode>   parentNode;
    private BinaryTreeNode<TNode>   childNode;

    public BinaryTreeNodeGeneration() {
        this.parentNode = null;
        this.childNode = null;
    }

    public BinaryTreeNode<TNode> getParentNode() {
        return parentNode;
    }

    public void setParentNode(BinaryTreeNode<TNode> parentNode) {
        this.parentNode = parentNode;
    }

    public BinaryTreeNode<TNode> getChildNode() {
        return childNode;
    }

    public void setChildNode(BinaryTreeNode<TNode> childNode) {
        this.childNode = childNode;
    }

}

이전 답변을 참조하십시오.
파슈 테

자세한 답변에 반대표를 던지는 것은 재미 있습니다. 나는 그래서 확인했고 데모 코드로 정확한 답을 찾을 수 없었기 때문에 내가 기억할 수있는 한이 대답을 작성했습니다. 단일 답변을 기다렸다가 다른 모든 답변에 반대 투표를하면 SO는 질문 소유자로부터 확인을받은 답변 이외의 모든 답변을 금지해야합니다.
Levent Divilioglu

네, 답변을 수정해야만 반대표를 삭제할 수 있습니다. 따라서 다른 답변을 읽고 해당 솔루션을 사용하고 싶지 않은 이유를 설명하십시오. 래퍼 (특히 재미를위한 REF 및 OUT 래퍼). 5 명의 사람들이 예를 들어 짧고 완전한 답변을 했으며 Eyal만이 기본적으로 "No you ca n't"라고 썼습니다.
파슈 테

1
이 대답은 괜찮아 보입니다. 최상위 답변과 유사하지만 Java에서 래퍼 클래스를 사용하는 방법에 대한 자세한 예제를 제공합니다.
hubatish

8

Java는 매개 변수를 값으로 전달하며 참조에 의한 전달을 허용하는 메커니즘이 없습니다. 즉, 매개 변수가 전달 될 때마다 해당 이 호출을 처리하는 스택 프레임에 복사됩니다.

여기서 사용하는 용어 은 약간의 설명이 필요합니다. 자바에는 두 가지 종류의 변수가 있습니다. 프리미티브와 객체입니다. 프리미티브의 값은 프리미티브 자체이고 객체의 값은 참조 (참조되는 객체의 상태가 아님)입니다. 따라서 메서드 내부의 값을 변경하면 스택의 값 복사본 만 변경되며 호출자에게는 표시되지 않습니다. 예를 들어 실제 스왑 메서드를 구현할 수있는 방법이 없습니다. 두 참조를 받고이를 스왑합니다 (그 내용이 아닙니다!).


6

다른 많은 프로젝트와 마찬가지로 C # 프로젝트를 Java로 변환해야했습니다. 웹에서 outref 수정 자 에 관한 완전한 솔루션을 찾지 못했습니다 . 그러나 나는 내가 찾은 정보를 가지고 그것을 확장하여 요구 사항을 충족시키기 위해 나만의 수업을 만들 수있었습니다. 코드 명확성을 위해 refout 매개 변수를 구분하고 싶었습니다 . 아래 수업으로 가능합니다. 이 정보가 다른 사람들의 시간과 노력을 절약하기를 바랍니다.

아래 코드에 예제가 포함되어 있습니다.

//*******************************************************************************************
//XOUT CLASS
//*******************************************************************************************
public class XOUT<T>
{
    public XOBJ<T> Obj = null;

    public XOUT(T value)
    {
        Obj = new XOBJ<T>(value);
    }

    public XOUT()
    {
      Obj = new XOBJ<T>();
    }

    public XOUT<T> Out()
    {
        return(this);
    }

    public XREF<T> Ref()
    {
        return(Obj.Ref());
    }
};

//*******************************************************************************************
//XREF CLASS
//*******************************************************************************************

public class XREF<T>
{
    public XOBJ<T> Obj = null;

    public XREF(T value)
    {
        Obj = new XOBJ<T>(value);
    }

    public XREF()
    {
      Obj = new XOBJ<T>();
    }

    public XOUT<T> Out()
    {
        return(Obj.Out());
    }

    public XREF<T> Ref()
    {
        return(this);
    }
};

//*******************************************************************************************
//XOBJ CLASS
//*******************************************************************************************
/**
 *
 * @author jsimms
 */
/*
    XOBJ is the base object that houses the value. XREF and XOUT are classes that
    internally use XOBJ. The classes XOBJ, XREF, and XOUT have methods that allow
    the object to be used as XREF or XOUT parameter; This is important, because
    objects of these types are interchangeable.

    See Method:
       XXX.Ref()
       XXX.Out()

    The below example shows how to use XOBJ, XREF, and XOUT;
    //
    // Reference parameter example
    //
    void AddToTotal(int a, XREF<Integer> Total)
    {
       Total.Obj.Value += a;
    }

    //
    // out parameter example
    //
    void Add(int a, int b, XOUT<Integer> ParmOut)
    {
       ParmOut.Obj.Value = a+b;
    }

    //
    // XOBJ example
    //
    int XObjTest()
    {
       XOBJ<Integer> Total = new XOBJ<>(0);
       Add(1, 2, Total.Out());    // Example of using out parameter
       AddToTotal(1,Total.Ref()); // Example of using ref parameter
       return(Total.Value);
    }
*/


public class XOBJ<T> {

    public T Value;

    public  XOBJ() {

    }

    public XOBJ(T value) {
        this.Value = value;
    }

    //
    // Method: Ref()
    // Purpose: returns a Reference Parameter object using the XOBJ value
    //
    public XREF<T> Ref()
    {
        XREF<T> ref = new XREF<T>();
        ref.Obj = this;
        return(ref);
    }

    //
    // Method: Out()
    // Purpose: returns an Out Parameter Object using the XOBJ value
    //
    public XOUT<T> Out()
    {
        XOUT<T> out = new XOUT<T>();
        out.Obj = this;
        return(out);
    }

    //
    // Method get()
    // Purpose: returns the value
    // Note: Because this is combersome to edit in the code,
    // the Value object has been made public
    //
    public T get() {
        return Value;
    }

    //
    // Method get()
    // Purpose: sets the value
    // Note: Because this is combersome to edit in the code,
    // the Value object has been made public
    //
    public void set(T anotherValue) {
        Value = anotherValue;
    }

    @Override
    public String toString() {
        return Value.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return Value.equals(obj);
    }

    @Override
    public int hashCode() {
        return Value.hashCode();
    }
}


-1

자바에는 표준 방식이 없습니다. 대부분의 스왑은 클래스에 포함 된 목록에서 이루어집니다. 그러나 비공식적 인 방법이 있습니다.

package Example;

import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;



 public class Test{


private static <T> void SetValue(T obj,T value){
    try {
        Field f = obj.getClass().getDeclaredField("value");
        f.setAccessible(true);
        f.set(obj,value);
        } catch (IllegalAccessException | IllegalArgumentException | 
            NoSuchFieldException | SecurityException ex) {
            Logger.getLogger(CautrucjavaCanBan.class.getName()).log(Level.SEVERE, 
       null, ex);
        }
}
private  static  void permutation(Integer a,Integer b){
    Integer tmp = new Integer(a);
    SetValue(a, b);
    SetValue(b, tmp);
}
 private  static  void permutation(String a,String b){
    char[] tmp = a.toCharArray();
    SetValue(a, b.toCharArray());
    SetValue(b, tmp);
}
public static void main(String[] args) {
    {
        Integer d = 9;
        Integer e = 8;
        HoanVi(d, e);
        System.out.println(d+" "+ e);
    }
    {
        String d = "tai nguyen";
        String e = "Thai nguyen";
        permutation(d, e);
        System.out.println(d+" "+ e);
    }
}

}

1
그것은 매개 변수에 대한 참조 의미를 제공하지 않습니다. 그것은 단지 리플렉션을 사용하여 변경 불가능하도록 설계된 객체를 변경하는 것입니다. 이는 끔찍한 아이디어이며 여전히 매개 변수에 대한 참조 의미를 제공하지 않습니다.
Servy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.