【问题标题】:String#equals throw an ArrayIndexOutOfBoundExceptionString#equals 抛出 ArrayIndexOutOfBoundException
【发布时间】:2012-09-03 15:04:17
【问题描述】:

堆栈跟踪很长,但这是相关部分。

Caused by: java.lang.ArrayIndexOutOfBoundsException: 33
  at java.lang.String.equals(String.java:1018)
  at java.util.HashMap.get(HashMap.java:305)

所以,当我从 HashMap<String,?> 检索一个元素时,会调用 String#equaqls。然后,从行 if (v1[i++] != v2[j++]) 抛出一个 ArrayIndexOutOfBoundException@

// Sun java 1.6
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}

真的很奇怪。


更新。异常来自日志分析程序。我没有在那里使用反射。我还考虑过某些东西损坏了字符串对象,但没有从代码中得到任何线索。而且这个问题在重启后没有重现。不知道继续重试能不能重现。

  1. LogUtils

    public static Map<String, String> parseLine(String line) {
        if (StringUtils.isEmpty(line)) {
            return Collections.emptyMap();
        }
        String[] parts = StringUtils.split(line, '\t');
        Map<String, String> results = new HashMap<String, String>();
        for (String part : parts) {
            String[] keyVal = StringUtils.split(part, "=", 2);
            if (keyVal.length == 2) {
                String key = keyVal[0];
                String value = keyVal[1];
                results.put(key, value);
            }
        }
        return results;
    }
    
    public static void process(String fileName, Date date, Closure closure) throws IOException {
        InputStream is = null;
        Reader r = null;
        try {
            is = new FileInputStream(getFilename(fileName, date));
            is = new BufferedInputStream(is);
            is = new GZIPInputStream(is);
            r = new InputStreamReader(is, "utf8");
            LineIterator iter = IOUtils.lineIterator(r);
            while (iter.hasNext()) {
                String line = iter.nextLine();
                Map<String, String> map = LogUtils.parseLine(line);
                closure.execute(map);
            }
        } finally {
            IOUtils.closeQuietly(r);
            IOUtils.closeQuietly(is);
        }
    }
    
  2. 关闭

    public void execute(Map<String, String> line) {
        if (dataMap == null) {
            dataMap = new HashMap<String, Map<Long, Integer>>();
        }
    
        String identifier = line.get(Constants.IDENTIFIER_KEY); // Exception thrown from there
        /* ...blahblah... */
    }
    

为了简单起见,我将创建一个闭包对象并用它调用LogUtils.process。 LogUtils 换行(例如:key1=value1\tkey2=value2\t...kn=valuen)喜欢它变成HashMap。然后LogUtils 会将地图传递给闭包。当 Constants.IDENTIFIER_KEY 是静态最终字段时,从 line.get(Constants.IDENTIFIER_KEY); 抛出异常。所以equals方法的lhs和rhs是一个静态的final String,返回值为StringUtils.split(line, '\t')。我检查了 commons-lang 的代码。实际上是String#substring。所以还是很奇怪。

【问题讨论】:

  • 这表明 i 或 j 超出了该数组的限制。
  • @veer:我不这么认为。想象一下,如果 n 以 0 开头...对于您的版本,它将永远不会终止。
  • @yegong 你能告诉我们更多代码吗?例如插入和访问Map 的内容。
  • @JonSkeet equals 方法的代码不是我的实现。它是 java 1.6 的源代码。
  • @Rhyono 确定。但它是 java.lang.String#equals。此处不应出现 ArrayIndexOutOfBoundException。

标签: java


【解决方案1】:

这基本上表明某些东西正在破坏字符串对象。很容易复制:

import java.lang.reflect.*;

public class Test {
    public static void main(String[] args) throws Exception {
        String x = "hello";
        String y = new String("xhell");

        Field field = String.class.getDeclaredField("offset");
        field.setAccessible(true);
        field.set(y, 1);
        System.out.println(x.equals(y));
    }
}

...但我们不知道这是否是实际上在您的情况下字符串被损坏的方式。

【讨论】:

  • 作为我粘贴的代码,没有反射。我同意损坏的字符串对象。但是,代码看起来很简单,没有尝试打开字符串并修改最终字段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-29
  • 1970-01-01
  • 2016-02-24
  • 2023-04-02
  • 1970-01-01
  • 2023-03-24
相关资源
最近更新 更多