这可能是任何人提出的最愚蠢的问题,但仅仅是为了好奇,我们可以为作为参数传递的对象赋值。例如
public class ForDemo3 {
int i = 0;
ArrayList cp = new ArrayList();
public ForDemo3() {
int j = 30;
cp.add(j);
cp.add(i);
i = 5;
j = 12;
System.out.println("i = " + i + " & j= " + j);
assignDvalues(i, j);
System.out
.println("After Restoring the values i = " + i + " & j= " + j);
}
public void assignDvalues(Object... obj) {
for (int n = 0; n <= obj.length - 1; n++) {
obj[n] = cp.get(n);
System.out.println("" + obj[n]);
}
}
public static void main(String[] args) {
new ForDemo3();
}
}
我正在尝试在java中开发基于检查点的恢复。 cp
是一个检查点对象,可以存储值。
上面的输出是
i = 5 & j= 12
30
0
After Restoring the values i = 5 & j= 12
编辑
道歉我不是stackoverflow的好用户。我正在研究并行计算的框架。并且将有一个函数savecheckpoint(List l)
,它将用于将列表或数组列表作为检查点存储到DB,另一个函数public object restoreCheckPoint(int i)
将恢复列表。到目前为止,我能够保存检查点,然后将其恢复。但是,如何在不影响用户代码的情况下分配对象或变量的值?如上例所示,我想使用assignDvalues()
恢复值。有没有办法让它成为可能?
答案 0 :(得分:2)
在这种情况下,没有任何可检测的事情发生:对象数组是由编译器隐式创建的,因此您无法访问它。此外,原始int
被自动装箱到不可变的Integer
中,因此通过对象本身的可变性,方法中所做的更改不会对调用者可见。
但是,如果您明确传递数组,则分配将保留:
Object[] args = new Object[] {i, j};
assignDvalues(args);
System.out.println(args[0]+" "+args[1]);
答案 1 :(得分:2)
这将是一个真正的黑客,所以明智地使用它。以下方法使用反射并具有两个局限性。无法处理原始类型(因为自动装箱)并且无法处理初始化为常量的字符串(即不支持String s = "some string"
,但String s = new String("some string")
工作正常)。你也应该使用new Integer(X)
而不是int x
来混淆原始类型(与字符串类似的故事)
在下面的示例中,我将int i
替换为Integer i
,将j
替换为public class Demo2 {
Integer i = 0;
ArrayList cp = new ArrayList();
public Demo2() {
Integer j = 30;
String s = "def";
cp.add(j);
cp.add(i);
cp.add(s);
i = new Integer(5); // you need to use "i = new Integer(5)" instead of "i = 5" because you risk with messing the primitive int 5
j = new Integer(12); // here also you need to use new Integer(12)
s = new String("some string"); // NOTE: don't even try this with s ="some string" because this will lead to unexpected behaviour
//s = "some string" - if you pass string initialized this way you will mess up the string "some string" in jvm string pool
System.out.println("i = " + i + " & j= " + j + " & s= " + s);
assignDvalues(i, j, s);
System.out.println("After Restoring the values i = " + i + " & j= " + j + " & s= " + s);
}
public void assignDvalues(Object... obj) {
try {
for (int n = 0; n <= (obj.length - 1); n++) {
if (obj[n] instanceof Integer) {
Integer curInt = (Integer) obj[n];
Field field = curInt.getClass().getDeclaredField("value"); // Integer stores the real value in private field "value"
field.setAccessible(true);
field.set(curInt, cp.get(n));
System.out.println("" + obj[n]);
} else if (obj[n] instanceof String) {
String curS = (String) obj[n];
Field field = curS.getClass().getDeclaredField("value"); // String stores the text as char sequence in private field "value"
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); // need to reset final flag to override value of String
field.set(curS, ((String) cp.get(n)).toCharArray());
System.out.println("" + obj[n]);
} // else if (obj[n] insteanceOf SomeOtherType) { // you should provide implementation specific for each type/class you want to support with assignDvalues method
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public static void main(String[] args) throws Exception {
new Demo2();
}
}
,因为我说原语不受支持。
用户唯一需要的是使用“Integer”而不是“int”,“Long”而不是“long”等等,并且可能会很痛苦,避免将字符串定义为常量。
{{1}}
答案 2 :(得分:1)
Java支持按值调用。这意味着在调用函数时,对象引用将作为值传递。 但是,如果你有一个vector或ArrayList,那么你可以传递vector或ArrayList对象引用作为函数的参数,比如f(ArrayList a),并且在函数内,你可以将项目插入刚刚传递的vector或arraylist。
答案 3 :(得分:0)
就调用者而言,您无法将传递给方法的对象更改为其他对象。虽然您可以更改传递的对象的状态。
在您的示例中,您尝试为参数数组分配新值将不会影响调用代码。
答案 4 :(得分:0)
不是这种情况。
Java中的参数具有基本类型或是引用。它们通过值传递,这意味着该方法具有其原始类型的每个参数的自己的本地副本,或每个引用的本地副本。如果您的方法分配给参数,则该方法会修改其自己的本地副本,但该分配不会影响调用者将看到的任何内容。但是,如果该方法使用引用来修改另一个对象中的字段,则调用者将看到引用对象中的更改;该方法创建引用的本地副本,但不是对象本身的本地副本。
数组是一个对象,所以如果你有一个数组参数,则传递一个引用;如果该方法使用该引用来修改数组的元素,则调用者将能够看到对数组元素的更改。
vararg参数是一种特殊情况。它作为数组传递,通过引用传递。所以,如果你写
public void assignSomething(Object... obj) {
obj[0] = "abcde";
}
如果你这样称呼它:
Object[] objects = new Object[1];
assignSomething(objects);
System.out.println(objects[0]);
它实际上会打印"abcde"
。但是如果你传递单个参数而不是数组:
Object obj1;
Object obj2;
assignSomething(obj1, obj2);
System.out.println(obj1);
该程序创建一个临时数组,其值是对您传递的对象的引用。然后,该方法将使用新数组替换临时数组(obj[0]
)中的第一个引用,但不会使用数组元素的先前值,即obj1
的引用。因此,即使分配数组元素通常是调用者可以看到的更改,在这种情况下,被分配的元素是“隐藏”数组的一部分,没有人能看到。
所以,不,obj1
不会受到影响 - 在您的示例中,i
和j
同样不会受到影响。
答案 5 :(得分:0)
您只能通过将对象打包到另一个对象来实现此目的。假设您创建了通用包装类:
class ObjectHolder<T> {
private T obj;
private ObjectHolder(T obj) {
this.obj = obj;
}
public static ObjectHolder of(Object o) {
return new ObjectHolder(o);
}
public T getValue() {
return obj;
}
public void setValue(T value) {
obj = value;
}
@Override
public String toString() {
return obj.toString();
}
}
现在您可以使用该包装器重写您的程序:
public class ForDemo3 {
ObjectHolder<Integer> i = ObjectHolder.of(0);
ArrayList cp = new ArrayList();
public ForDemo3() {
ObjectHolder<Integer> j = ObjectHolder.of(30);
cp.add(j.getValue());
cp.add(i.getValue());
i.setValue(5);
j.setValue(12);
System.out.println("i = " + i + " & j= " + j);
assignDvalues(i, j);
System.out.println("After Restoring the values i = " + i + " & j= " + j);
}
public void assignDvalues(ObjectHolder... obj) {
for (int n = 0; n <= (obj.length - 1); n++) {
obj[n].setValue(cp.get(n));
System.out.println("" + obj[n].getValue());
}
}
public static void main(String[] args) {
new ForDemo3();
}
}