假设这是 C++ 代码:
void change(int& x){
x++;
}
或者
void change2(int* a){
*a++;
}
两者都会改变全局 x,对吧?
那么我怎么能在java中做这样的事情呢?
具体来说,我想指向一个 Vector 对象
但由于 Java 没有指针,我不知道该怎么做。
通过搜索互联网,我看到人们说 Java 以其他方式做到这一点,但我没有找到任何真实的例子。
感谢帮助!
在 Java 中,不是指针,而是对对象的引用。您不能通过引用传递原始类型,但可以将原始类型包装在对象中,然后传递对该对象的引用。
Java 提供了Integer
wraps的类型int
,但是这种类型是不可变的,因此您无法在构造后更改其值。但是,您可以MutableInt
从 Apache Commons 使用:
void change(MutableInt x) {
x.increment();
}
对 x 的更改将对调用者可见。
具体来说,我想指向一个 Vector 对象
当您编写时,您正在为变量Vector v = ...;
分配对向量的引用v
。Java 中的引用与指针非常相似。引用实际上是在内部使用指针实现的。
Java 使用按值传递。将向量传递给方法时,实际上是在复制对该向量的引用。它不会克隆载体本身。因此,在 Java 中传递引用与在 C++ 中传递指针非常相似。
使用 Java,您不能像int
通过引用一样传递原始类型,它们只能通过值传递。
您唯一能做的就是找到技巧来做到这一点,因为它Objects
是通过引用传递的。这里举两个例子。
使用单值数组,像这样
int[] value = new int[1];
value[0] = 2;
// call a method
obj.setValue(value);
// and in setValue
public void setValue(int[] value) {
value[0] = 5;
}
或者第二种方法使用持有者类:
public class Holder<T> {
public T value;
public Holder(T value) {
this.value = value;
}
}
// then use it in this way
Holder<Integer> h = new Holder<Integer>(2);
obj.setValue(h);
// and in setValue
public void setValue(Holder<Integer> h) {
h.value = 5;
}
在这种情况下,我使用带有泛型的持有者类实现,但您也可以有一个简单的持有者,仅适用于整数。例如:
public class IntHolder {
public int value;
public IntHolder(int value) {
this.value = value;
}
}
Java 总是按值传递,并且没有 C++ 意义上的全局变量。因此,如果您想在 C++ 中执行相同的操作,则需要返回新值。
因此:
public int change(int x) {
return ++x;
// or
// return x + 1;
}
要测试它:
int x = 2;
change(x);
System.out.println(x); // returns 2
x = change(x);
System.out.println(x); // returns 3
所以让方法被调用没有任何意义,change
按照calculateThisInt
.
Java 确实按值传递对象。但正如Mark Byers提到的,Integer类是不可变的,您可以MutableInt
从 Apache Commons 库中使用。为了描述它是如何工作的,您可以自己为您的示例实现它:
public class MyInt() {
public int i;
public void setInt(int i) {
this.i = i;
}
public int getInt() {
return this.i;
}
public int increment() {
this.i++;
}
}
您需要更改change
函数以将上述MyInt
对象作为参数:
public void change(MyInt i) {
i.increment();
}
用法:
MyInt x = new MyInt();
x.setInt(2);
change(x);
System.out.println(x.getInt); // returns 3
在您的情况下,您想更改Vector对象...
public void changeVector(Vector v) {
// anything you do with 'v' will change it even
// for the scope that called this method
}
// Usage:
Vector v = new Vector();
changeVector(v);
// v should be changed after calling change vector method
希望这一切都有意义。
虽然您无法替换已传递给函数的对象,但您可以通过直接更改字段或调用方法来更改其状态。如果您需要类似指向原语的指针,请将其包装在一个对象中。要遵循您的代码,您可以这样做:
public class IntPointer {
public int value;
public IntPointer(int value) {
this.value = value;
}
}
然后在其他地方你可以说:
public static void change(IntPointer ipoint) {
ipoint.value++;
}
public static void main(String[] args) {
IntPointer a = new IntPointer(10);
change(a);
}
这可能看起来有点尴尬,但它并没有像你想象的那样经常出现。我更有可能做这样的事情:
public class ABPair {
private int a = 0;
private int b = 0;
public static void changeA() {
a++;
}
public static void changeB() {
b++;
}
}
所以在其他地方我可以说:
public static void main(String[] args) {
ABPair ab = new ABPair();
if (ACondition) {
ab.changeA();
}
}
换句话说,我的数据往往已经包装在某种对象中,并且我倾向于使用数据对象的方法来调解任何更改。
两者都会改变全局 x,对吧?
那么我怎么能在java中做这样的事情呢?具体来说,我想指向一个 Vector 对象
这个问题有点模糊,但我的印象是你最终想要一个可以保存东西的全局向量?
有很多方法可以做到这一点,但最简单的方法之一是在类中拥有一个静态字段,并使用公共静态方法来访问它。(或者只是一个可以直接访问的公共静态字段,但这在 Java 中确实不是惯用的。)
public class Foo {
private static List<Integer> globalVector = new Vector<Integer>();
public static void add(int number){
globalVector.add(number);
}
// ... plus whatever other accessors to the global list that you need
}
代码中的其他任何地方:
Foo.add(23); // modifies the global vector
(顺便说一句,Vector有点过时了,通常我们现在会使用 ArrayList 代替它。正如 Javadoc 所说,它已经过改造以实现 List 接口,我也在示例中使用了该接口。)
Java 支持它所谓的“引用”。引用的行为很像 C/C++ 类语言中的指针。它们的行为方式与这些语言中的“参考”工作方式不同。
C 中的指针和 Java 中的引用之间的主要区别是:
您不能在 Java 中进行指针运算(即,您不能从 Java 引用中“添加”或“减去”,您只能取消引用它或将其与另一个引用进行比较)。您不能将其转换为不兼容的类型:Java 是强类型安全的,您不能将内存中的字节“重新解释”为其他对象。对于指针的某些用途,这没有真正的影响(例如,链表在两种语言中的工作方式几乎相同),对于其他人来说,差异很大(C 中的数组只是花哨的指针算法,在 Java 中它们的工作方式完全不同)。
所以在某种程度上,Java 引用可以称为“受限指针”。