简体   繁体   English

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

[英]Does Java have something like C#'s ref and out keywords?

Something like the following: 类似于以下内容:

ref example: 参考示例:

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

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

out example: 例子:

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

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

No, Java doesn't have something like C#'s ref and out keywords for passing by reference. 不,Java没有像C#的refout关键字那样通过引用传递。

You can only pass by value in Java. 您只能通过Java传递值。 Even references are passed by value. 甚至引用都是按值传递的。 See Jon Skeet 's page about parameter passing in Java for more details. 有关更多详细信息,请参阅Jon Skeet关于Java中参数传递的页面。

To do something similar to ref or out you would have to wrap your parameters inside another object and pass that object reference in as a parameter. 要执行与refout类似的操作,您必须将参数包装在另一个对象中,并将该对象引用作为参数传递。

Direct answer: No 直接回答:没有

But you can simulate reference with wrappers . 但您可以使用包装器模拟引用

And do the following: 并执行以下操作:

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

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

Out 退房

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

And basically any other type such as: 基本上任何其他类型,如:

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

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

Java passes parameters by value and doesn't have any mechanism to allow pass-by-reference. Java按值传递参数,并且没有任何允许传递引用的机制。 That means that whenever a parameter is passed, its value is copied into the stack frame handling the call. 这意味着无论何时传递参数,其值都会被复制到处理调用的堆栈帧中。

The term value as I use it here needs a little clarification. 我在这里使用的术语需要一点澄清。 In Java we have two kinds of variables - primitives and objects. 在Java中,我们有两种变量 - 基元和对象。 A value of a primitive is the primitive itself, and the value of an object is its reference (and not the state of the object being referenced). 基元的值是基元本身,对象的值是其引用(而不是被引用对象的状态)。 Therefore, any change to the value inside the method will only change the copy of the value in the stack, and will not be seen by the caller. 因此,对方法内部值的任何更改都只会更改堆栈中值的副本,并且调用者不会看到它。 For example, there isn't any way to implement a real swap method, that receives two references and swaps them (not their content!). 例如,没有任何方法可以实现真正的交换方法,它接收两个引用并交换它们(而不是它们的内容!)。

Like many others, I needed to convert a C# project to Java. 像许多其他人一样,我需要将C#项目转换为Java。 I did not find a complete solution on the web regarding out and ref modifiers. 我没有在网上找到关于outref修饰符的完整解决方案。 But, I was able to take the information I found, and expand upon it to create my own classes to fulfill the requirements. 但是,我能够获取我发现的信息,并扩展它以创建我自己的类来满足要求。 I wanted to make a distinction between ref and out parameters for code clarity. 我想区分refout参数以获得代码清晰度。 With the below classes, it is possible. 通过以下课程,这是可能的。 May this information save others time and effort. 愿这些信息可以节省他人的时间和精力。

An example is included in the code below. 下面的代码中包含一个示例。

//*******************************************************************************************
//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();
    }
}

Actually there is neither ref nor out keyword equivalent in Java language as far as I know. 实际上,就我所知, Java语言中既没有ref也没有out关键字等价物。 However I've just transformed a C# code into Java that uses out parameter and will advise what I've just done. 但是,我刚刚将C#代码转换为使用out参数的Java ,并将建议我刚刚完成的工作。 You should wrap whatever object into a wrapper class and pass the values wrapped in wrapper object instance as follows; 您应该将任何对象包装到包装器类中,并传递包装器对象实例中包含的值,如下所示;

A Simple Example For Using Wrapper 使用包装器的一个简单示例

Here is the Wrapper Class ; 这是包装类 ;

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

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

And here is the test code; 这是测试代码;

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

}

A Real World Example 真实世界的例子

AC#.NET method using out parameter 使用out参数的AC#.NET方法

Here there is a C#.NET method that is using out keyword; 这里有一个使用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;
}

Java Equivalent of the C# code that is using the out parameter Java等效的使用out参数的C#代码

And the Java equivalent of this method with the help of wrapper class is as follows; 包装类的帮助下,这个方法的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;
}

Wrapper Class 包装类

And the wrapper class used in this Java code is as below; 此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;
    }

}

Three solutions not officially, explicitly mentioned: 三个解决方案未正式明确提及:

ArrayList<String> doThings() {
  //
}

void doThings(ArrayList<String> list) {
  //
}

Pair<String, String> doThings() {
  //
}

For Pair, I would recommend: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html 对于Pair,我建议: https//commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

java has no standard way of doing it. java没有标准的方法。 Most swaps will be made on the list that is packaged in the class. 大多数交换都将在类中打包的列表中生成。 but there is an unofficial way to do it: 但是有一种非官方的方式可以做到:

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM