如何在Java中模拟引用传递?

发布于 2024-12-11 20:54:05 字数 361 浏览 0 评论 0原文

我是一个十足的 Java 菜鸟。我知道 Java 将所有参数视为按值传递,并且还有其他几个线程人们对此进行了解释。

例如,在 C++ 中我可以这样做:

void makeAThree(int &n)
{
   n = 3;
}
int main()
{
   int myInt = 4;
   makeAThree(myInt);
   cout << myInt;
}

它将输出 3。我知道在 Java 中,所有参数都是按值传递的,因此您无法操作传入的参数。是否有标准方法来模拟 Java 中通过引用传递?有没有办法调用一个函数来操作传入的变量?我很难接受没有办法做到这一点的想法。

I'm a complete Java noob. I know that Java treats all parameters as pass by value and there are several other threads where people explain this.

For example, in C++ I can do:

void makeAThree(int &n)
{
   n = 3;
}
int main()
{
   int myInt = 4;
   makeAThree(myInt);
   cout << myInt;
}

Which will output 3. I know that in Java, all parameters are passed by value and thus you can not manipulate the parameter passed in. Is there a standard way to simulate pass by reference in Java? Is there no way to call a function that manipulates a variable passed in? It's tough for me to wrap my head around the idea of there being no way to do this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

迷雾森÷林ヴ 2024-12-18 20:54:05

模拟传递引用的主要方法是传递保存该值的容器。

static void makeAThree(Reference<Integer> ref)
{
   ref.set(3);
}

public static void main(String[] args)
{
  Reference<Integer> myInt = new Reference<>(4);
  makeAThree(myInt);
  System.out.println(myInt.get());
}

由于在 Java 中,它是对按值传递的对象的引用(对象本身根本不会传递),因此将 ref 设置为 3 makeAThree 中的内容更改了 main()myInt 引用的同一对象。

免责声明:Reference 不是一个可以直接与开箱即用的 Java 一起使用的类。我在这里使用它作为任何其他对象类型的占位符。这是一个非常简单的实现:

public class Reference<T> {
    private T referent;

    public Reference(T initialValue) {
       referent = initialValue;
    }

    public void set(T newVal) {
       referent = newVal;
    }

    public T get() {
       return referent;
    }
}

编辑

这并不是说修改方法的参数是很好的做法。通常这会被认为是副作用。通常,最佳实践是将方法的输出限制为返回值和 this(如果该方法是实例方法)。修改参数是一种非常“C”的方法设计方式,不能很好地映射到面向对象编程。

The primary way you can simulate passing a reference is to pass a container that holds the value.

static void makeAThree(Reference<Integer> ref)
{
   ref.set(3);
}

public static void main(String[] args)
{
  Reference<Integer> myInt = new Reference<>(4);
  makeAThree(myInt);
  System.out.println(myInt.get());
}

Since in Java, it is references to objects that are passed by value (the object itself is never passed at all), setting ref to 3 in makeAThree changes the same object referred to by myInt in main().

Disclaimer: Reference isn't a class you can just use with out-of-the-box Java. I'm using it here as a placeholder for any other object type. Here's a very simple implementation:

public class Reference<T> {
    private T referent;

    public Reference(T initialValue) {
       referent = initialValue;
    }

    public void set(T newVal) {
       referent = newVal;
    }

    public T get() {
       return referent;
    }
}

Edit

That's not to say it's great practice to modify the arguments to your method. Often this would be considered a side-effect. Usually it is best practice to limit the outputs of your method to the return value and this (if the method is an instance method). Modifying an argument is a very "C" way of designing a method and doesn't map well to object-oriented programming.

一桥轻雨一伞开 2024-12-18 20:54:05

您可以使用大小为 1 的数组

You can use an array of size 1

断爱 2024-12-18 20:54:05

Java按值传递所有内容,如果它是一个对象,那么传递的是该对象的引用值。就像,

void someMethod()
{
   int value = 4;
   changeInt(value);
   System.out.printlin(value); 
}

public void changeInt(int x)
{
   x = x + 1;
}

上面的代码将打印 4,因为它是按值传递的

class SomeClass
    {
       int x;
    }

void someMethod()
    {
       SomeClass value = new SomeClass();
       value.x = 4;
       changeCls(value);
       System.out.printlin(value.x); 
    }

    public void changeCls(SomeClass cls)
    {
        cls = new SomeClass();
        cls.x = 5;
    }

上面的代码仍然会打印 4,因为对象是按值传递的,并且对对象的引用在这里传递,即使它在方法内部发生了更改,也不会反映到方法“someMethod”。

class SomeClass
{
   int x;
}

void someMethod()
    {
       SomeClass value = new SomeClass();
       value.x = 4;
       changeCls(value);
       System.out.printlin(value.x); 
    }

    public void changeCls(SomeClass cls)
    {
        cls.x = cls.x + 1;
    }

这里它也是按值传递对象,并且该值将是对该对象的引用。因此,当您更改该对象的某些字段时,它将反映到引用该对象的所有位置。因此它会打印 5。所以这可以是你可以用来做你想做的事情的方式。将值封装在对象中并将其传递给要更改它的方法。

Java pass everything by value, if it's an object then what would be passed is the reference value of the object. It's like,

void someMethod()
{
   int value = 4;
   changeInt(value);
   System.out.printlin(value); 
}

public void changeInt(int x)
{
   x = x + 1;
}

above code will print 4, because it's passed by value

class SomeClass
    {
       int x;
    }

void someMethod()
    {
       SomeClass value = new SomeClass();
       value.x = 4;
       changeCls(value);
       System.out.printlin(value.x); 
    }

    public void changeCls(SomeClass cls)
    {
        cls = new SomeClass();
        cls.x = 5;
    }

Above code will still print 4, because the object is passed by value and the reference to the object is passed here, even it's changed inside the method it won't reflect to the method 'someMethod'.

class SomeClass
{
   int x;
}

void someMethod()
    {
       SomeClass value = new SomeClass();
       value.x = 4;
       changeCls(value);
       System.out.printlin(value.x); 
    }

    public void changeCls(SomeClass cls)
    {
        cls.x = cls.x + 1;
    }

here also it passes the object by value, and this value will be the reference to the object. So when you change some field of this object it will reflect to the all the places where the object is referred. Hence it would print 5. So this can be the way you can use to do what you want. Encapsulate the value in an object and pass it to the method where you want to change it.

独夜无伴 2024-12-18 20:54:05

Java 是按值传递,意思是按复制传递。我们不能像 C++ 中那样对引用变量进行算术运算。简而言之,Java 不是 C/C++。
因此,作为解决方法,您可以这样做:

public static void main (String [] args) {
    int myInt = 4;
    myInt = makeAThree(myInt);

}
static int makeAThree(int n)
{
   return n = 3;
}

PS 只是将方法设为静态,以便在没有类对象的情况下使用它。没有其他意图。 ;)

这会让你更好地理解。

Java is pass-by-value that mean pass-by-copy. We cannot do arithmetic on a reference variable as in C++. In-short Java is not C/C++.
So as a workaround you can do this:

public static void main (String [] args) {
    int myInt = 4;
    myInt = makeAThree(myInt);

}
static int makeAThree(int n)
{
   return n = 3;
}

P.S. Just made the method static so as to use it without class object. No other intention. ;)

This will make you understand better.

为人所爱 2024-12-18 20:54:05

我运行了上面的一些不同场景。

是的,如果您想更改函数外部的值而不返回相同的原语,则必须向其传递该原语的单个单位数组。然而,在 Java 中,数组都是内部对象。请注意,如果您按名称将“值”传递给 println(),则不会出现编译错误,并且由于内部的 toString() 本机,它会打印哈希值。数组类。您会注意到这些名称在打印时会发生变化(将其放入长循环中并观察)。遗憾的是,Java 还没有意识到,由于某些原因,我们希望有一个受保护但物理上静态的地址空间可供我们使用。但这会损害 Java 的安全机制。事实上,我们不能依赖已知的地址,这意味着攻击它更困难。 Java 性能非常出色,因为我们拥有快速的处理器。如果您需要更快或更小,那就适用于其他语言。早在 1999 年,我就记得这一点,当时我在 Dobbs 上读到一篇关于这个论点的文章。由于它是一种网络感知语言,旨在在线运行,因此这是对安全性的一个重大设计让步。 1999 年的 PC 具有 64mb 到 256mb 的 RAM,运行频率约为 800mhz
如今,您的移动设备的内存是原来的 2 到 8 倍,速度更快 200-700mhz,每次运行的操作次数也更多,而 Java 是 Android 的首选语言,Android 是销量占主导地位的操作系统(iOS 仍然很强大,我必须学习 Objective我猜有一天 C 会讨厌我所见过的语法)。

如果您将 int[] 而不是 int 传递给此代码,您会从调用它的 someMethod() 返回 5


public void changeInt(int x)
{
   x = x + 1;
} 

public void changeInt(int[] x)
{
   x[0] += 1; 

}

这是上面的一个令人困惑的选择。如果作者没有通过声明同名的局部变量来隐藏传递的变量,则代码将起作用。当然,这是行不通的,为了清楚起见,请忽略上面引用的以下示例。


  public void changeCls(SomeClass cls)
   {
       cls = new SomeClass();
       cls.x = 5;
   }

上面的代码仍然会打印4,因为传递的对象被本地声明隐藏在范围之外。另外,这是在一个方法内部,所以我认为即使调用 this 和 super 也无法正确澄清它。


如果它没有在方法本地隐藏,那么它会更改外部传递的对象的值。

I ran some of the various scenarios above.

Yes, if you wanted to change a value outside of the function without returning the same primitive, you'd have to pass it a single unit array of that primitive. HOWEVER, in Java, Array's are all internal objects. You please note that if you pass 'value' by name to the println() there is no compile error and it prints hashes because of the toString() native to the internal array class. You will note that those names change as they print (put it in a long loop and watch). Sadly, Java hasn't gotten the idea that we WOULD like a protected yet physically static address space available to us for certain reasons. It would hurt Java's security mechanisms though. The fact that we can't depend on known addresses means that it's harder to hack at that. Java performance is fantastic because we have fast processors. If you need faster or smaller, that's for other languages. I remember this from way back when in 1999 reading an article in Dobbs just about this argument. Since it's a web aware language meant to function online, this was a big design concession to security. Your PC in 1999 had 64mb to 256mb of RAM and ran around 800mhz
Today, your mobile device has 2 to 8 times that ram and is 200-700mhz faster and does WAY more ops per tick, and Java is the preferred language for Android, the dominant OS by unit sales (iOS still rocks, i gotta learn Objective C someday i guess, hate the syntax i've seen though).

If you passed int[] instead of int to this code you get 5 back from someMethod() calling it.


public void changeInt(int x)
{
   x = x + 1;
} 

public void changeInt(int[] x)
{
   x[0] += 1; 

}

This is a confusing selection from above. The code WOULD work if the author hadn't hidden the passed variable by declaring a local variable of the same name. OFCOURSE this isn't going to work, ignore the following example cited from above for clarity.


  public void changeCls(SomeClass cls)
   {
       cls = new SomeClass();
       cls.x = 5;
   }

Above code will still print 4, because the passed object is HIDDEN FROM SCOPE by the local declaration. Also, this is inside a method, so I think even calling this and super wouldn't clarify it properly.


If it weren't hidden locally in the method, then it would have changed the value of the object passed externally.

壹場煙雨 2024-12-18 20:54:05

要完成方法中基元变量的更改,有 2 个基本选项:

1) 如果您想在不同方法中更改基元上的值,您可以将基元包装在“java bean”对象中,这本质上就像一个指针。

或者

2)您可以使用 AtomicInteger/AtomicLong 类,它们用于并发,当许多线程可能需要修改变量时......因此变量必须具有一致的状态。这些类为您包装原语。

警告:从可维护性的角度来看,您通常最好返回新值,而不是在方法内部设置/编辑它。

To accomplish the changing of a primitive variable in a method there are 2 basic options :

1) If you want to change values on a primitive in a different method you can wrap the primitive in a "java bean" object, which will be essentially like a pointer.

Or

2) You can use an AtomicInteger/AtomicLong class which are used to concurrency, when many threads might need to modify a variable....so the variables has to have state that is consistent. Theses classes wrap primitives for you.

Warning : you are usually better off returning the new value, rather than setting/editting it internally in a method, from a maintainability standpoint ..

小猫一只 2024-12-18 20:54:05

实现模拟按引用传递的一种快速方法是将参数移动到封闭类的成员变量

尽管有多种方法可以做到这一点,例如使用类或数组包装器或将它们移至函数返回类型,但代码可能并不干净。如果你像我一样,之所以会问这样的问题,是因为一段Java代码已经用C++方式编码了(这是行不通的),需要快速修复。例如,在深度优先搜索等递归程序中,我们可能需要在 C++ 递归函数的参数列表中保留多个变量,例如搜索路径、搜索是否应该结束的标志。如果遇到这种情况,最快的解决方法是将这些参数变量变成类成员变量。不过,请注意变量的生命周期,并在必要时重置它们的值。

One quick way to achieving simulate passing by reference is to move the arguments to member variables of the enclosing class.

Although there are multiple ways to do it such as using a class or array wrapper or moving them to the function return type, the code may not turn out clean. If you are like me, the reason to ask such a question is that a piece of Java code has already been coded in a C++ way (which does not work) and a quick fix is needed. For example, in a recursion program such as depth-first-search, we may need to keep multiple variables in the C++ recursion function's argument list such as search path, flags whether the search should end. If you are in such a situation, the quickest fix is to make these argument variables into class member variables. Take care of the variable life cycle though and reset their values when necessary.

絕版丫頭 2024-12-18 20:54:05

Java 对一切使用值传递。

据我了解,您不确定是否可以修改传入的变量。

当您将对象传递给方法时,如果您在该方法中使用该对象,那么您实际上是在修改该对象。但是,您正在修改该对象的副本,该副本仍然指向同一对象。所以实际上当你将一个对象传递给一个方法时,你可以修改它。

再次强调,java 中的所有内容都是通过 value.period 传递的。

Java uses pass by value for everything.

As far as I understand you are not really sure if you can modify a variable passed in.

When you pass an object to a method, and if you use that object within that method, you are actually modifying that object. However you are modifying that object on a copy of it which still points to the same object. So actually when you pass an object to a method, you can modify it.

Once again, everything in java is pass by value.period.

往昔成烟 2024-12-18 20:54:05

为了方便起见,你可以使用大小为 1 的数组,尽管创建一个新对象也可以。

void helper(int[] arr){
    arr[0] = 4;
}

@overload
void helper(int var){
    var = 8;
}

void my_function(){
    int[] variable = new int[1];
    variable[0] = 5;
    int v = 10;

    helper(variable);
    helper(v);

    System.out.println(variable[0]);
    // print : 4 (modified)
    System.out.println(v);
    // print : 10 (not modified)
}

u can use array of size 1, for ease though creating a new object will also work.

void helper(int[] arr){
    arr[0] = 4;
}

@overload
void helper(int var){
    var = 8;
}

void my_function(){
    int[] variable = new int[1];
    variable[0] = 5;
    int v = 10;

    helper(variable);
    helper(v);

    System.out.println(variable[0]);
    // print : 4 (modified)
    System.out.println(v);
    // print : 10 (not modified)
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文