我对Java相对较新,在尝试使用某些代码时遇到了令我惊讶的事情。希望有人能够对此有所了解。这是与我的问题相关的一些代码片段。那些阅读过编程实践的人可能会觉得这很熟悉。
此函数是为List数据类型定义的,并将传递的“fn”参数(只是包装在对象中的函数)应用于列表的所有成员。
public void apply(MapFunctionI fn, Object fnArg) {
Node curr = head;
for (; curr != null; curr = curr.getNext()){
fn.function(curr.getItem(), fnArg);
}
}
接下来,我尝试使用这个函数来计算列表中元素的数量,使用一个实现MapFunctionI的类(一个需要一个名为'function'的方法的接口)
class CounterFunction implements MapFunctionI {
public void function(Object node, Object arg){
((MyInteger)arg).increment();
}
}
以下是我称之为的方式。
static void TestApply(LinkedList l){
System.out.println("Number of elements in List -> ");
MyInteger n = new MyInteger(0);
l.apply(new CounterFunction(),n);
System.out.println(n.value());
}
这是MyInteger类型。
class MyInteger {
private int n;
MyInteger(int i){
n = i;
}
public void increment(){
n++;
}
public int value(){
return n;
}
现在,如果您想知道我为什么使用自己的Integer类型,那就是我的问题。我尝试使用Java Integer类型,但我无法使其工作,打印的答案始终为O,“整数”的值不会在多个调用中持续存在。这就是我这样做的方式,
arg = ((Integer)arg).intValue() + 1;
是什么解释了这种行为?
我相信有一个更简洁的方式提出这个问题: - )
答案 0 :(得分:6)
第一个问题是类型Integer
是不可变的;一旦使用某个整数值创建,该值就无法更改。所以你不能直接改变一个整数(我不是说你不知道这个或试过)。
下一个问题是传递给函数的是对该Integer的引用。您可以在函数内部将该引用更改为指向不同值的Integer,但是函数内部更改的引用永远不会传递回调用函数,因此其值与此无关。
您的自制类的工作原因是您现在正在更改对象的内部内容而不仅仅是对它的引用。
表示在函数内部和外部存在完全相同的对象,因此当您在内部进行更改时,确实会看到更改。答案 1 :(得分:2)
使用Integer
类型时它不起作用的原因是因为您正在更新arg
内function()
指针的本地副本。在Java中,所有非基元都是“引用类型”,所有函数参数都是按值传递的。
编辑 - 如果最后一个语句令人困惑,想象一下你是否正在使用C ++方言,它只允许你按值传递引用(即你只能传递指针的副本),并且您想要实现swap
功能。不可能,对吧?更新本地指针不会影响传递给函数的指针。
答案 2 :(得分:2)
首先,Java的Integer
类是不可变的;它只代表一个整数值。当你在它上面调用intValue()
时,它只是返回整数的当前(不可变)值。
当您将(未装箱和重新装箱)增量值分配给arg
时,arg
只是对传入内容的本地引用(就像C中函数内的指针值一样) 。设置为某个东西,然后从该函数返回会丢失刚刚给出的新值。
如果您使用的是C / C ++,那么您可以使用指向指针的指针。但Java没有相应的构造,所以你自己处理它 - 像你使用的包装器对象是你问题的合理解决方案。
答案 3 :(得分:1)
这是因为在Java参数传递中是BY VALUE。 请注意,当您将对象传递给函数时,您传递BY VALUE其引用...或者,以另一种方式说,您按值传递其地址。
当你写:
arg = .... // a new Integer Object
你在函数中本地更改了arg引用的值(指向新对象),而保存在List.apply函数中的fnArg变量中的引用仍然是相同的(因此指向同一个Integer) (0))。
如果您了解C ++,那么您在具有int *或int *&的函数中所具有的差异是相同的。作为参数:在Java中,它就像拥有int *(用于对象)。
答案 4 :(得分:0)
最后一个代码部分的问题是arg
变量只保存对Integer
类的引用。将arg
设置为某个值时,其值将在本地上下文中替换为新对象,并且不会更新已存在的对象。您必须指定要更新的引用的完整路径。