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

大致如下:

参考例子:

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"
}
136390 次浏览

不,Java 没有像 C # 的 refout这样的关键字用于通过引用传递。

只能在 Java 中通过值传递。甚至引用也是通过值传递的。有关更多细节,请参阅 Jon Skeet关于 在 Java 中传递参数的页面。

要执行类似于 refout的操作,您必须将参数包装到另一个对象中,并将该对象引用作为参数传递进来。

直接回答: 不

但是你可以模拟 带有包装的参考文献

然后做以下几件事:

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

Java 通过值传递参数,没有任何允许引用传递的机制。这意味着无论何时传递参数,它的 价值都会被复制到处理调用的堆栈帧中。

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

像许多其他人一样,我需要将一个 C # 项目转换成 Java。我没有找到一个完整的解决方案在网上关于 出去裁判修饰。但是,我能够利用我发现的信息,并扩展它来创建我自己的类来满足需求。为了代码清晰,我想对 裁判出去参数进行区分。使用下面的类,这是可能的。希望这些信息能为其他人节省时间和精力。

下面的代码中包含一个示例。

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

事实上,就我所知,爪哇咖啡语言中既没有 裁判关键字,也没有 出去关键字。然而,我刚刚转换了 C # 代码到 爪哇咖啡,使用 出去参数,并将建议我刚才所做的。您应该将任何对象包装到一个包装器类中,并按如下方式传递包装器对象实例中包装的值;

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

这是 包装类;

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 参数的 C # .NET 方法

这里有一个使用 出去关键字的 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 等价物

包装类的帮助下,该方法的 爪哇咖啡等价物如下;

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

包装类

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


}

三个没有正式明确提及的解决方案:

ArrayList<String> doThings() {
//
}


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


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

对于 Pair,我推荐: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

Java 没有标准的做法。大多数交换将在类中打包的列表中进行。但有一种非官方的方式:

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


}