前几天写递归运算时候,报了一个错误--->内存溢出,代码如下:
/** * 获取所有乘积为n的小于n的数字,1只能出现一次 * n可以拆解成各个小数相乘,每次/ 一个小于n的数字看结果是不是 1 * 同时验证 % 余数 * * @param * @return void * @author kongzhi * @date 2019年2月26日下午3:28:12 * */ public static void getAllNumber(ArrayList<Long> result, Long targetNum) { if (targetNum == 1) { //contains 用的是 equals比较值 ---> if (!result.contains(1L)) { result.add(Long.valueOf(1)); } System.out.println(result); return; } else { for (long jj = 1; jj <= targetNum; jj++) { if (targetNum % jj != 0) { continue; } //避免1添加 //特别注意下:这里 contains后面必须写 1L,如果ArrayList<Long> 是Long的话,因为会转Object,1 默认对应 Integer if (jj == 1L && result.contains(1)) { continue; } @SuppressWarnings({ "unchecked" }) ArrayList<Long> resultNew = (ArrayList<Long>)result.clone(); resultNew.add(Long.valueOf(jj)); getAllPlusResult(resultNew, targetNum / jj); } } }
原因出在这里:
if (jj == 1L && result.contains(1))
原始整数类型 short int long如果不加标识符,默认是int类型,而ArrayList.contains源码如下:
/** * Returns <tt>true</tt> if this list contains the specified element. * More formally, returns <tt>true</tt> if and only if this list contains * at least one element <tt>e</tt> such that * <tt>(o==null ? e==null : o.equals(e))</tt>. * * @param o element whose presence in this list is to be tested * @return <tt>true</tt> if this list contains the specified element */ public boolean contains(Object o) { return indexOf(o) >= 0; } /** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
而equals的执行如下:
/** * Compares this object to the specified object. The result is * {@code true} if and only if the argument is not * {@code null} and is a {@code Long} object that * contains the same {@code long} value as this object. * * @param obj the object to compare with. * @return {@code true} if the objects are the same; * {@code false} otherwise. */ public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; }
会先去判断是否是同一种类型,再去比较数值。
前面说了默认是int类型,自动装箱后变为Integer类型,而递归代码中的为 ArrayList<Long> 所以第一步判断就因为类型不一致而不通过。
之后会一直循环递归调用直到内存溢出。