[Java] 作业5 (数组)

这篇博客介绍了Java数组的基本概念和操作,包括数组的初始值、多维数组的使用。同时,讲解了try-catch-finally语句在处理数组越界异常时的作用,强调finally块的执行特性。还涉及到了参数传递时的基础类型与引用类型的区别,以及如何翻转数组。文章提供了相关书籍章节供读者深入学习。
摘要由CSDN通过智能技术生成

Q10

public class Test {
  public static void main(String args[]) {
    int a[] = new int[5];
    boolean b[] = new boolean[5];
    System.out.print(a[1]);
    System.out.println(b[2]);
  }
}
在第 3 行和第 4 行,我们分别创建了两个数组:

    - 含有5个 int 元素的数组 a

    - 含有5个 boolean 元素的数组 b

根据Oracle官文文档 -- 4.12.5. Initial Values of Variables

Every variable in a program must have a value before its value is used.

Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10):

    - For type int, the default value is zero, that is, 0.

    - For type boolean, the default value is false.

    - ... (byte, long, float, double等类型可以点击上述链接,自行查阅)

程序中的每个变量必须在使用前拥有一个值;

在数组创建时,其组件(每个元素)都会初始化一个默认值:

    - int 类型的默认值是 0

    - boolean 类型的默认值是 false


Q15

public class Test {
  public static void main(String[] args) {
    int b[][] = { { 1 }, { 2, 2 }, { 2, 2, 2 } };
    int sum = 1;
    for (int i = 0; i < b.length; i++) {
      for (int j = 0; j < b[i].length; j++) {
        sum *= b[i][j];
      }
    }
    System.out.println(sum);
  }
}
考察多(二)维数组的知识,这方面的知识可以参考:

    - 《Java核心编程 卷1 基础知识》 (原书第9版) 3.10.6 多维数组

    - 最权威的Oracle官方文档:10.6. Array Initializers


Q18

预备知识

try, catch, finally的用法大概是:

try {
  // Do your task here
} catch (ExceptionType e) {
  // Program will enter this section only if exception occur (threw)
} finally {
  // Program will enter this section whatever there is an exception or not.
}
在try块中,我们可以执行任务,在执行任务的过程中,可能会出现异常(比如说对含有 n 个元素的数组 a 进行 a[n] 这样的下标访问 —— 因为 a 只能支持 a[0, 1, ..., n - 1] 这样的下标访问),因此程序会抛出异常。

在catch块中,我们可以捕获这个异常,并且执行我们想要做的事

    - 比如打印信息:System.out.println("There is an exception here."); 

    - 这样做的好处是,在实际项目中,可以通过try-catch显式地定制处理异常的方法,而不会像大家在实验课上因为一些异常,导致程序直接中止(abort). 试想如果你的服务器上正运行着提供给上万个用户使用的APP, 你并不希望因为无法处理某一个用户的请求,而使整个服务器、APP中止。

在finally块中,无论是否发生异常,这个块中的内容都会被执行。finally块是可选的(optional), 但try-catch必须要搭配起来使用,所以下述语句也是符合语法的:

try {
  // Do your task here
} catch (ExceptionType e) {
  // Handle the exception here
}
回到原题
import java.util.Scanner;

public class Test {
  public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    // 两个case
    for (int i = 1; i <= 2; ++i) {
      // 每个case的第一个数字代表:数组中将包含几个元素
      int n = in.nextInt();
      int[] a = new int[n];
      // 通过循环,输入数字a0, a1, ..., a(n-1),并分别赋值给a[j], (0 < j < n)
      for (int j = 0; j < n; ++j)
        a[j] = in.nextInt();
      try {
        int sum = 0;
        for (int j = 0; j <= n; ++j) {
          if (a[j] % 10 == 0)
            break;
          sum = sum + a[j];
        }
        System.out.print("sum=" + sum);
      } catch (ArrayIndexOutOfBoundsException e) {
        System.out.print("@@@");
      } finally {
        System.out.print("###");
      }
    }
    in.close();
  }
}
题目输入为:

4

12 45 67 20

2

21 31

第一个case

首先,n = 4, 输入 4 个数字,并初始化数组 a, 此时 a = {12, 45, 67, 20};

其次,我们在循环中遍历数组每个元素,并进行累和操作,当 j = 3 时,由于 a[3] % 10 == 0 成立,break:语句生效,跳出循环,打印"sum=124".

最后,执行finally语句,输出 "###"

第二个case

首先,n = 2, 输入 2 个数字,并初始化数组 a, 此时 a = {21, 31};

其次,我们在循环中遍历数组每个元素,并进行累和操作

    - 当 j = 0 或 1 时,sum += a[j]

    - 当 j = 2 时,if (a[j] % 10 == 0) 将访问数组 a 的第 2 个元素,这会发生数组的访问越界。抛出异常,所以在此没有打印"sum=..."

再次,catch语句捕获了这个ArrayIndexOutOfBoundsException. 输出 "@@@"

最后,执行finally语句(在此强调,这个语句无论是否出现异常,都将被执行),输出 "###"


Q28

要解决这题,只要把题目复制到eclipse下,ctrl + shift + f重新排版一下就可以:

public class Test {
  public static void main(String[] args) {
    int[] x = new int[5];
    int i;
    for (i = 0; i < x.length; i++)
      x[i] = i;
    System.out.println("i: " + i);
    System.out.println(x[i]);
  }
}
仍然不理解的同学,可以考虑一下上面程序的第7行输出的 i 的值会是多少。


Q39

public class Test {
  public static void main(String[] args) {
    int[] x = { 1, 2, 3, 4, 5 };
    // 调用increase(x)时,编译器将在一份新的内存空间中,创建一个跟本地的x的值相同的变量(我们姑且称之为x2)
    // x2的值和x相同,所以x2和x一样,指向了同一个数组的起始位置
    increase(x);
    int[] y = { 1, 2, 3, 4, 5 };
    // 调用increase(y[0])时,编译器将在一份新的内存空间中,创建一个跟本地的y[0]的值相同的变量(称为y2)
    // 虽然这个y2的值跟y[0]相同,但因为它们分别指向不同的内存空间
    // 所以,在increase(y2)中即使y2++, 仍然没有改变y指向的数组中的内容
    increase(y[0]);
    System.out.println(x[0] + " " + y[0]);
  }
  
  // 为避免混淆,我们在此将参数名从 x 改为 x2
  // 事实上,无论参数名叫什么,都不会影响程序最终的结果
  public static void increase(int[] x2) {
    for (int i = 0; i < x2.length; i++)
      x2[i]++;
  }

  public static void increase(int y) {
    y++;
  }
}
根据语法,在发生参数传递的时候,无论参数的类型是什么,都会在一份新的内存空间中,将原来的值拷贝一份:

    - 对于基础类型(类型名都是小写字母的),如int, long, double等,在调用方法中(callee)中修改形参,并不会影响caller中实参的值——形参和实参分别指向不同的内存空间;

    - 对于数组、String等,同样会在一份新的内存空间中,将原来的值拷贝一份。以数组 x 为例:

        - 这里的拷贝并不代表将整个数组赋值一遍,而是将数组第一个元素的内存地址拷贝一份作为 x2 传递给调用方法(callee). 

        - 所以在 callee 中,通过下标访问去修改 x2 指向的内容,等价于修改 calle r中 x 数组的内容。这是由于:

            - 在方法调用\参数传递时,采用的copy by value策略,决定了 caller中的x 和 callee中的x2 的值相同;相同的值,则意味着 x 和 x2 都指向着相同的内存空间。


Q40

// Program I
public class Test {
  public static void main(String[] args) {
    int[] list = { 1, 2, 3, 4, 5 };
    reverse(list);
    for (int i = 0; i < list.length; i++)
      System.out.print(list[i] + " ");
  }

  public static void reverse(int[] list) {
    int[] newList = new int[list.length];
    for (int i = 0; i < list.length; i++)
      newList[i] = list[list.length - 1 - i];
    list = newList;
  }
}

// Program II
public class Test {
  public static void main(String[] args) {
    int[] oldList = { 1, 2, 3, 4, 5 };
    reverse(oldList);
    for (int i = 0; i < oldList.length; i++)
      System.out.print(oldList[i] + " ");
  }

  public static void reverse(int[] list) {
    int[] newList = new int[list.length];
    for (int i = 0; i < list.length; i++)
      newList[i] = list[list.length - 1 - i];
    list = newList;
  }
}
首先,要明确一点:程序 I 和程序 II 中的reverse方法,是完全等价的:

    - 接受一个int[]类型的参数,将数组中的元素翻转
其次,程序 I 和程序 II 唯一的区别,就是在main方法中,采用了不同的参数名用来表示{ 1, 2, 3, 4, 5 }. 但换个名字,最终是不会改变结果的。


Q41

参考《Java语言程序设计-基础篇》第8版:

    6.6 给方法传递数组


Q46

试运行下述程序,并理解运行结果;

在理解运行结果后,可查阅课本、参考书加深理解。

public class Test {
  public static void main(String[] args) {
    double[][] x = new double[4][5];
    System.out.println("x.length = " + x.length);
    for (int i = 0; i < x.length; ++ i)
      System.out.println("x[" + i + "] = " + x[i].length);
  }
}


Q48

参考《Java核心技术 卷1 基础知识》第9版:

    - 3.10.7 不规则数组

        - 对多维数组掌握不够好的同学,可参考 3.10.6 多维数组


Q52

预备知识:

// 通过形式如下所述的for语句,我们可以遍历elements中的每个元素
for (DataType element: elements) {
  // 如果elements的类型是double[], 那么element的类型应该是double
  // 如果elements的类型是long[][], 那么element的类型应该是long
}
实验:

// 下述程序将输出1 2 3 (每个数字各占一行)
int[] array = {0, 1, 2};
for (int elem: array) {
  System.out.println(elem);
}

回到原题:

public class Test {
  public static void main(String[] args) {
    int[][] values = { { 3, 4, 5, 1 }, { 33, 6, 1, 2 } };
    int v = values[0][0];
    for (int[] list : values)
      for (int element : list)
        if (v > element)
          v = element;
    System.out.print(v);
  }
}

values是一个二维数组,我们通过for遍历values中的每个元素,所以每个list都是一个一维数组int[]

    - 我们通过for遍历list中的每个元素,所以每个element都是一个整型int


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值