📎前言
✨本篇文章是博主第一次通过对语言的系统总结完成的正式的博客,希望大家可以提供宝贵的意见,我定会积极采纳~ 后续我也将持续更新自己的学习记录,希望大家关注支持!✨
🚀🚀系列专栏:【JavaSE】
📻📻本章内容:对Java方法的初识与数组的基础应用
文章目录
📌方法的概念及使用
🍔 什么是方法
方法就是一个代码片段. 类似于 C 语言中的 “函数”。方法存在的意义:
- 能够模块化的组织代码.
- 做到代码被重复使用, 一份代码可以在多个位置使用.
- 让代码更好理解更简单.
- 直接调用现有方法开发, 不必重复
eg:要用Java语言开发一款日历,要想判断某一年份是否为闰年,则有如下代码:
int year = 1900;
if((0 == year % 4 && 0 != year % 100) || 0 == year % 400){
System.out.println(year+"年是闰年");
}else {
System.out.println(year+"年不是闰年");
}
那么该如何将其定义为一个方法呢?
🍕 方法的定义
修饰符 返回值类型 方法名称([参数类型 形参 …]) {
方法体代码;
[return 返回值];
}
将上面判断闰年的例子用方法定义后可以得到如下的代码
public class Method {
//方法的定义
public static boolean isLeapYear(int year) {
if((year%4==0&&year%100!=0)||year%400==0) {
return true;
} else {
return false
}
}
}
eg2:实现两个整数相加的方法
public class Method {
public static int add(int x,int y) {
return x+y;
}
}
【注意事项】
- 返回值类型:如果方法有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void
- 方法名字:采用小驼峰命名
- 参数列表:如果方法没有参数,()中什么都不写,如果有参数,需指定参数类型,多个参数之间使用逗号隔开
- 方法体:方法内部要执行的语句
- 在java当中,方法必须写在类当中
- 在java当中,方法不能嵌套定义
- 在java当中,没有方法声明一说
🍟 方法调用的执行过程
调用方法—>传递参数—>找到方法地址—>执行被调方法的方法体—>被调方法结束返回—>回到主调方法继续往下执行
- 定义方法时,不会执行方法中的代码,只有被调用时才会被执行.
- 一个方法可以被多次调用
【代码示例】计算两个整数相加.
public class Test {
public static int add(int x,int y) {
System.out.println("调用add方法");
return x+y;
}
public static void main(String[] args) {
int a = 20;
int b = 10;
System.out.println("第一次调用方法之前");
int ret = add(a,b);//调用add()方法
System.out.println("第一次调用方法之后");
System.out.println("ret = "+ret);
System.out.println("=========");//分隔符
System.out.println("第二次调用方法之前");
ret = add(30, 50);//第二次调用add()方法
System.out.println("第二次调用方法之后");
System.out.println("ret = " + ret);
}
}
该代码直观的反映出方法调用与执行的顺序,执行结果如下:
🌭 实参和形参的关系
方法的形参相当于数学函数中的自变量,比如:1 + 2 + 3 + … + n的公式为sum(n)=(n+1)*n/2
Java语言中方法的形参就相当于sum函数中的自变量n,用来接收sum函数在调用时传递的值的。形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。
public class Test {
public static int getSum(int N) {
return (N+1)*N/2;
}
public static void main(String[] args) {
System.out.println(getSum(10));
System.out.println("===============");
System.out.println(getSum(100));
}
}
上述代码中,N即为getSum()方法的形式参数,而在main方法中调用时,“10”和“100”即为getSum()的实际参数。
注意:在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体
【代码示例】
public class Test {
public static void swap(int x,int y) {
x = 20;
y = 10;
int temp = 0;
temp = x;
x = y;
y = temp;
System.out.println("swap:x="+ x + " y=" + y);
}
public static void main(String[] args) {
int a = 20;
int b = 10;
swap(a,b);
System.out.println("main:a="+ a + " b=" + b);
}
//运行结果
swap:x=10 y=20
main:a=20 b=10
不难看到,在swap方法中,形参x和y的值发生了交换,而main方法中的值还保持着交换之前的值。 本篇的数组部分会提供解决方法
【原因分析】
实参a和b是main方法中的两个变量,其空间在main方法的栈(一块特殊的内存空间)中,而形参x和y是swap方法中的两个变量,x和y的空间在swap方法运行时的栈中,因此:实参a和b与形参x和y是两个没有任何关联性的变量,在swap方法调用时,只是将实参a和b中的值拷贝了一份传递给了形参x和y,因此对形参x和y操作不会对实参a和b产生任何影响
【解决办法】: 传引用类型参数(此处利用数组完成)
public class Test {
public static void main(String[] args) {
int[] arr = {10, 20};
swap(arr);
System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
}
public static void swap(int[] arr) {
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
}
输出结果:
📌方法的重载
🥐为什么要进行重载
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int ret = add(a, b);
System.out.println("ret = " + ret);
double a2 = 10.5;
double b2 = 20.5;
double ret2 = add(a2, b2);
System.out.println("ret2 = " + ret2);
}
public static int add(int x, int y) {
return x + y;
}
}
// 编译出错
Test.java:13: 错误: 不兼容的类型: 从double转换到int可能会有损失
double ret2 = add(a2, b2);
由上述代码不难看出,由于参数类型不匹配, 所以不能直接使用现有的 add 方法.因此需要进行方法的重载
🌮 方法重载的概念
在自然语言中,如果一词有多个含义,则说该词语被重载了。Java语言中类似,如果多个方法名字相同而参数列表不同,则说明这几种方法被重载了
【代码示例】
public class Test {
public static int add(int x,int y) {
return x+y;
}
public static double add(double x,double y) {
return x+y;
}
public static double add(double x,double y,double z) {
return x+y+z;
}
public static void main(String[] args) {
System.out.println(add(10, 20));
System.out.println(add(10.5,50.2));
System.out.println(add(1.5,2.5,3.6));
}
【注意事项】
- 方法名必须相同
- 参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
- 与返回值类型是否相同无关
📌递归
🥪递归的概念及条件
递归有两个过程,即“递”和“归”。递归过程中,方法不断的调用自己本身。而且一定需要一个终止条件。
例如求 N!
起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件.
可以把问题转换成 N! => N * (N-1)!
【递归的必要条件】
- 将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同
- 递归出口(避免造成死递归)
【代码示例】 递归求n的阶乘
public class Test {
public static int factor(int n) {
if(n==1)
return 1;
else
return n * factor(n-1);
}
public static void main(String[] args) {
int n = 5;
int ret = factor(n);
System.out.println("ret = "+ret);
}
//输出结果
ret = 120
【执行过程图】
全过程按(1)->(8)的顺序执行
🍞递归的练习
eg1:按顺序打印一个数字的每一位(如1234,打印出1 2 3 4);
public static void print(int n) {
if(n>9)
print(n/10);
System.out.print(n%10+" ");
}
public static void main(String[] args) {
print(1234);
}
eg2:递归求1+2+…+10
public static int sum(int num) {
if(num == 1) {
return 1;
}
return num+sum(num-1);
}
public static void main(String[] args) {
System.out.println(sum(10));
}
eg3:输入一个非负整数,返回组成它的数字之和.
public static int sum(int num) {
if(num<10)
return num;
else
return num % 10+sum(num/10);
}
public static void main(String[] args) {
System.out.println(sum(1234));
}
📌数组
🍘数组的基本概念
数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。就如同现实中的车库
在java中,包含6个相同类型元素的数组就如同上面6个连在一起的方格,从图中可以看出:
- 数组中存放的元素类型相同。
- 数组的空间是连在一起的。
- 每个空间都有自己的编号,且起始位置的下标为0.
🍙数组的创建与初始化
数组的创建
T[] 数组名 = new T[N];
T:表示数组中存放的元素类型。
N:表示数组的长度。
T[]:表示数组的类型。
int[] array1 = new int[10]; // 创建一个可以容纳10个int类型元素的数组
double[] array2 = new double[5]; // 创建一个可以容纳5个double类型元素的数组
String[] array3 = new double[3]; // 创建一个可以容纳3个字符串元素的数组
数组的初始化
数组的初始化主要分为 动态初始化与静态初始化。
1. 动态初始化:在创建数组时,直接指定数组中元素的个数。
int[] array = new int[10];
2. 静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定
语法格式:
T[] 数组名称 = {data1, data2, data3, …, datan};
int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9}; //“new int[]”可省略 下同。
double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = new String[]{"hello", "Java", "!!!"};
【注意事项】
- 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。
- 静态初始化时,{}中数据类型必须与[]前数据类型一致。
- 静态初始化可以简写,省去后面的new T[]。(编译器编译代码时仍会还原)
- 如果没有对数组初始化,数组中的元素有默认值。
- 如果数组中存储元素类型为基类类型,默认值为基类类型对应的默认值,比如:
类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0 |
float | 0.0f |
double | 0.0 |
char | /u0000 |
boolean | false |
- 如果数组中存储元素类型为引用类型,默认值为null
🥞数组是引用类型
内存是一段连续的存储空间,主要用来存储程序运行时的数据。
JVM对所使用的内存按照功能的不同进行了如上的划分。目前我们只关心堆和虚拟机栈两块空间。
基本类型变量与引用类型变量的区别
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。
public static void fuc() {
int a = 20;
int b = 10;
int[] arr = new int[]{1,2,3};
}
在上述代码中,a、b、arr,都是函数内部的变量,因此其空间都在main方法对应的栈帧中分配。
a、b是内置类型的变量,因此其空间中保存的就是给该变量初始化的值。
arr是数组类型的引用变量,其内部保存的内容可以简单理解成是数组在堆空间中的首地址。
从上图可以看到,引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象。有点类似C语言中的指针,但是Java中引用要比指针的操作更简单。
【补充】
Java当中局部变量在使用时必须进行初始化,代码示例如下
public static void main(String[] args) {
double a =0.0;
int[] arr = null;//(此处即表示不指向任何对象)
System.out.println(a);
System.out.println(arr);
}
//运行结果
0.0
null
如果再使用空指针赋值后的变量,就会空指针异常
public static void main(String[] args) {
int[] arr = null;
System.out.println(arr[0]);
}
🍤数组的应用场景
保存数据
public static void main(String[] args) {
int[] arr = new int[]{1,2,3};
for (int i = 0; i < arr.length; ++i) {//数组名.length表示数组的长度,可用来遍历数组
System.out.print(arr[i]+" ");
}
作为函数的参数
在介绍形参的部分我们提到了通过传引用参数来实现交换两个数的方法。代码如下:
public class Test {
public static void main(String[] args) {
int[] arr = {10, 20};
swap(arr);
System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
}
public static void swap(int[] arr) {
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
}
发现在swap方法内部修改数组的内容, 方法外部的数组内容也发生改变.
因为数组是引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的。
总结: 所谓的 “引用” 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝。
作为函数的返回值
【代码示例】
public class Test {
public static int[] fib(int n) {
if (n <= 0) {
return null;
}
int[] array = new int[n];
array[0] = array[1] = 1;
for (int i = 2; i < n; ++i) {
array[i] = array[i - 1] + array[i - 2];
}
return array;
}
public static void main(String[] args) {
int[] array = fib(10);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
🍰二维数组
二维数组本质上也是一维数组,不过每个元素又是一个一维数组
基本语法
数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
【代码示例】
public class Test {
public static void main(String[] args) {
int[][] arr = {
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
for (int row = 0; row < arr.length; row++) {
for (int col = 0; col < arr[row].length; col++) {
System.out.printf("%d ",arr[row][col]);
}
System.out.println(" ");
}
}
//执行结果
1 2 3 4
5 6 7 8
9 10 11 12
🎉总结
🎇到这里本篇文章就结束了,感谢大家的阅读。非常希望大家可以提出宝贵的建议!!
🎇本篇文章是博主对自己编程学习中所学知识的个人理解。日后我也将不断更新自己学习过程
🎇希望大家可以点赞+收藏+评论支持一下噢!
下篇内容我将正式从Java语言面向对象的特性方面进行总结,继续保持关注噢~