Java Reducer中的ArrayList问题

Java Reducer中的ArrayList问题,java,hadoop,mapreduce,Java,Hadoop,Mapreduce,嗨,我正在reducer中执行一些计算,并试图将数据加载到ArrayList中。当我在代码后期对ArrayList执行get操作时,ArrayList中的所有对象都具有相同的值 public ArrayList<some_class> temp = new ArrayList<some_class>(); //This is global variable @Override public void reduce(Key_class key, Iterator<s

嗨,我正在reducer中执行一些计算,并试图将数据加载到ArrayList中。当我在代码后期对ArrayList执行get操作时,ArrayList中的所有对象都具有相同的值

public ArrayList<some_class> temp = new ArrayList<some_class>();
//This is global variable

@Override
public void reduce(Key_class key, Iterator<some_class> values,
        OutputCollector<Text, Text> output, Reporter reporter)
                throws IOException {
    if(this.output==null){
        this.output=output;
    }

    while(values.hasNext())
    {
                    //if i print here
                    //and do the following values.next().val1
                    //I'm getting the right result
        temp.add(values.next());
    }

    System.out.println(temp.get(0).val1);//Wrong result
}
public ArrayList temp=new ArrayList();
//这是全局变量
@凌驾
public void reduce(Key_类Key、迭代器值、,
OutputCollector输出,报告器(报告器)
抛出IOException{
if(this.output==null){
这个。输出=输出;
}
while(values.hasNext())
{
//如果我在这里打印
//并执行以下值。下一步().val1
//我得到了正确的结果
临时添加(values.next());
}
System.out.println(temp.get(0.val1);//结果错误
}
我得到的输出如下: 12/10/2012 10:13 2012年10月12日10:13

实际产出应为: 12/10/2012 09:10 2012年10月12日10:13


谢谢你的帮助。谢谢

价值观的实现是什么?出现症状的一个原因是,如果values.mext()总是返回对同一对象的引用,但会更改该对象的值以匹配迭代中的下一项。如果您没有访问其源代码的权限,可以通过在循环中打印值的System.identityHashCode().next()结果来测试这种情况


如果是这样,您需要修复迭代器的实现以每次返回不同的对象,或者需要在添加到ArrayList之前克隆对象。

值的实现是什么?出现症状的一个原因是,如果values.mext()总是返回对同一对象的引用,但会更改该对象的值以匹配迭代中的下一项。如果您没有访问其源代码的权限,可以通过在循环中打印值的System.identityHashCode().next()结果来测试这种情况


如果是这样,您需要修复迭代器的实现以每次返回不同的对象,或者需要在添加到ArrayList之前克隆对象。

正如@Patricia Shanahan已经指出的,对象正在被重复使用-对象的底层内容正在更新(但是所有的子对象等也被重用,这取决于您的readFields/write方法)

在将对象添加到ArrayList之前,您可以绕过这一问题来制作对象的副本:

@Override
public void reduce(Key_class key, Iterator<some_class> values,
    OutputCollector<Text, Text> output, Reporter reporter)
            throws IOException {
  if(this.output==null){
    this.output=output;
  }

  // you should out the arraylist to avoid unexpected behaviour and OOME
  temp.clear();

  while(values.hasNext())
  {
    // you'll need a copy of the configuration - conf
    temp.add(
        ReflectionUtils.copy(conf, values.next(), new some_class()));
  }
}
@覆盖
public void reduce(Key_类Key、迭代器值、,
OutputCollector输出,报告器(报告器)
抛出IOException{
if(this.output==null){
这个。输出=输出;
}
//您应该退出arraylist以避免意外行为和OOME
温度清除();
while(values.hasNext())
{
//您需要一份configuration-conf的副本
临时添加(
copy(conf,values.next(),newsome_class());
}
}

正如@Patricia Shanahan已经指出的,对象正在被重用——对象的底层内容正在更新(但所有子对象等也在被重用,这取决于您的读字段/写方法)

在将对象添加到ArrayList之前,您可以绕过这一问题来制作对象的副本:

@Override
public void reduce(Key_class key, Iterator<some_class> values,
    OutputCollector<Text, Text> output, Reporter reporter)
            throws IOException {
  if(this.output==null){
    this.output=output;
  }

  // you should out the arraylist to avoid unexpected behaviour and OOME
  temp.clear();

  while(values.hasNext())
  {
    // you'll need a copy of the configuration - conf
    temp.add(
        ReflectionUtils.copy(conf, values.next(), new some_class()));
  }
}
@覆盖
public void reduce(Key_类Key、迭代器值、,
OutputCollector输出,报告器(报告器)
抛出IOException{
if(this.output==null){
这个。输出=输出;
}
//您应该退出arraylist以避免意外行为和OOME
温度清除();
while(values.hasNext())
{
//您需要一份configuration-conf的副本
临时添加(
copy(conf,values.next(),newsome_class());
}
}

你总是打印出
temp
的第一个元素……你真的这么想吗?那只是为了测试目的,但它的值应该是2012年10月12日09:10,而我得到的是2012年10月12日10:13。你确定你的Reducer实例没有被重用吗?因为使用字段而不是局部变量来保存你的temp值是一个错误这样的类有点代码味道(虽然我不熟悉Hadoop)。为什么需要(公共)字段?范围和可见性应该尽可能有限(对象应该封装)。你总是打印出
temp
…的第一个元素。你真的这么想吗?那只是为了测试,但它的值应该是2012年10月12日09:10,而不是我得到的2012年10月12日10:13。你确定你的Reducer实例没有被重用吗?因为使用字段而不是局部变量来保存你的temp值有点麻烦这样一个类的代码味道(虽然我不熟悉Hadoop)。为什么需要一个(公共)字段?范围和可见性应该尽可能有限(应该封装对象)。values.next()正在返回不同的对象,但一旦我加载到ArrayList并在后续计算中使用它…ArrayList中的对象具有相同的对象。Patricia在这里是正确的。迭代器实现将重用具有不同值的相同可写对象作为优化。如果需要唯一值,则必须创建并存储新对象在数组中。values.next()正在返回不同的对象,但一旦我加载到ArrayList并在后续计算中使用它…ArrayList中的对象具有相同的对象。Patricia在这里是正确的。迭代器实现将重用具有不同值的相同可写对象作为优化。如果需要唯一值,则必须创建并存储新对象在您的阵列中。