Java有像C#的ref和out关键字吗?

dev*_*ium 106 c# java

类似于以下内容:

参考示例:

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

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

例子:

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

void main() {
    String abc;
    changeString(out abc);
    System.out.println(abc); //prints "def"
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 93

不,Java没有像C#refout关键字那样通过引用传递.

您只能通过Java传递值.甚至引用都是按值传递的.有关更多详细信息,请参阅Jon Skeet关于Java中参数传递的页面.

要做类似的事情,ref或者out你必须将参数包装在另一个对象中,并将该对象引用作为参数传递.

  • 这不是100%为真,如果传入数组或类,则按值传入对数组或对象的引用,您可以将内部更改为数组或对象,它将反映在调用者中. (13认同)
  • @fearofawhackplanet:嗯,除非你使用`ref`. (12认同)
  • 这应该扩展到一些.您只能将原语(int,short,char等)作为值传递.不,没有出局. (5认同)
  • 从CLR的角度来看,你是按值传递托管引用(`T&`),是的.但是C#有自己的术语,它特别不包括类型`ref T`的值 - 来自C#透视图,`ref`严格来说是一个参数修饰符,并且说的是"按值传递引用"它没有意义. (5认同)
  • @fearofawhackplanet:`参考参数需要ref修饰符的声明和调用两个部分 - 这意味着它的总是很清楚,当你路过的东西通过reference.` http://www.yoda.arachsys.com/csharp/parameters html的 (2认同)

Osc*_*Ryz 26

直接回答:没有

但您可以使用包装器模拟引用.

并执行以下操作:

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

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

退房

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

基本上任何其他类型,如:

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

out.println( one ); // May print 2
Run Code Online (Sandbox Code Playgroud)

  • 我从来没有说过,*你可以用这种优雅的方式做到这一点*:P (41认同)
  • 哎哟.那很难看. (26认同)
  • @ user311130您的代码很难阅读,但您可以创建一个新问题,例如:"我找到了这个答案<链接到我的答案>但是以下内容不起作用<您的代码在这里> (3认同)

Eya*_*der 7

Java按值传递参数,并且没有任何允许传递引用的机制.这意味着无论何时传递参数,其值都会被复制到处理调用的堆栈帧中.

我在这里使用的术语需要一点澄清.在Java中,我们有两种变量 - 基元和对象.基元的值是基元本身,对象的值是其引用(而不是被引用对象的状态).因此,对方法内部值的任何更改都只会更改堆栈中值的副本,并且调用者不会看到它.例如,没有任何方法可以实现真正的交换方法,它接收两个引用并交换它们(而不是它们的内容!).


Lev*_*glu 7

实际上,就我所知,Java语言中既没有ref也没有out关键字等价物.但是,我刚刚将C#代码转换为使用out参数的Java,并将建议我刚刚完成的工作.您应该将任何对象包装到包装器类中,并传递包装器对象实例中包含的值,如下所示;

使用包装器的一个简单示例

这是包装类 ;

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

    public Wrapper(Object ref1) {
        this.ref1 = ref1;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试代码;

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!";
    }

}
Run Code Online (Sandbox Code Playgroud)

真实世界的例子

使用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;
}
Run Code Online (Sandbox Code Playgroud)

Java等效的使用out参数的C#代码

包装类的帮助下,这个方法的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;
}
Run Code Online (Sandbox Code Playgroud)

包装类

此Java代码中使用的包装类如下所示;

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;
    }

}
Run Code Online (Sandbox Code Playgroud)


Jam*_*mms 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();
    }
}
Run Code Online (Sandbox Code Playgroud)