6-方法和数组
1 什么是方法
一段用来完成特定功能的代码片段
/**
* 我们定义的第一个方法
* 作用:输入 x 到 y之间的所有的偶数
* @param x
* @param y
*/
public static void printEven(int x,int y){
for (int i = x ; i <= y ; i++) {
if(i % 2 == 0){
System.out.println( i);
}
}
}
2 为什么使用方法
- 程序中多次使用到的功能
- 便于程序的阅读
- 提供程序的重用性
在其他语言中,方法又称为函数
3.方法的定义
3.1 方法的语法规则
访问修饰符 返回值类型 方法名称(参数类型 参数1 , 参数类型 参数2 ...){
方法体;
return 返回值;
}
访问修饰符: 暂时使用 public static
,后面我们会在面向对象的课程中详细介绍这部分的内容
返回值类型:该方法的返回结果的数据类型,可以是八大基本数据类型也可以是引用类型[后面介绍]
方法名称:自定义的,符合标识符的命名规则即可,见名知意
参数:方法实现需要的参数
【实参】:水果榨汁机案例中,具体放进榨汁机中的水果,比如 苹果,西瓜等。
【形参】:水果榨汁机案例中,这个机器在设计的时候定义的外部要给与的类型
方法体:就是完成特定功能的代码,具体根据需求来确定
返回值:方法特定功能的结果,通过过return返回给调用者的,哪里调用的就返回到哪里去
3.2 方法的具体实现
// 位置 5
public class FunDemo03 {
// 位置 1
public static void main(String[] args) {
// 位置 2
}
// 位置 3
}
// 位置 4
- 首先方法和方法是平级的关系,main方法也是一个方法,所以方法是不能写在main方法中的
- 方法只能定义在类以内。不能单独的写到类以外
- 一个类中可以包含任意个方法,没有先后顺序
4.方法重载
在一个类中可以定义有相同名称,但参数列表不同的多个方法,调用的时候会根据不同的参数列表类选择对应的方法。
参数列表不同:参数的个数,顺序,类型不同
重载的特点:
- 发生在同一个类中
- 方法名称相同
- 参数列表不同(类型、个数、顺序)
- 和返回类型没有关系
案例:
public class FunDemo08 {
/**
* 方法的重载
* 1.方法名称相同
* 2.方法参数列表不同
* 参数个数
* 参数类型
* 参数顺序
* @param args
*/
public static void main(String[] args) {
System.out.println(add(1,2));
System.out.println(add(2,3,4));
System.out.println(add(12.3,45.6));
System.out.println(add(2.3,6));
}
/**
* 两个int类型的求和
* @param a
* @param b
* @return
*/
public static int add(int a,int b){
return a + b;
}
public static double add(double d1 ,double d2){
return d1 + d2;
}
public static double add(double d1 ,int d2){
return d1 + d2;
}
public static double add(int d1 ,double d2){
return d1 + d2;
}
public static int add(int a ,int b,int c){
return a + b + c;
}
}
5.递归
什么是递归:方法中调用本地方法,自己调用自己。
递归条件:
- 自己调自己
- 有出口,不然死递归
- 构造方法不能递归(后面学面向对象会讲)
案例:n的阶乘计算
public class FunDemo11 {
/**
* 求n的阶乘 5 ! 5*4*3*2*1
* @param args
*/
public static void main(String[] args) {
//System.out.println(getFactorial(10));
System.out.println(getFactorialRecursion(10));
}
/**
* 通过递归的方式来实现N的阶乘计算
* 分析 递归的出口
* 5!=5*4!=5*4*3!
* @param num
* @return
*/
public static int getFactorialRecursion(int num){
if(num < 0){
return 0;
}
// 先确定递归的出口
if( num == 0 || num == 1){
return 1;
}else{
return num * getFactorialRecursion(num-1);
}
}
/**
* 普通的获取num的阶乘
* @param num
* @return
*/
public static int getFactorial(int num){
if(num <=0 ){
return 0;
}
int factorial = 1;
for( int i = 1 ; i <= num;i++){
factorial *= i;
}
return factorial;
}
}
6.数组
6.1一维数组
1.为什么要使用数组
问题:Java考试结束后,需要统计全班学员的平均分(30个人)。
解决方案:定义30个变量,然后相加求和,并计算平均分。
更好的解决方案:数组 数据容器
2.内存分配
2.1 硬盘
持久化我们的数据
2.2 内存
运行时
存储,在软件(程序)运行的时候开辟空间,软件运行结束后,内存中的数据就会消失
Java程序运行的时候,系统分配的内存
,Java程序是怎么利用的?
FunDemo01.java这个Java文件肯定是存储在硬盘上的。但是当我们通过javac FunDemo01.java --> FunDemo01.class -->
java FunDemo01 执行 这个过程中内存是怎么分配的?
2.3. Java程序的内存分区
内存划分的结构图
名称 | 描述 |
---|---|
方法区 | 又称为代码区/永久区,存放 代码、静态东西、常量池 |
堆 | 存放的是new 出来的东西 |
本地方法栈 | 和系统有关系,我们暂时不介绍 |
Java虚拟机栈 | 存放局部变量的 |
程序计数器 | 和CPU计算有关,暂时也不介绍 |
局部变量:方法体内定义的变量 或者 方法定义时声明的变量【形参】,局部变量使用前必须先赋值,不然会编译错误
案例
public class ArrayDemo01 {
// 定义一个全局变量
int sum = 30;
public static void main(String[] args) {
// 定义一个局部变量
int i = 10;
}
}
2.4 Java虚拟机栈的特点
- 先进后出(Firt in last out FILO),类似于子弹夹
- 栈区中的数据仅在作用域内有效,使用完毕之后立马自动释放
- 栈内的变量没有默认值,如果没有给出默认值就直接报错
2.5 堆区的特点
1.堆区中的每个变量都有默认值
byte short int long 默认的都是 0
float double 默认的 0.0
char 默认的是 ‘\u0000’ 就是一个空字符
boolean 默认值 false
引用类型 默认值是 null
2.凡是new
出来的东西都在堆区
开辟空间,堆区开辟的空间都会有地址值
3.在堆区中的对象,一旦使用完毕之后,不会立刻消失,会等待垃圾回收期空闲的时候自动回收
3.数组的初始化
3.1 数组的语法格式
数据类型[] 数组名 = new 数据类型[数组的长度];
数据类型 数组名[] = new 数据类型[数组的长度];
public static void main(String[] args) {
// 定义一个数组
int[] array1 = new int[5];
int array2[] = new int[10];
}
数组其实也一个变量,存储相同类型的一组数据
作用:告诉计算机数据类型是什么
特点:
- 数据类型相同
- 数组名实际上就是一个变量,既然是变量,那就必须先赋值在使用
- 数组的每一个元素既可以是基本数据类型,也可以是引用数据类型
A “张三” ,“李四” ,“王五”
B 9 , 99, “c”, 12
C 98.1 ,33.3 ,45
3.2 数组的内存分配
上面的数组的语法格式其实有两步组成
1.数组的声明
int[] array1;
声明的变量会在内存中划分一块合适的空间,栈区
2.数组的赋值
arra1 = new int[5];
将内存划分出来的一串连续的内存空间的地址赋值给了变量
3.3 数组的赋值
在前面介绍的 arra1 = new int[5];
数组中的每个元素会根据数组的类型赋予默认值,那么我们可以通过数组的下标来获取数组中的各个位置上的元素,在Java中数组的下标是从0
开始的,最大的下标 length-1
如果我们从数组中获取元素的下表超过的数组的长度会出错,下表越界
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
下标不能是负数
java.lang.ArrayIndexOutOfBoundsException: -1
我想要修改数组中对应位置中的元素
public static void main(String[] args) {
int i = 10;
// 定义一个数组
int[] array1 = new int[3];
array1[0] = 5;
array1[1] = 6;
array1[2] = 7;
System.out.println(array1[0]);
System.out.println(array1[1]);
System.out.println(array1[2]);
}
简化的初始化方式
在初始化的时候就为每个元素赋值,不需要指明长度
public static void main(String[] args) {
//int[] a1 = new int[7];
// 声明变量后直接将一个数组赋值给了这个变量
int a1[] = {1,2,3,4,5,6,7,8,9};
System.out.println(a1[0]);
System.out.println(a1[3]);
System.out.println(a1[4]);
System.out.println(a1[5]);
System.out.println(a1[6]);
}
注意事项:
- 标识符:数组的名称,用于区分不同的数组
- 数组元素:向数组中存放的数据
- 元素下标,从0开始,数据中的每个元素都可以通过下标来访问
- 元素类型:数组元素的数据类型
4. 数组的遍历
前面我们是通过下标一个个从数组中取出元素的,这种在数组中元素比较多的情况下,会比较麻烦这时我们可以考虑使用前面介绍的循环来实现。
public static void main(String[] args) {
//int[] a1 = new int[]{1,2,3,4,5,6,7,8,9};
int a1[] = {1,2,3,4,5,6,7,8,9};
// 通过遍历的形式获取数组中的每个元素
System.out.println(a1[0]);
System.out.println(a1[1]);
System.out.println(a1[2]);
System.out.println(a1[3]);
System.out.println(a1[4]);
System.out.println(a1[5]);
System.out.println(a1[6]);
System.out.println(a1[7]);
System.out.println(a1[8]);
//遍历
for(int i = 0 ; i < a1.length ; i ++){
System.out.println(a1[i]);
}
}
案例:计算5个学员的平均分
public class ArrayDemo05 {
/**
* 计算5个学员的平均分
*
* @param args
*/
public static void main(String[] args) {
double[] score = {67,89,87,68,54};
// 记录学员总分
double sum = 0;
for(int i = 0 ; i < score.length; i ++){
sum += score[i];
}
System.out.println("5个学员的平均分是:" + sum/5);
}
}
6.2二维数组
概念:本质上就是一个存放了一维数据的数组
语法规则:
//格式1:
数据类型[][] 变量名 = new 数据类型[m][n];
//m:表示一个二维数组中有m个一维数组
//n:每个一维数组中有n个元素
//格式2:
数据类型 变量名[][] = new 数据类型[m][n];
//格式3
数据类型[] 变量名[] = new 数据类型[m][n];
m必不可少,n可写可不写
/**
* 二维数组
* @param args
*/
public static void main(String[] args) {
int[] a = new int[4];
int[][] arr = new int[3][2];
int arr1[][] = new int[3][2];
int[] arr2[] = new int[3][2];
}
注意:Java中并没有真正意义上的二维数组,本质上就是一个存放了一维数组的数组
数组中的每个元素还是一个数组,那么二维数组中每一个元素的值应该是地址值
1.二维数组的静态初始化
// 一维数组中的静态初始化
int arr[] = new int[]{1,2,3,4,5,6};
int arr[] = {1,2,3,4,5,6};
2.二维数组遍历
import java.util.Arrays;
public class ArrayDemo09 {
public static void main(String[] args) {
int[][] arr = new int[][]{{11,22,33},{44,55},{66,77,88,99}};
arrayPrintToString(arr);
}
public static void arrayPrintToString(int[] ... arr){
for(int i = 0 ; i < arr.length ; i++){
//System.out.println(Arrays.toString(arr[i]));
// arr[i] 又是一个新的一维数组 那么我就可以按照一维数组的处理方式来处理了
for(int j = 0 ; j < arr[i].length; j++){
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
}
}
foreach循环效果
import java.util.Arrays;
public class ArrayDemo09 {
public static void main(String[] args) {
int[][] arr = new int[][]{{11,22,33},{44,55},{66,77,88,99}};
arrayPrintToString(arr);
}
public static void arrayPrintToString(int[] ... arr){
for(int[] x : arr){
for(int y : x){
System.out.print(y + "\t");
}
System.out.println();
}
}
}
案例:统计三个班级中的学员的成绩的平均分
package com.bobo.array;
public class ArrayDemo10 {
/**
* 1.统计三个班级中的学员的成绩的平均分
* @param args
*/
public static void main(String[] args) {
int score[][] = {{78,87,90,93,78},{67,76,84},{45,80}};
// 总分
int sum = 0 ;
int num = 0; // 记录总的学员数量
for(int[] ss:score){
for(int s:ss){
sum+=s;
num++;
}
}
System.out.println("统计获取总的平均分:"+sum/num);
}
}