精华内容
下载资源
问答
  • 大家了解什么是数组长度吗?什么是数组下标吗?经常有人将这两个词混淆...总而言之一句话,在java中,数组的长度是不能够发生改变的,数组下标是从0开始的。java中的数组的定义就是 相同类型 ,固定长度 的一组数据,...

    大家了解什么是数组长度吗?什么是数组下标吗?经常有人将这两个词混淆,今天呢,小编给小伙伴们带来了有关数组的相关知识,就让我们一起了解了解吧。

    有的人说数组是可以改变,有的人说数组是不可以。然而我在使用的过程中,不指定数组的长度就会报错。不知道你们是否一样呢?

    总而言之一句话,在java中,数组的长度是不能够发生改变的,数组下标是从0开始的。

    java中的数组的定义就是 相同类型 ,固定长度 的一组数据,一旦被初始化,长度是不可更改。

    数组声明有两种方式:

    静态的初始化

    比如:int[] strArrayTest1 = {1,2};

    声明好之后它的长度就是2,是不可改变的。

    动态初始化

    案列:int[] strArrayTest2 = new int[5];

    这个时候它的长度为5,也是不可改变的。

    当然你可以先声明一个数组int[] strArrayTest1 = {1,2}, 然后由于业务需要修改为strArrayTest2 = new  int[4],表面上看长度改变了,但是这已经是两个不同的数组了,前面一个由于没有用,被垃圾回收器回收了。

    注意区分使用 new 的区别。

    如果对需要用的数组的长度不确定,有两种解决办法:

    第一种是在数组初始化的时候 长度申请的足够大,这样做会造成内存空间的浪费,一般不推荐使用的。

    第二种是使用java中提供的 集合 的方式来存储数据的,列如List,Set和Map类型的对象来进行存储数据,

    一方面这些类型的对象的长度也都是动态增长的;

    另一方面这些类中提供了很多便于操作数据的一些方法。

    因此在对此所需存储数据的多少不确定的时候,推荐使用第二种方法。

    好了,以上就是今天所讲的内容,是否了解了呢?希望给小伙伴们留下深刻的印象,想要了解更多知识,请据需关注本网站。

    展开全文
  • 刚刚学习Java不到一个星期,本来是搞C++的,没事学习Java,将来可以更好的想Android方向发展一下。现在正处于磨基础的阶段,对与每一个新手来书,最痛苦的莫过于此了。写了一个冒泡排序,用C++的思想写,没有任何...

    刚刚学习Java不到一个星期,本来是搞C++的,没事学习Java,将来可以更好的想Android方向发展一下。

    现在正处于磨基础的阶段,对与每一个新手来书,最痛苦的莫过于此了。

    写了一个冒泡排序,用C++的思想写,没有任何错误,但是改成Java就出现如下错误:

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 7

    at Range.paixu(c6_8.java:11)

    at c6_8.main(c6_8.java:29)

    貌似自己没有遇到过,数组越界,C++都没有问题,怎么这里就有问题了。把自己的代码也贴出来吧。代码写的比较粗糙,没任何注释。

    class Range

    {

    void paixu(int arr[])

    {

    for (int i = 0; i <= arr.length - 1; i++)

    {

    int temp;

    for (int j = 0; j <= arr.length - i; j++)

    {

    if (arr[j] > arr[j + 1])

    {

    temp = arr[j];

    arr[j] = arr[j + 1];

    arr[j + 1] = temp;

    }

    }

    }

    }

    }

    public class c6_8

    {

    public static void main(String []args)

    {

    int arr[] = {2, 5, 1, 32, 21, 3, 8};

    Range r = new Range();

    r.paixu(arr);

    for (int j = 0; j < arr.length; j++)

    {

    System.out.print("  " + arr[j]);

    }

    }

    }

    对于一个新手来说,改这个有点难度。最后还是想到了,Java的下标越界检查啊。我的天啊。

    检查了半天。不容易,该死的Java,可恨又可爱啊!

    展开全文
  • java 数组下标越界异常(ArrayIndexOutOfBoundsException) java 数组下标越界异常(ArrayIndexOutOfBoundsException)
  • BUG-并行流与数组下标越界-思考与总结今天线上环境报异常,发现了一个之前没注意过的问题,记录一下。1. 异常信息异常信息如下:···Caused by: java.lang.ArrayIndexOutOfBoundsExceptionat java.lang.String....

    BUG-并行流与数组下标越界-思考与总结

    今天线上环境报异常,发现了一个之前没注意过的问题,记录一下。

    1. 异常信息

    异常信息如下:

    ···

    Caused by: java.lang.ArrayIndexOutOfBoundsException

    at java.lang.String.getChars(String.java:826)

    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449)

    at java.lang.StringBuilder.append(StringBuilder.java:136)

    ···

    产生bug的代码改写后如下:

    public static void main(String[] args) {

    List lists = Lists.newArrayList();

    for (int i = 0; i < 10; i++) {

    lists.add(i);

    }

    for (int i = 0; i < 100; i++) {

    StringBuilder sb = new StringBuilder();

    // StringBuffer sb = new StringBuffer();

    lists.parallelStream().forEach(p -> {

    sb.append(p);

    // 可以明显看到,拼接的字符串长度越大,异常越容易发生

    sb.append("----------------------------------------");

    // stringBuilder.append("-");

    });

    System.out.println(i + ": " + sb.toString());

    }

    }

    2. 异常追踪分析

    从上面的信息可以看出,是StringBuilder.append使用时,产生了数组下标越界异常。下面是代码追踪:

    @Override

    public StringBuilder append(String str) {

    // 1

    super.append(str);

    return this;

    }

    public AbstractStringBuilder append(String str) {

    if (str == null)

    return appendNull();

    int len = str.length();

    // 2.1

    // 检查现有字符串加上要拼接的字符串以后,长度是否超出内部数组的最大长度,如果超出,则会分配一个新的内部数组,确保数组能装的下拼接后的字符串

    ensureCapacityInternal(count + len);

    // 2.2

    str.getChars(0, len, value, count);

    count += len;

    return this;

    }

    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {

    if (srcBegin < 0) {

    throw new StringIndexOutOfBoundsException(srcBegin);

    }

    if (srcEnd > value.length) {

    throw new StringIndexOutOfBoundsException(srcEnd);

    }

    if (srcBegin > srcEnd) {

    throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);

    }

    // 3

    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);

    }

    public static native void arraycopy(Object src, int srcPos,

    Object dest, int destPos,

    int length);

    一路追踪代码,可以无论是2.1还是2.2,最终都调用了本地方法arraycopy(),这里抛出的异常。

    本地方法定义如下:

    /* Only register the performance-critical methods */

    static JNINativeMethod methods[] = {

    {"currentTimeMillis", "()J", (void *)&JVM_CurrentTimeMillis},

    {"nanoTime", "()J", (void *)&JVM_NanoTime},

    {"arraycopy", "(" OBJ "I" OBJ "II)V", (void *)&JVM_ArrayCopy},

    };

    JNIEXPORT void JNICALL

    JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos,

    jobject dst, jint dst_pos, jint length);

    /*

    java.lang.System中的arraycopy方法

    */

    JVM_ENTRY(void, JVM_ArrayCopy(JNIEnv *env, jclass ignored, jobject src, jint src_pos,

    jobject dst, jint dst_pos, jint length))

    JVMWrapper("JVM_ArrayCopy");

    // Check if we have null pointers

    if (src == NULL || dst == NULL) {

    THROW(vmSymbols::java_lang_NullPointerException());

    }

    arrayOop s = arrayOop(JNIHandles::resolve_non_null(src));

    arrayOop d = arrayOop(JNIHandles::resolve_non_null(dst));

    assert(oopDesc::is_oop(s), "JVM_ArrayCopy: src not an oop");

    assert(oopDesc::is_oop(d), "JVM_ArrayCopy: dst not an oop");

    // Do copy

    s->klass()->copy_array(s, src_pos, d, dst_pos, length, thread);

    JVM_END

    这里发现JVM_ArrayCopy()只是简单的检测源数组和目的数组不为空,排除一些异常情况,并没有复制数组,而是调用了s->klass()->copy_array()方法来实现。源码如下:

    /**

    * java.lang.System中的arraycopy方法具体实现

    *

    * @param s 源数组

    * @param src_pos 源数组开始复制的下标

    * @param d 目标数组

    * @param dst_pos 目标数组开始覆盖的下标

    * @param length 要复制的数组元素数量

    * @param TRAPS 线程信息

    */

    void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,

    int dst_pos, int length, TRAPS) {

    ···

    // Check is all offsets and lengths are non negative

    // 检查所有的偏移量和长度是否非负

    if (src_pos < 0 || dst_pos < 0 || length < 0) {

    ···

    THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());

    }

    // Check if the ranges are valid

    // 检查数组边界是否合法,如果

    // 1.要复制的数组元素数量 + 源数组开始复制的下标 > 源数组长度

    // 2.要复制的数组元素数量 + 目标数组开始覆盖的下标 > 目标数组长度

    // 两种情况中有一种,就抛出数组下标越界异常

    if ((((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) ||

    (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length())) {

    ···

    THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());

    }

    ···

    }

    阅读源码及注释可以知道,上面两种情况下,都会抛出ArrayIndexOutOfBoundsException。

    到这里我们可以猜测出异常抛出的原因了:因为append()方法是在多线程(parallelStream并行流)中调用的,所以可能有两个或者多个线程通过了ensureCapacityInternal()方法的空间校验,而实际空间不足而导致了数组下标越界。

    例如有A、B两个线程,都需要拼接一个长度为40的字符串,而当前剩余空间为50。

    当A通过ensureCapacityInternal()检验且为执行getChars()方法时被挂起,这时B线程通过ensureCapacityInternal()对空间进行校验是可以通过的,因为40<50。

    接下来当A、B线程进行数组复制时,后复制的那个线程将出现数组下标越界异常,因为第一个线程复制完成后,剩下空间只有10。10<40而导致空间不足,下标越界。

    3. 其他问题

    3.1在测试代码中,我们可以很容易观察到,拼接的字符串长度越大,异常越容易发生。

    我们分析下面的源码:

    private void ensureCapacityInternal(int minimumCapacity) {

    // overflow-conscious code

    if (minimumCapacity - value.length > 0) {

    value = Arrays.copyOf(value,

    newCapacity(minimumCapacity));

    }

    }

    private int newCapacity(int minCapacity) {

    // 默认新数组容量为原数组的两倍+2

    int newCapacity = (value.length << 1) + 2;

    // 如果原数组的两倍+2还是小于需要的最小所需容量,则取最小所需容量为新数组容量

    if (newCapacity - minCapacity < 0) {

    newCapacity = minCapacity;

    }

    // 如果获取容量数值溢出,或者大于最大数组容量,则特殊处理(小于int最大值,则正常返回,否则抛出异常)

    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)

    ? hugeCapacity(minCapacity)

    : newCapacity;

    }

    public static char[] copyOf(char[] original, int newLength) {

    char[] copy = new char[newLength];

    System.arraycopy(original, 0, copy, 0,

    Math.min(original.length, newLength));

    return copy;

    }

    可以看到ensureCapacityInternal()方法的入参minimumCapacity是源内部数组已存放的字符串长度+要拼接的字符串长度,只有源内部数组的总长度小于minimumCapacity,才会调用newCapacity()方法获取新内部数组的长度,然后调用copyOf()方法将源数组的元素复制到新内部数组。

    分析可以得出原因:

    字符串的内部数组,默认的长度是16,如果循环拼接最终的字符串长度小于16,则这个异常不会发生。

    因为内部数组每次扩容,都是原数组长度x2+2,所以拼接的字符串长度越长,循环前几次,遇到长度不够报异常的可能性越大,触发异常所需要的的循环次数越少。

    3.2 并行流parallelStream()使用问题

    parallelStream提供了流的并行处理,它是Stream的另一重要特性,其底层使用Fork/Join框架实现。

    Fork/Join 框架的核心是采用分治法的思想,将一个大任务拆分为若干互不依赖的子任务,把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务。

    同时,为了最大限度地提高并行处理能力,采用了工作窃取算法来运行任务,也就是说当某个线程处理完自己工作队列中的任务后,尝试当其他线程的工作队列中窃取一个任务来执行,直到所有任务处理完毕。所以为了减少线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。

    Fork/Join 的运行流程图

    4f972297adda520bc32235e025d5547c.png

    用下面的示例演示一下parallelStream的使用。

    public static void main(String[] args) {

    List lists = Lists.newArrayList();

    for (int i = 0; i < 10; i++) {

    lists.add(i);

    }

    lists.parallelStream().forEach(System.out::println);

    lists.parallelStream().map(p->++p).forEach(System.out::println);

    }

    输出:

    6 5 8 9 7 1 0 2 4 3

    7 9 3 10 2 6 1 8 5 4

    我们发现,使用parallelStream后,结果并不按照集合原有顺序输出。为了进一步证明该操作是并行的,我们打印出线程信息。

    public static void main(String[] args) {

    List lists = Lists.newArrayList();

    for (int i = 0; i < 10; i++) {

    lists.add(i);

    }

    lists.parallelStream().forEach(num -> System.out.println(num + "--" +

    Thread.currentThread().getName()));

    }

    输出:

    6--main

    8--ForkJoinPool.commonPool-worker-2

    1--ForkJoinPool.commonPool-worker-3

    2--ForkJoinPool.commonPool-worker-1

    9--ForkJoinPool.commonPool-worker-2

    5--main

    3--ForkJoinPool.commonPool-worker-2

    4--ForkJoinPool.commonPool-worker-1

    7--ForkJoinPool.commonPool-worker-4

    0--ForkJoinPool.commonPool-worker-3

    如上,可以确信parallelStream是利用多线程进行的,这可以很大程度简化我们在需要的时候,进行并行操作。例如第一个例子中,对所有集合元素进行自增操作。尤其是当数据量非常庞大的时候,并行流的数据处理将具有无与伦比的优势。

    但同时,并行流也是一把双刃剑,使用不当,也会引发不好后果,比如我这次碰到的线上bug,还有就是bug代码中,使用并行流进行字符串拼接,我认为也是一种非常不好的用法,因为字符串拼接是,我们往往是追求有序地拼接,这样文本语意才会符合我们的预期,但是使用并行流很明显不能满足这一点。

    由于并行流使用多线程,则一切线程安全问题都应该是需要考虑的问题,如:资源竞争、死锁、事务、可见性等等。

    4. 总结

    4.1 bug修复方法

    使用串行流stream();

    使用线程安全的StringBuffer。

    结合前面讨论与思考,适合第一种方式,毕竟数据量也不大。

    4.2 并行流 or 串行流

    parallelStream是一把同时有巨大隐患和好处的双刃剑,那么,使用如何选择,我们可以考虑以下几个问题:

    是否需要并行?

    任务之间是否是独立的?是否会引起任何竞态条件?

    结果是否取决于任务的调用顺序?

    对于问题1,在回答这个问题之前,你需要弄清楚你要解决的问题是什么,数据量有多大,计算的特点是什么?并不是所有的问题都适合使用并发程序来求解,比如当数据量不大时,顺序执行往往比并行执行更快。毕竟,准备线程池和其它相关资源也是需要时间的。但是,当任务涉及到I/O操作并且任务之间不互相依赖时,那么并行化就是一个不错的选择。通常而言,将这类程序并行化之后,执行速度会提升好几个等级。

    对于问题2,如果任务之间是独立的,并且代码中不涉及到对同一个对象的某个状态或者某个变量的更新操作,那么就表明代码是可以被并行化的。

    对于问题3,由于在并行环境中任务的执行顺序是不确定的,因此对于依赖于顺序的任务而言,并行化也许不能给出正确的结果。

    展开全文
  • importjava.util.Arrays;importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);intn=sc.nextInt();intk=sc.nextInt();inta...import java.util.Arrays;imp...

    importjava.util.Arrays;importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);intn=sc.nextInt();intk=sc.nextInt();inta...

    import java.util.Arrays;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc=new Scanner(System.in); int n=sc.nextInt(); int k=sc.nextInt(); int array[]=new int [n]; for(int i=0;i

    展开

    展开全文
  • } Input Error: java.lang.ArrayIndexOutOfBoundsException:1 at.com.CenDB.FileInsert.getText(FileInsert .java ;41) at.com.CenDB.main(FileInsert .java ;53) 能不能帮我解决下问题? 展开
  • java数组下标越界的问题

    万次阅读 2015-07-28 00:10:29
    java数组下标越界的问题: 最近一直出现这类问题:数组下标越界 举例说明: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10 at day07.PaiXu.get3max(RankDemo2.java:15) at day07....
  • (若是不满意JAVA自带的乱序此方法同样可用于容器)接下来我就直接写成工具了,方便新手收集使用。因为现在我也是在新手阶段使用的.../**对指定长度的数组进行乱序(下标乱序)*/publicclassDisorder{privatestaticint...
  • importjava.util.*;publicclassSorter{publicstaticvoidmain(String[]args){System.out.println("Pleaseentersamplesize:");intx;x=Keyboard.readInt();intinputArray[]=newint[x];in...import java.util.*;public c...
  • 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。基本特点:数组的长度是确定的。数组一旦被创建,它的大小就是不可以改变的。数组元素必须是相同类型,不允许出现混合类型。数组中的...
  • public class practice_1_6_8 {public static void main(String[] args) {int[] cored = {11,22,33,44,55,...System.out.println("判断数组下标:");for (int i = 0 ; iSystem.out.println("数组内容:"+cored[i]);...
  • 【判断题】Java语言中数组元素下标从0开始。 【判断题】使用泛型时,需要在尖括号中指定。 【判断题】一维条码对物品的标识,二维条码对物品的描述,二维条码在垂直方向携带信息,而一维条码在垂直方向不携带信息。...
  • 【填空题】数组的初始化包括 、 和 。【编程题】编写一个程序,实现1~100的累加。【填空题】数据类型转换分为 及 两种。【填空题】break语句最常见的用法是在switch语句中,通过break语句退出switch语句,使程序从...
  • 此类实现:输出一行数组数据,根据输入的下标,以下标位置为结束,将原数组分割成两组子数组。并交换两个子数组的位置,保持子数组中的元素序号不变.如:原数组为7,9,8,5,3,2 以下标3为分割点,分割为子数组一:7,9,8,...
  • JAVA数组下标和(19.3.26)

    千次阅读 2019-03-26 21:21:29
    *** 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。** 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 例如:...
  • java入门(六)数组(一)什么是数组数组的声明和创建三种初始化及内存分析下标越界及小结什么是数组数组的定义:数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成其中,...
  • 数组:1、概念一组相同类型的数据的组合,数组也是一种引用类型。数组的特点:一经创建,长度不可变。2、名称数组名称不是固定的,与存放的数据的类型有关。如:存放一组int类型的数据,数组名称 int[ ]存放一组字符串...
  • 数组是一段连续的空间,要求a[i]就是求它的地址,然后找到它。如果从0开始,则a[i]的地址= 首地址 + i*每个数据所占的长度;如果从1开始,则a[i]的地址= 首地址 + (i-1)*每个数据所占的长度。是不是前一种更好计算呢...
  • 刚刚学习Java不到一个星期,本来是搞C++的,没事学习Java,将来可以更好的想Android方向发展一下。 现在正处于磨基础的阶段,对与每一个新手来书,最痛苦的莫过于此了。 写了一个冒泡排序,用C++的思想写,没有...
  • Java数组在被创建的时候确定数组长度。索引下标从0开始。 1.数组定义及初始化int[]anArray;//定义anArray=newint[2];//初始化anArray[0]=100;//赋值anArray[1]=200;//赋值System.out.println("Elementatindex0:"+an...
  • Java从入门到放弃(六)--数组放弃数组是什么,好吃吗入门数组就是人以类聚,物以群分相同类型的 很多个 就可以用一个数组来代替他示例public class Main {public static void main(String[] args) {//声明一个元素是int...
  • package practice;... // 顺序遍历数组arr中的元素 int arr[] = { 8, 5, 14, 5, 15, 5, 16 }; System.out.print("数组arr中的元素:"); for (int i = 0; i < arr.length; i++) { System.out.print(a
  • public class Test{ public static void main(String[]args){ ...doc显示Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:0 at Test.main(Test.java:3) 这是照着书上打的怎么还有错啊
  • 背景我们知道大部分编程语言中的数组都是从0开始编号的,即array[0]是数组的第一个元素。这个和我们平时生活中从1开始编号的习惯相比显得很反人类。那么究竟是什么样的原因让大部分编程语言数组都遵从了这个神奇的...
  • 请编程实现一个函数找出数组中任意一个数值等于其下标的元素。例如,在数组{-3, -1,1, 3, 5}中,数字3和它的下标相等。思路同53-1和53-2一样,不再从头到尾遍历,由于是排序数组,我们继续考虑使用二分查找算法:1)...
  • 1.Java数组的语法:String[数组下标], Java数组的下标是从0开始的。2.示例代码public class StringArray{public static void main(String[]args){//java数组初始化String[] strArray={"1","2","3"};//输出j...
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼这是一个输入有n个数字的数组,选出k个最小值的函数。import java.util.*;public class example { public static void main(String[] args) {try{Scanner scan=new ...
  • 数组特性数组的一大特性:随机访问,这个在实际开发中大家也经常使用到。数组地址如何理解随机访问?假设有个数组int a[10],它的起始地址值为0x1000(address),那么当你访问第n个...假设下标是从1开始,其寻址公...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,894
精华内容 4,357
关键字:

java数组下标

java 订阅