Java方法、数组
方法的定义
在许多语言(如 C 和 C++)中,使用术语 函数 (function) 用来命名子程序。在 Java 中,我们使用术语 方法(method)来表示“做某事的方式”。
在 Java 中,方法决定对象能接收哪些消息。方法的基本组成部分包括名称、参数、返回类型、方法体。格式如:
[返回类型] [方法名](/*参数列表*/){
// 方法体
}
返回类型
方法的返回类型表明了当你调用它时会返回的结果类型。参数列表则显示了可被传递到方法内部的参数类型及名称。方法名和参数列表统称为方法签名(signature of the method)。签名作为方法的唯一标识。
Java 中的方法只能作为类的一部分创建。它只能被对象所调用 [1],并且该对象必须有权限来执行调用。若对象调用错误的方法,则程序将在编译时报错。
我们可以像下面这样调用一个对象的方法:
[对象引用].[方法名](参数1, 参数2, 参数3);
若方法不带参数,例如一个对象引用 a 的方法 f 不带参数并返回 int 型结果,我们可以如下表示:
int x = a.f();
上例中方法 f 的返回值类型必须和变量 x 的类型兼容 。调用方法的行为有时被称为向对象发送消息。面向对象编程可以总结为:向对象发送消息。
参数列表
方法参数列表指定了传递给方法的信息。正如你可能猜到的,这些信息就像 Java 中的其他所有信息 ,以对象的形式传递。参数列表必须指定每个对象的类型和名称。同样,我们并没有直接处理对象,而是在传递对象引用 [2]。但是引用的类型必须是正确的。如果方法需要 String 参数,则必须传入 String,否则编译器将报错。
int storage(String s) {
return s.length() * 2;
}
此方法计算并返回某个字符串所占的字节数。参数 s 的类型为 String 。将 s 传递给 storage() 后,我们可以把它看作和任何其他对象一样,可以向它发送消息。在这里,我们调用 length() 方法,它是一个 String 方法,返回字符串中的字符数。字符串中每个字符的大小为 16 位或 2 个字节。你还看到了 return 关键字,它执行两项操作。首先,它意味着“方法执行结束”。其次,如果方法有返回值,那么该值就紧跟 return 语句之后。这里,返回值是通过计算
s.length() * 2
产生的。在方法中,我们可以返回任何类型的数据。如果我们不想方法返回数据,则可以通过给方法标识 void 来表明这是一个无需返回值的方法。 代码示例:
boolean flag() {
return true;
}
double naturalLogBase() {
return 2.718;
}
void nothing() {
return;
}
void nothing2() {
}
当返回类型为 void 时, return 关键字仅用于退出方法,因此在方法结束处的 return 可被省略。我们可以随时从方法中返回,但若方法返回类型为非 void,则编译器会强制我们返回相应类型的值。
可变参数
- 在方法声明中,在指定参数类型后加一个省略号(...)
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明
方法重载
方法重载是必要的,它允许方法具有相同的方法名但接收的参数不同。
区分重载方法
如果两个方法命名相同,Java是怎么知道你调用的是哪个呢?有一条简单的规则:每个被重载的方法必须有独一无二的参数列表。你稍微思考下,就会很明了了,除了通过参数列表的不同来区分两个相同命名的方法,其他也没什么方式了。你甚至可以根据参数列表中的参数顺序来区分不同的方法,尽管这会造成代码难以维护。
不能根据返回值类型区分重载的方法。
递归
- A方法调用B方法,我们很容易理解
- 递归就是:A方法调用A方法,就是自己调用自己
- 利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
- 递归结构包括两个部分:
- 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环
- 递归体:什么时候需要调用自身方法
数组的定义
- 数组是相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成
- 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
数组声明创建
- 首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
- Java语言使用new操作符来创建数组,语法如下:
dataType[] arrayRefVar = new dataType[arraySize];
- 数组的元素是通过索引访问的,数组索引从0开始
- 获取数组长度:
arrays.length
数组初始化
- 静态初始化
这种特殊的初始化是由一对花括号括起来的值组成。
int[] a1 = {1, 2, 3, 4, 5};
- 动态初始化
int[] a2 = new int[5];
数组元素中的基本数据类型值会自动初始化为空值(对于数字和字符是 0;对于布尔型是 false)。
数组的四个基本特点
- 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
- 其元素必须是相同类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
- 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
- 栈内存(Stack)存在于常规内存 RAM(随机访问存储器,Random Access Memory)区域中,可通过栈指针获得处理器的直接支持。栈指针下移分配内存,上移释放内存,这是一种快速有效的内存分配方法,速度仅次于寄存器。创建程序时,Java 系统必须准确地知道栈内保存的所有项的生命周期。这种约束限制了程序的灵活性。因此,虽然在栈内存上存在一些 Java 数据,特别是对象引用,但 Java 对象却是保存在堆内存的。
- 堆内存(Heap)这是一种通用的内存池(也在 RAM 区域),所有 Java 对象都存在于其中。与栈内存不同,编译器不需要知道对象必须在堆内存上停留多长时间。因此,用堆内存保存数据更具灵活性。创建一个对象时,只需用
new命令实例化对象即可,当执行代码时,会自动在堆中进行内存分配。这种灵活性是有代价的:分配和清理堆内存要比栈内存需要更多的时间(如果可以用 Java 在栈内存上创建对象,就像在 C++ 中那样的话)。随着时间的推移,Java 的堆内存分配机制现在已经非常快,因此这不是一个值得关心的问题了。
数组边界
- 下标的合法区间:[0,length-1],如果越界就会报错;
- ArrayIndexOutOfBoundsException:数组下标越界异常!
多维数组
- 多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。
- 二维数字
int a[][] = new int[2][5];
解析:以上二维数组a可以看成一个两行五列的数组。
Arrays 类
- 数组的工具类java.util.Arrays
- Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用使用对象来调用
冒泡排序
- 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序。
import java.util.Arrays;
public class ArrayDemo07 {
public static void main(String[] args) {
//冒泡排序
//比较数组中,两个相邻的元素,如果第一个数比第二个数大,就交换它们的位置
// 每一次比较,都会产生出一个最大,或者最小的数字,下一轮测试则可以少一次排序,依次循环,直到结束
int[] a = {1,4,6,3,6,7,4,8,4};
int[] sort = sort(a);
System.out.println(Arrays.toString(sort));
}
public static int[] sort(int[] array) {
//临时变量
int temp = 0;
//外层循环,判断要走多少次
for (int i = 0; i < array.length-1; i++) {
//内层循环,比较判断两个数,如果第一个数比第二个数大,则交换位置
for (int j = 0; j < array.length-1-i; j++) {
if(array[j+1] < array[j]) {
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
}
稀疏数组
- 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
- 稀疏数组的处理方式是:
- 记录数组一共有几行几列,有多少个不同值
- 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
public class ArrayDemo {
public static void main(String[] args) {
// 1.创建一个二维数组 11 * 11 0:没有棋子 1:黑棋 2白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
System.out.println("输出原始的数组");
for (int[] ints : array1) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
System.out.println("=================================");
//转换为稀疏数组保存
//获取有效值的个数
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (array1[i][j] != 0) {
sum++;
}
}
}
System.out.println("有效值的个数: " + sum);
// 2.创建一个稀疏数组的数组
int[][] array2 = new int[sum+1][3];
array2[0][0] = 11;
array2[0][1] = 11;
array2[0][2] = sum;
// 遍历二维数组,将非零的值,存放在稀疏数组中
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j] != 0) {
count++;
array2[count][0] = i;
array2[count][1] = j;
array2[count][2] = array1[i][j];
}
}
}
// 输出稀疏数组
System.out.println("稀疏数组");
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2] + "\t");
}
System.out.println("=====================================");
System.out.println("还原");
// 1.读取稀疏数组
int[][] array3 = new int[array2[0][0]][array2[0][1]];
// 2.给其中的元素还原它的值
for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2];
}
// 3.打印
System.out.println("输出还原的数组");
for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
}
}

浙公网安备 33010602011771号