[Java] 方法和数组
目录
1. 方法
1.2 什么是方法
Java中的方法就类似于C语言当中的函数,是实现一种特定的,使用频率高的功能,专门解决一种问题的办法。例如:求一个数的开平方,判断一个数是不是素数。
方法也分为两种,一种是Java语言规定的方法,还有一种是程序员根据自己的需要自定义的一些方法。
当在解决重复问题时,设置一个方法解决重复问题,可以多次调用方法去解决重复问题,不用每次使用就需要写代码,减少代码冗余度。
1.2 方法的定义
修饰符 返回值类型 方法名(参数类型){
方法体代码;
(return 返回值;)
}
上面是方法的基本形式,举个例子,写一个判断一个数是不是素数的方法:
public static boolean isPrimeNumber(int n){
for (int i = 2; i < Math.sqrt(n); i++) {
if(n % i == 0){
return false;
}
}
return true;
}
}
public static 是修饰符,boolean 是返回值类型,返回值类型必须与return返回的类型一致,isPrimeNumber是方法名,int n是参数,下面便是方法体,如果没有返回值,则返回值类型写void,不用写return。
方法不能嵌套定义,方法的命名一般是小驼峰,方法必须在类里面。
1.3 方法的调用
定义好一个方法后,需要在main函数里面进行调用,否则不会调用。
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
boolean b = isPrimeNumber(a);
if (b == true) {
System.out.println(a + "是素数");
}
}
在调用方法时候如果方法需要传参,便需要在调用的时候传入对应类型的参数,然后调用方法。 形参是实参的一份临时拷贝,改变形参的值不会改变实参的值,因为形参和实参不是同一块地址,每次调用方法都需要在栈中调用一块空间,方法调用完销毁。
1.4 方法的重载
方法在调用时候可能需要传的参数的类型,顺序,数量不同,但都是同一种功能的方法,这时候就可以把两种方法用相同的名字命名,例如:
public static int add(int a,int b){
return a + b;
}
public static double add(double a,double b){
return a + b;
}
上面代码是计算两个数的和的方法,但是传的参数不一样,可以用相同的名字来命名方法,这样调用这个方法时候既可以计算两个整型的和,也能计算两个双精度浮点数的和。
注意:
方法名必须相同
方法参数的类型,顺序,数量其中至少有一种不同
与方法的返回值类型无关。
按理来说同一块作用域不能有两个相同的标识符,但是为什么类里面可以有相同名字的两种方法呢?
其实不然,我们编写的方法名并不是真正存储在内存中的方法名,而编译器会将方法+后面的参数编译成一种方法签名供机器识别。
我们可以通过JDK自带的反汇编工具查看方法在机器中存储的真正名字。
1.先将.java文件编译成.class文件
2. 找到.class文件所在的目录,用控制台打开
3. 输入javap -v 字节码文件名就可以显示反汇编码了。

上面第一个方法名是add;(II)I,括号里面表示方法的参数是两个整型,后面表示返回值是整型,第二个方法名add(DD)D,括号里面表示方法的参数是两个double类型的,后面表示返回值是double类型。机器识别的是这种方法签名,区分方法的重载。
下面方法签名的一些符号:

1.5 递归
递归就是递推和回归的意思,在解决一些问题时,使用递归将复杂的问题简单化,就可以轻松求解。递归也就是方法重复调用自己,知道遇到停止条件,才停止调用,返回调用的值。
因此递归有两个重要的部分:
1. 递推公式
2. 终止条件
例如求n!;
public static void main(String[] args) {
//求n的阶乘
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.println(fib(n));
}
public static int fib(int a){
if(a == 1){
return 1;
}
return a * fib(a-1);
}
上面代码中 a == 1是终止条件,a * fib(a-1)是递推公式。
但是递归也有它的坏处,那就是容易导致栈溢出,因为每次调用方法都需要在栈里面申请空间,如果问题过于复杂,申请的空间过多,就会导致栈溢出,例如用递归解决斐波那契数列问题,给的数太大,就会导致栈溢出。
2. 一维数组
2.1 什么是数组
数组可以理解为相同元素的集合,数组里面可以存储许多相同类型的数据,数组在内存中是连续存储的。
2.2 数组的创建
数组创建的基本形式,下面我以创建整型数组为例:
int[] a = new int[10];
int[]是数据类型,代表引用类型,a是变量名,称为引用变量也被称为引用,new是创建一个新的对象,后面中括号里是数组的大小。
2.3 数组的初始化
数组的初始化分为两种动态初始化和静态初始化:
动态初始化:
在创建数组的时候直接指定数组的大小,不指定数组内容,系统默认赋值为0:
int[] a = new int[10];
静态初始化:
在创建数组的时候不指定数组元素的个数,而是指定数组里面的值:
int[] a = new int[]{1,2,3,4,5};
静态变量虽然没有指定数组的大小,但是编译器会根据后面数据的内容来判断数组的大小。
静态变量初始化时候可以简写成:
int[] a = {1,2,3,4,5};
在Java中也支持C语言的定义数组的方法:
int a[] = {1,2,3,4,5};
当然不建议平时这样定义数组和初始化。
在静态初始化和动态初始化时也可以分开来写:
//静态初始化
int[] a;
a = new int[]{1,2,3,4,5};
//动态初始化
int[] b;
b = new int[10];
当然不能写成如下格式:
//错误
int[] a;
a = {1,2,3,4,5};
数组没有初始化的话,系统默认的值是:

数组中存储的是引用类型时的默认值是:null。
2.4 遍历数组
遍历数组有三种方法:
方法一:
下面方法中使用循环的方法来遍历数组并打印,里面用到.length的属性,.length是求数组长度的属性。
int[] a = new int[]{1,2,3,4,5};
for(int i = 0;i < a.length;i++) {
System.out.print(a[i] + " ");
}
方法二:
下面是for循环的的另一种版本,能够更简便的遍历数组,把数组里的每个值传给定义的 x变量,并打印。
int[] a = new int[]{1,2,3,4,5};
for (int x,a) {
System.out.print(x + " ");
}
方法二的优点是遍历数组简单,缺点是获取不了数组元素的下标,不能改变数组里面的值。
方法三:
这里用到了Arrays里面的toString方法,将数组传进去返回数字里面的值的字符串形式:

import java.util.Arrays
int[] a = new int[]{1,2,3,4,5};
String b = Arrays.toString(a);
System.out.println(b);
输出结果是:[1,2,3,4,5]
2.5 引用数据类型
数组属于引用数据类型,引用数据类型就是存储到是数据在堆区创建的地址,存储都引用变量里面。下面先介绍一下JVM(java虚拟机):
程序都要在JVM中运行,在JVM中的栈区申请一块栈帧,存放方法的局部变量等,在堆区创建对象,用引用变量存放对象的地址,来使用对象。
下面是JVM里面的代码运行时的数据区:

为什么会有两个栈区?
本地方法栈执行的是由C/C++编写的方法。
虚拟机栈是执行的Java的方法的。
我们今天只用到堆区和虚拟机栈。
这里定义一个整型数组:
int[] a = new int[]{1,2,3,4,5};
int[] 是引用类型,a是引用变量,又称引用,new是创建新对象,后面是创建的新对象,它们在内存中存储如下:

引用变量a先在栈区申请一块空间,a是引用变量存放的是对象的地址,new创建的对象存放在堆区,a存放的地址,指向堆区里面创建的数组对象。
1. 一个引用变量只能指向一个对象。
2. 引用变量初始化赋值为null时,引用变量不指向任何对象。
3. 假设两个引用变量a 和 b,a=b的含义是:a指向的对象变成b指向的对象
4. 引用类型的引用变量存放的是对象的地址。
在Java中数组可以作为返回值,也可以作为方法的参数:
例如:
public static int[] arr(int[] a) {
int[] b = new int[a.length];
for(int i = 0;i < a.length;i++) {
b[i] = a[i];
return b;
}
2.6 关于null
null 在Java中被称为空引用,也就是不指向任何一个对象:
int[] a = null;
该引用不能进行读写操作,或者.length操作等,如果使用就会报错:
null相当于C语言中的NULL指针,表示的是一个无效的内存。
2.7 数组转字符串
在Java中有一个名为Arrays的类,里面有很多对数组处理的方法,Arrsys类里面的toString(数组名)的方法,能帮助我们快速的将数组转换成字符串:
public static void main(String[] args) {
//数组转字符串
int[] a = new int[]{1, 2, 3, 4, 5};
String b = Arrays.toString(a);
System.out.println(b);
}
当然我们也可以自己书写一个将数组转换为字符串的方法:
public static void main(String[] args) {
int[] a = new int[]{1,3,5,7,9};
String b = myToString(a);
System.out.println(b);
}
public static String myToString(int[] a) {
String arr = "[";
for (int i = 0; i < a.length; i++) {
arr += a[i];
if(i != a.length-1) {
arr += ", ";
}
}
arr += "]";
return arr;
}
2.8 数组元素的查找
方法一:顺序查找
一次遍历数组中的每个元素,知道遇到要查找的元素,返回元素下标。
public static void main(String[] args) {
//查找数组中的元素,返回下标
int[] a = new int[]{1,2,3,4,5};
int b = 3;
System.out.println(find(a,b));
}
public static int find(int[] a,int b) {
for (int i = 0; i < a.length; i++) {
if(b == a[i]) {
return i;
}
}
return -1;
}
方法二:二分查找
二分查找的前提是数组元素是有序的,一次检查一半的元素,直到查找到元素,返回下标。
public static int fingOne(int[] a,int b) {
int left = 0;
int right = a.length - 1;
while(left <= right) {
int mid = (left + right) / 2;
if(b > a[mid]) {
left = mid + 1;
}else if(b < a[mid]) {
right = mid - 1;
}else {
return mid;
}
}
return -1;
}
方法三:系统自带的二分查找方法
int[] a = new int[]{1,2,3,4,5};
int c = Arrays.binarySearch(a,3);
System.out.println(c);
用到Arrays类里面的binarySearch(数组名,查找元素)方法 ,返回查找的数组下标,如果数组中没有查找元素,则返回 -(最后一次二分查找左下标 + 1)。
该方法的重载还可以实现指定数组返回进行二分查找元素:
int[] a = new int[]{1,2,3,4,5};
int d = Arrays.binarySearch(a,1,3,3);
System.out.println(d);
Arrays.binarySearch(数组名,范围开始下标,范围结束下标,查找元素);
从数组下标范围 [1,3)里面查找3元素,返回下标。
2.9 数组的排序
方法一:冒泡排序
升序:对数组中的元素从开始依次相邻两个进行比较;大的数后移,直到比较到最后两个数结束,数组中最大的数就在最后一个位置。循环往复,最后完成数组的升序排列:
public static void main(String[] args) {
//冒泡排序(升序)
int[] a = new int[]{1,22,5,33,66,55,9};
mysort(a);
System.out.println(Arrays.toString(a));
}
public static void mysort(int[] a) {
boolean b = true;
//轮数
for (int i = 0; i < a.length-1; i++) {
for (int j = 0; j < a.length-1-i; j++) {
if(a[j] > a[j+1]) {
int tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
b = false;
}
}
if(b == true) {
return;
}
}
return;
}
方法二:Java自带的方法
Arrays类里面的.sort(数组名)方法,默认将数组内容升序排列:
int[] a = new int[]{1,22,5,33,66,55,9};
Arrays.sort(a);
System.out.println(Arrays.toString(a));
2.10 数组的拷贝
方法一:
自己创建方法实现
public static void main(String[] args) {
//数组的拷贝
int[] a = new int[]{1,2,3,4,5};
int[] b = myCopyArray(a);
System.out.println(Arrays.toString(b));
}
public static int[] myCopyArray(int[] a) {
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
b[i] = a[i];
}
return b;
}
方法二:
Java中自带的方法
Arrays类中的copyOf(拷贝的数组名,新数组的长度);
int[] a = new int[]{1,2,3,4,5};
int[] c = Arrays.copyOf(a,a.length);
System.out.println(Arrays.toString(c));
Arrays类里面还有一种方法可以指定数组范围拷贝:copyOfRange(拷贝的数组名,拷贝开始的下标,拷贝结束的下标);
int[] a = new int[]{1,2,3,4,5};
int[] d = Arrays.copyOfRange(a,2,4);
System.out.println(Arrays.toString(d));
注意:拷贝方法的底层方法代码由C/C++代码书写,被关键字native修饰的方法是由C/C++代码书写的,运行效率高,查看不了源代码。
2.11 数组逆序
将数组中的元素逆序输出:
public static void main(String[] args) {
//数组逆序
int[] a = new int[]{1,2,3,4,5};
move(a);
System.out.println(Arrays.toString(a));
}
public static void move(int[] a) {
int left = 0;
int right = a.length - 1;
while(left < right) {
int tmp = a[left];
a[left] = a[right];
a[right] = tmp;
left++;
right--;
}
}
2.12 Arrays类部分方法
查找数组指定元素(二分查找)
Arrays.binarySearch(数组名,查找元素);返回查找元素下标,若不存在查找元素,返回最后一次二分查找的左下标 + 1 取负数。
//查找数组指定元素
int[] a = new int[]{1,2,3,4,5};
int b = Arrays.binarySearch(a,4);
int c = Arrays.binarySearch(a,2,4,3);
System.out.println(b);
System.out.println(c);
数组的拷贝
Arrays.copyOf(拷贝的数组名,新数组的大小);返回拷贝的新数组。
int[] a = new int[]{1,2,3,4,5};
int[] c = Arrays.copyOf(a,a.length);
System.out.println(Arrays.toString(c));
Arrays.copyOfRange(拷贝的数组名,拷贝开始下标,拷贝结束下标);拷贝数组指定范围的数据到新数组。
int[] a = new int[]{1,2,3,4,5};
int[] d = Arrays.copyOfRange(a,2,4);
System.out.println(Arrays.toString(d));
判断两个数组是否相等
Arrays.equals(数组1,数组2);比较数组1和数组2里面的内容是否相等。相等返回true,不相等返回false。
//比较两个数组是否相等
int[] arr1 = new int[]{1,2,3,4,5};
int[] arr2 = new int[]{1,2,3,4,5};
boolean d = Arrays.equals(arr1,arr2);
System.out.println(d);
数组的赋值
Arrays.fill(数组名,值);将值赋值给数组的所有元素。
//数组赋值
int[] arr3 = new int[]{1,2,3,4,5};
Arrays.fill(arr3,6);
System.out.println(Arrays.toString(arr3));
fill方法的重载:Arrays.fill(数组名,赋值开始坐标,赋值结束坐标,值);指定数组范围赋值。
//数组赋值
int[] arr3 = new int[]{1,2,3,4,5};
Arrays.fill(arr3,2,4,6);
System.out.println(Arrays.toString(arr3));
数组的排序(升序)
Arrays.sort(数组名);对数组内的元素进行升序排列。
int[] a = new int[]{1,22,5,33,66,55,9};
Arrays.sort(a);
System.out.println(Arrays.toString(a));
数组转换成字符串
Arrays.toString(数组名);将数组转换成字符串[1,2,3,4,5]。
//数组转换成字符串
int[] arr4 = new int[]{1,2,3,4,5};
System.out.println(Arrays.toString(arr4));
二维数组转换成字符串
Arrays.deepToString(数组名) ;将二维数组转换成[ [1,2,3],[4,5,6] ]。
//二维数组转换成字符串
int[][] a = new int[][]{{1,2,3},{4,5,6}};
System.out.println(Arrays.deepToString(a));
3. 二维数组
3.1 二维数组的定义和初始化
下面是定义并初始化数组的写法:
int[][] a = new int[2][3];
int[][] b = new int[][]{{1,2,3},{4,5,6}};
int[][] c = {{1,2,3},{4,5,6}};
int[][] d;
d = new int[2][3];
int[][] f;
f = new int[][]{{1,2,3},{4,5,6}};
3.2 数组的遍历
二维数组是特殊的一维数组,假设二维数组int[][] arr = new int[][]{{1,2,3},{4,5,6,}},arr指向的对象是一维数组,里面存放两个一维数组对象的地址,而两个地址位置分别是两个一维数组。
关系如下图:

方法一:循环遍历
public static void main(String[] args) {
int[][] a = new int[][]{{1,2,3},{4,5,6}};
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
方法二:for-each遍历
public static void main(String[] args) {
int[][] a = new int[][]{{1,2,3},{4,5,6}};
for(int[] b : a) {
for(int c : b) {
System.out.print(c + " ");
}
System.out.println();
}
}
方法三:Java自带的方法
Arrays.deepToString(数组名);作用是将二维数组转换成字符串
System.out.println(Arrays.deepToString(a));
打印结果:

3.3 不规则二维数组
Java中定义数组时不可以省略行的值,可以省略列的值:
public static void main(String[] args) {
int[][] a = new int[2][];
a[0] = new int[3];
a[1] = new int[4];
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
上面数组a就是不规则数组,第一行有三列,第二行有四列。
打印出来是:

在堆中存储如下:

更多推荐

所有评论(0)