C++参考和Java参考

pan*_*ajt 11 c++ java

// C++示例

#include <iostream>
using namespace std;

int doHello (std::string&);
int main() {
    std::string str1 = "perry";
    cout << "String=" << str1 << endl;
    doHello(str1);
    cout << "String=" << str1 << endl; // prints pieterson
    return 0;
}

int doHello(std::string& str){
    str = "pieterson";
    cout << "String=" << str << endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,正如预期的那样,当修改str引用时,字符串'str1'引用被修改

// Java示例

public class hello {

    public static void main(String args[]){
        String str1 = "perry";
        System.out.println("String=" + str1);
        doHello(str1);
        System.out.println("String=" + str1); // does not prints pieterson
    }

    public static void doHello(String str){
        str = "pieterson";
        System.out.println("String = " + str);
    }
}
Run Code Online (Sandbox Code Playgroud)

在Java中,String str和String str1是最初引用相同String的两个不同对象,因此当我们在doHello()中更改str引用时,str1引用不会更改.

我们如何使用字符串,集合(如List,Vectors,其他对象)在Java中实现C++样式功能.

更新:

感谢Jon的精彩解释,我相信任何Java初学者肯定都会遇到这个问题.让我解释一下使用列表时遇到的问题.

//bad doHello() 

void doHello(List inputList) { 
    inputList = getListFromAnyFunction(); // wrong, didnt work 
} 

// good doHello 

void doHello(List inputList) { 
    inputList.addAll(getListFromAnyFunction()); // worked 
}
Run Code Online (Sandbox Code Playgroud)

感谢Powell和Harshath的解释和代码示例.

Jon*_*eet 13

Java根本没有通过引用传递(您在C++代码中使用).引用按值传递.(它们的值strstr1根本不是对象,它们是引用 - 它确实有助于保持两个概念非常分离.)

通常,如果需要,您将使用返回值返回新引用:

str1 = doHello(str1);
Run Code Online (Sandbox Code Playgroud)

请注意,String与List等略有不同,因为字符串是不可变的.要修改集合(以及任何可变集合),您不需要创建新集合,只需通过原始引用修改对象:

public static void addHello(List<String> items)
{
    items.add("Hello");
}
Run Code Online (Sandbox Code Playgroud)

你可以这样调用它:

List<String> list = new ArrayList<String>();
addHello(list);
System.out.println(list.get(0)); // "Hello"
Run Code Online (Sandbox Code Playgroud)

改变现有对象和改变变量值以引用不同对象之间的区别是至关重要的.如果您想单独保留现有集合并创建一个新集合,则必须明确地执行此操作:

public static List<String> withHello(List<String> items)
{
    List<String> newList = new ArrayList<String>(items);
    newList.add("Hello");
    return newList;
}
Run Code Online (Sandbox Code Playgroud)

然后你会这样称呼它:

List<String> empty = new ArrayList<String>();
List<String> newList = withHello(empty);
System.out.println(empty.size()); // Prints 0
System.out.println(newList.size()); // Prints 1
Run Code Online (Sandbox Code Playgroud)

这回答了你需要的一切吗?

  • 我在这里不同意克里斯.引用类型表达式的值是引用,该引用通过值*传递给方法.这当然可以实现为指针(在这种情况下,它通过逐个指针传递,这仍然不同于逐个传递对象)."NullPointerException"类基本上不幸被命名.声称Java通过引用传递对象在过去引起了很大的混乱.知道"通过引用"真正含义的人然后希望能够编写"交换"方法等. (11认同)
  • 请参阅http://javadude.com/articles/passbyvalue.htm以及更多Stack Overflow问题和答案以获取更多信息:) (3认同)
  • (特别是,我要说Java很难声称Java在第8.4.1节中使用了pass-by-reference,如上面链接的文章中所引用的:当调用方法或构造函数时(第15.12节),实际参数表达式的值初始化新创建的参数变量[...]"请参阅说"实际参数表达式的值初始化新创建的参数变量的位"?这基本上是传值的定义:评估表达式,传递值. (2认同)

Ste*_*ell 13

参数传递,按引用调用和按值调用(简答)

在C++中,有两个参数传递形式,按值调用按引用调用.(call-by-value更好的名字是call-by-new-L-value,但我离题了.)

在Java程序中,所有参数都按值传递.[有些人认为Java通过引用传递对象,但它们是错误的 - 请参阅下面的长答案 - Java传递 Objects 的引用值,但这根本不是一回事.

Java Object 的(以及传递的内容)是指向对象的指针(令人困惑,但准确地称为对象的引用),并调用Java对象方法,例如obj.meth(),取消引用指针obj在调用那里找到的对象的方法之前.

在C++中,同样的调用看起来像:obj->meth().

如果你操作对象(例如,通过调用它上面的方法)作为参数传递给Java中的方法,这可能会修改对象,如果调用者仍然有一个包含该对象的变量,它可以看到这些更改.如果仅分配给(本地)参数变量,则只需更新存储在局部变量中的指针 - 对象不受影响,调用者不会注意到这一点.

因此,对您的问题的简短回答是Java按值传递,并且Java中没有C++的call-by-reference机制.

参数,变量和按值调用(长答案)

要了解这里发生了什么,我们需要了解变量和参数传递的机制.

变量

一般而言,编程语言中的变量是与值相关联的标识符.表示在运行时操作的值的变量(我们在这里忽略宏变量,"编译掉"的常量,等等)必须有两个与之关联的值.这是一个解释原因的例子:

int a = 0;
a = a + 1;
Run Code Online (Sandbox Code Playgroud)

a是变量,在行中a = a + 1;它被引用两次.一次,(在右手侧=)的值0是指,一旦,(在左手侧=)的位置的值的a意思(即,的整数值,其中 a 被存储).只有访问该位置,程序才能更新其中包含的值.

与变量关联的这两个值称为R值L值.(这些名字是由Christopher Strachey发明的;我是粉丝.)语言中的其他结构根据上下文指代这些值中的一个或另一个.例如:

a[x-1] = x;
Run Code Online (Sandbox Code Playgroud)

指的是x两次的R值(即使一个在左侧=),但只是L值a(或阵列的至少一个元素a).

在大多数编程语言中,我们明确地操纵变量的R值,并让编译器(从程序的形式)自动管理L值.我们必须对它们有所了解(在C中,特别是对于数组,我们假设很多关于L值),但大多数时候我们不必知道机制.

按价值呼叫

看看这个电话:

int p=1;
obj.meth(p);
…
void meth(int a) {…a…}
Run Code Online (Sandbox Code Playgroud)

这里的参数会发生什么变化?首先p计算R值,然后,当meth"输入"时,a构造一个新变量.它被赋予一个新的L值(这个位置通常在某种堆栈上),并且参数的R值存储在该位置.

现在,当它a出现meth时具有相同的R值p(最初)和新的L值.对aR值的改变对变量没有影响p.这称为按值调用(更合适的是,按新L调用值).

通过引用打电话

看看这个C++调用:

int p=1;
obj.meth(p);
…
void meth(int& a) {…a…}
Run Code Online (Sandbox Code Playgroud)

这里p计算参数的L值,并且当a构造变量时,它"给予" L 相同的 L值p.然后a在身体的任何使用meth就像一个使用p.例如,赋值将改变存储的值p以及(显然)值a.

Java不会这样做.