【黑马Java基础】1、数组,方法

数组

数组的定义与访问

静态初始化数组

定义数组时直接给数组赋值

//正常版本
int[] ages = new int[]{12,24,36};
//简化版本
int[] ages = {12,24,36};
  • 什么类型的数组只能存放什么类型的数据。

  • int[] ages = {12,24,36};

计算机中的程序都是在内存中执行的,计算机遇到代码之后会在内存中开辟一块空间,但暂时不装东西,会等到等号右边的东西进来。右边的代码也会新开辟一块区域,分三块存储(12,24,36)。然后右边会把数组地址交给左边的数组变量,用数据变量指向数组,然后进行访问。

  • 对象可以理解为就是个东西
int[] ages = new int[]{121, 234, 234};
System.out.println(ages);
//响应结果
[I@afb5f4df
Process finished with exit code 0
 //[代表是数组的地址,I代表是Int类型数组,@在哪个地址,在afb5f4df这个地址

注意:数组变量名中存储的是数组在内存中的地址,数组是引用数据类型

🧙‍♂️数组的访问

取值、赋值、数组的长度属性

数组名[索引] 索引可以理解为就是数组里的第几个
索引就是数组中的编号
//取值
    System.out.println(ages[0]);
//赋值
    ages[1] = 900;
    System.out.println(ages[1]);
//响应结果
121
900

Process finished with exit code 0
//数组的长度属性:length
System.out.println(ages.length);

//响应结果
3

Process finished with exit code 0
  • 技巧:获取非空数组的最大索引:arr.length-1

  • 如果访问数组时,使用的索引超过了数组的最大索引,会提示:索引越界的bug

🧙‍♂️数组的遍历
  • 遍历就是一个一个访问一遍容器中的数据。

  • 为什么要遍历?求和、元素搜索、找最大值最小值

  • 怎么遍历数组? 用for循环

int[] ages = new int[]{12,23,36};

        for (int i = 0; i < ages.length; i++) {
            System.out.println(ages[i]);
        }
//响应结果:
12
23
36

Process finished with exit code 0

技巧:编码的时候写ages.fori一回车就可以了

动态初始化数组

定义数组时先不存入具体的元素值,只确定数组存储的数据类型和数组长度

数据类型[] 数组名 = new 数据类型[长度];
int[] arr = new int[3];
//后赋值
arr[0] = 10;
System.out.println(arr[0]);
  • 提示:静态初始化和动态初始化数组的写法是独立的,不能混用

    int[] arr = new int[3]{12,23,34}; 就是错的!

//动态初始化数据没有放数据之前,初始值是0
int[] arr = new int[3];
      System.out.println(arr[0]);
      System.out.println(arr[1]);
      System.out.println(arr[2]);
//相应结果:
0
0
0

Process finished with exit code 0
//往数组里存入数据
int[] arr = new int[3];
        arr[0] =11;
        arr[1] =22;
        arr[2] =33;

        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
//
11
22
33

Process finished with exit code 0

在这里插入图片描述

案例

某歌唱比赛,需要开发一个系统,可以录入六个评委的打分,录入完毕后立即输出平均分作为选手得分。

public static void main(String[] args) {
        int[] grades = new int[6];
        Scanner sc = new Scanner(System.in);  //准备一个扫描器
        int total = 0;

        for (int i = 0; i < grades.length; i++) {
            System.out.println("输入第" + (i+1) + "位评委的分数:");
            int scores = sc.nextInt();      //接收数据
            grades[i] =scores;       //把数据存起来
        }

        for (int i = 0; i < grades.length; i++) {
            total += grades[i];
        }
        System.out.println("总分为:" + total);
    }
//响应结果:
输入第1位评委的分数:
5
输入第2位评委的分数:
6
输入第3位评委的分数:
7
输入第4位评委的分数:
8
输入第5位评委的分数:
9
输入第6位评委的分数:
10
总分为:45

Process finished with exit code 0

两种数组定义的方法适合什么业务场景?

动态初始化:适合开始不确定具体元素值,只知道元素个数的业务场景。

静态初始化:适合一开始就知道要存入哪些元素值的业务场景

数组在计算机中的执行原理

数组的执行原理,java程序的执行原理

运行一个java程序,主要看JVM中包含的3块内存区域:方法区、栈内存、堆内存

程序都是在计算机中的内存中执行的,Java程序编译之后会产生class文件,
在这里插入图片描述

这个class文件提取到内存中正在运行的JVM虚拟机里面执行

在这里插入图片描述

Java为了便于虚拟机执行程序,将虚拟机中的这块内存区域进行划分,划分成方法区、栈、堆、本地方法栈、程序计数器。

Java程序在计算机中的执行过程,主要通过方法区、栈、堆这三块区域配合执行的

  • 方法区是放编译后的class文件(字节码文件)的,先加载到方法区里。

  • 栈内存是方法运行时所进入的内存。由于变量是在方法里的,所以变量也在这片区域里。执行main方法时,是把main方法提到栈里进行执行。

  • 堆内存里放的都是new出来的东西,这些东西会在堆内存中开辟空间并产生地址。

在这里插入图片描述

数组在计算机中的执行原理:

在这里插入图片描述

1.首先程序执行的时候,程序的class文件会被提取出来,到方法区里。

2.会把main方法加载到栈里执行,此时正式执行第一行代码

3.第一行在定义一个基本类型变量,这个变量会在栈里开辟空间,并存储数据10。

4.接着执行第二行代码,输出变量a,把数据10直接打印出来。

5.第三行代码时,会在栈内存开辟arr变量的空间,一开始变量中没有存储数据

6.接着会执行等号右边的代码,右边的代码相当于是New一个数据对象,所以会放在堆内存中,因此会在堆内存中开辟一个空间。这个空间会分成三个等分的区域,第一个区域存11,第二个区域存22,第三个区域存33。

7.然后将地址信息赋值给arr,再arr指向数组对象

8.接着第四行,输出引用类型的变量,arr变量里存储的是右边数组对象的地址,所以输出地址。

9.第五行,通过arr变量,可以找到数组对象。再通过申请索引1,定位到第二个元素,输出22

10.第6 7 8行,通过arr变量找到数据对象以及索引,改数。第9 10 11行同理。

多个变量指向同一个数组的问题

//声明一个数组arr1
int[] arr1 = {11,22,33};
//把int类型的数组变量arr1赋值给int类型的数组变量arr2
int[] arr2 = arr1;

System.out.println(arr1);
System.out.println(arr2);
//响应结果:
[I@81ed48b1
[I@81ed48b1

Process finished with exit code 0

多个变量指向同一数组对象:(其实赋值的是数组的地址,所以指向的一样)

int[] arr1 = {11,22,33};
int[] arr2 = arr1;

arr2[1] = 99;
System.out.println(arr1[1]);
//响应结果:
99

Process finished with exit code 0

注意:如果某个数组变量存储的地址是null,那么该变量将不再指向任何数组对象

arr2 = null; //把Null赋值给arr2
System.out.println(arr2);  //null
System.out.println(arr2[0]);   //会出异常
System.out.println(arr2.length);   //会出异常

//响应结果
null
Exception in thread "main" java.lang.NullPointerException
	at ArrayDemo7.main(ArrayDemo7.java:15)

Process finished with exit code 1

java.lang.NullPointerException空指针异常

代码量:5000行(入门) 20000行(工作)

专项训练: 数组常见案例

1.数组求最值

定义一个数组(静态),定义一个变量用于记录最终的最大值(建议存储数组的第一个元素值作为参照)

public static void main(String[] args) {
        int[] faceScores = new int[]{15, 900, 1000, 2000, 950, -5};
        int max = faceScores[0];
        int num = 0;

        for (int i = 0; i < faceScores.length; i++) {
            if (faceScores[i] > max) {
                max = faceScores[i];
                num = i;
            }
        }
        
        System.out.println("第" + num + "位分数最高,分数为:" + max);
    }
//响应结果3位分数最高,分数为:2000

Process finished with exit code 0

2.数组反转

某个数组有5个数据:10,20,30,40,50,请将这个数组中的数据进行反转。

[10,20,30,40,50] 反转后 [50,40,30,20,10]

分析:数组的反转操作实际上就是依次前后交换数据

//单指针
public static void main(String[] args) {
        //数组反转
        int[] arr = new int[]{10,20,30,40,50};
        int temp = 0;

        for (int i = 0; i < arr.length/2; i++) {
            temp = arr[arr.length-(i+1)];
            arr[arr.length-(i+1)] = arr[i];
            arr[i] = temp;
        }
        
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
//响应结果:
50
40
30
20
10

Process finished with exit code 0
//双指针
public static void main(String[] args) {
        //数组反转
        int[] arr = new int[]{10, 20, 30, 40, 50};
        int temp = 0;

        for (int i = 0, j = arr.length - 1; i < j; i++,j--) {
                temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
        }

        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
//响应结果:
50
40
30
20
10

Process finished with exit code 0

3.随机排名

某公司开发部5名开发人员,要进行项目进展汇报演讲,现在采取随即排名后进行汇报。请先依次录入5名员工的工号,然后展示出一组随机的排名顺序。

分析:在程序中录入5名员工的工号存储起来(使用动态初始化数组的方式);依次遍历数组中的每个数据;每遍历到一个数据,都随机一个索引值出来,让当前数据与该索引位置处的数据进行交换。

public static void main(String[] args) {
        //随机排名
        int[] codes = new int[5];
        int temp = 0;
        Scanner sc = new Scanner(System.in);

        for (int i = 0; i < codes.length; i++) {
            System.out.println("请输入第" + (i+1) + "名员工的工号");
            int code = sc.nextInt();
            codes[i] = code;
        }

        Random r = new Random();
        for (int i = 0; i < codes.length; i++) {
            int index = r.nextInt(codes.length);
            temp = codes[index];
            codes[index] = codes[i];
            codes[i] = temp;

        }

        for (int i = 0; i < codes.length; i++) {
            System.out.println(codes[i]);
        }

    }

tip:随机

Random r = new Random();
int index = r.nextInt(codes.length);

tip:输入

Scanner sc = new Scanner(System.in);
int code = sc.nextInt();
codes[i] = code;

Debug工具的使用

IDEA自带的断点调试工具,可以控制代码从断点开始一行一行的执行,然后详细观看程序执行的情况。

在这里插入图片描述

方法

方法的定义

方法是一种语法结构,它可以把一段代码封装成一个功能,以便重复调用

修饰符 返回值类型 方法名(形参列表){
    方法体代码(需要执行的功能代码)
        return 返回值;
}
public class MethodDemo1 {
    public static void main(String[] args) {
        int rs = sum(10, 20);
        System.out.println(rs);
    }

    public static int sum(int a, int b) {
        int c = a+b;
        return c;
    } 
}
//响应结果:
30

Process finished with exit code 0

方法如何执行:方法定义后,必须调用才可以跑起来,调用格式:方法名(…);

注意:

  • 方法的修饰符:暂时都用public static修饰。

  • 方法申明了具体的返回值类型,内部必须使用return返回对应类型的数据。

  • 形参列表可以有很多个,甚至可以没有;如果有多个形参必须用”,“隔开,且不能给初始化值。

//无参数,无返回值的方法
public class MethodDemo1 {
    public static void main(String[] args) {
        printHello();
        System.out.println("==============");
        printHello();
    }

    //无参数,无返回值的方法
    public static void printHello(){
        for (int i = 0; i < 3; i++) {
            System.out.println("Hello World");
        }
    }
}
//响应结果:
Hello World
Hello World
Hello World
==============
Hello World
Hello World
Hello World

Process finished with exit code 0
//有参数,无返回值的方法
public class MethodDemo1 {
    public static void main(String[] args) {
        printHello(2);

    }

    //有参数,无返回值的方法
    public static void printHello(int n){
        for (int i = 0; i < n; i++) {
            System.out.println("Hello World");
        }
    }
}
//响应结果:
Hello World
Hello World
    
Process finished with exit code 0

注意:

  • 如果方法不需要返回结果,返回值类型必须声明成void(),此时方法内部不可以使用return返回数据。
  • 方法如果不需要接收数据,则不需要定义形参,且调用方法时也不可以传数据给方法了。
  • 没有参数,且没有返回值类型(void)申明的方法,称为无参数、无返回值的方法,以此类推。

方法使用时的常见问题

  • 方法在类中的位置放前放后无所谓,但一个方法不能定义在另一个方法里面。

  • 方法的返回值类型写**void(无返回申明)**时,方法内不能使用return返回数据,如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据。

  • return语句的下面,不能编写代码,属于无效的代码,执行不到这儿。

  • 方法不调用就不会执行,调用方法时,传给方法的数据,必须严格匹配方法的参数情况。

  • 调用有返回值的方法,有3种方式:1、可以定义变量接收结果 2、或者直接输出调用 3、甚至直接调用;

    //1
       int rs = sum(10,20);
       System.out.println(rs);
    //2
       System.out.println(sum(1,2));
    //3
       sum(3,4);
    
  • 调用无返回值的方法,只有1种方式:1、只能直接调用。

printHello();

方法的案例

设计方法的技巧,主要关注三个方面:

  1. 方法是否需要接收数据进行处理?
  2. 方法是否需要返回数据
  3. 方法要处理的业务

一、求1-n的和

import java.util.Scanner;

public class MethodDemo2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int score = sc.nextInt();
        int rs = add(score);
        System.out.println(rs);
    }

    public static int add(int n){
        int sum = 0;
        for (int i = 1; i <= n ; i++) {
            sum += i;
        }
        return sum;
    }
}
//响应结果:
3
6

Process finished with exit code 0

二、判断一个整数是奇数还是偶数,并把判断的结果输出出来

public class MethodDemo3 {
    public static void main(String[] args) {
        ifodd(7);
    }

    public static void ifodd(int a) {
        if (a % 2 == 0) {
            System.out.println("输入的" + a + "是偶数");
        } else {
            System.out.println("输入的" + a + "是奇数");
        }
    }
}
//响应结果:
输入的7是奇数

Process finished with exit code 0

方法在计算机中的执行原理

  • 方法被调用的时候,是进入到栈内存中运行。

-方法为什么要在栈中运行自己?

保证一个方法调用完另一个方法后,可以回来

java的参数传递机制

基本类型的参数传递

java的参数传递机制都是:值传递

  • 所谓的值传递:指的是在传递实参给方法的形参时,传输的是实参变量中存储的值的副本

实参:在方法内部定义的变量。

形参:定义方法时 “(…)” 中声明的参数

public class MethodDemo4 {
    public static void main(String[] args) {
        int a = 10;
        change(a);     //这步执行完之后,从栈中出去了,所以下一行里a还是10
        System.out.println("main:" + a);  //10
    }

    public static void change(int a) {
        System.out.println("change1:" + a);  //10
        a = 20;
        System.out.println("change2:" + a);   //20
    }
}
//响应结果:
change1:10
change2:20
main:10

Process finished with exit code 0

引用类型的参数传递

public class MethodDemo5 {
    public static void main(String[] args) {
        int[] arrs = new int[]{10, 20,30};
        change(arrs);
        System.out.println("main:" + arrs[1]);
    }

    public static void change(int[] arrs){
        System.out.println("方法内1:"  + arrs[1]);
        arrs[1] = 222;
        System.out.println("方法内2:"  + arrs[1]);
    }
}
//响应结果:
方法内120
方法内2222
main:222    //因为数组传递的是地址变量

Process finished with exit code 0

基本类型和引用类型的参数在传递的时候有什么不同?

  • 都是值传递
  • 基本类型的参数传输存储的是数据值
  • 引用类型的参数传递存储的是地址值

参数传递的案例

引用类型参数传递的相关案例(数组的传递)

案例一:打印int类型的数组内容

需求:输出一个int类型的数组内容,要求输出的格式为:[11,22,33,44,55]

分析:

  1. 方法是否需要接收数据进行处理?

    需要接收一个int类型的数组,因此形参声明为:int[] arr

  2. 方法是否需要返回数据

    方法内部直接输出数组内容即可,无需返回,因此返回值类型声明为:void

  3. 方法内部的业务?

    遍历数组,并输出相应的内容

public class MethodDemo6 {
    public static void main(String[] args) {
        int[] arr = new int[]{11, 22, 33};
        printArray(arr);

        int[] arr2 = null;
        printArray(arr2);
    }

    public static void printArray(int[] arr) {

        if (arr == null) {
            System.out.println(arr);   //null
            return;   //跳出当前方法(break只能跳出循环,不能跳出方法,方法执行到return会结束方法)
        } else {
            System.out.print("[");
            for (int i = 0; i < arr.length; i++) {
//            if (i == arr.length-1){
//                System.out.print(arr[i]);
//            }else {
//                System.out.print(arr[i] + ",");
//            }
                //优化:
                System.out.print(i == arr.length - 1 ? arr[i] : arr[i] + ",");
            }
            System.out.println("]");
        }
    }
}
//响应结果:
[11,22,33]
Process finished with exit code 0
案例二:比较两个int类型的数组是否一样

需求:如果两个int类型的数组,元素个数,元素顺序和内容是一样的,我们就认为这两个数组是一模一样的

  1. 方法是否需要接收数据进行处理?

    需要接收2个int类型的数组,因此形参声明为:int[] arr1,int[] arr2

  2. 方法是否需要返回数据

    方法判断完后需要返回:true, false,因此返回值类型声明为boolean类型

  3. 方法内部的业务?

    判断两个数组内容是否一样

public class MethodDemo7 {
    public static void main(String[] args) {
        int[] arr1 = null;
        int[] arr2 = null;
        System.out.println(equals(arr1, arr2));

        int[] arr11 = null;
        int[] arr22 = {10,20,30};
        System.out.println(equals(arr11, arr22));

        int[] arr111 = {10,20,30,40};
        int[] arr222 = {10,20,30};
        System.out.println(equals(arr111, arr222));

        int[] arr1111 = {10,20,31};
        int[] arr2222 = {10,20,30};
        System.out.println(equals(arr1111, arr2222));

        int[] arr11111 = {10,20,30};
        int[] arr22222 = {10,20,30};
        System.out.println(equals(arr11111, arr22222));

    }

    public static boolean equals(int[] arr1, int[] arr2) {
        //1.判断arr1和arr2是否都是null
        if (arr1 == null && arr2 == null) {
            return true;
        }
        //2.判断arr1是null,或者arr2是null
        if (arr1 == null || arr2 == null) {
            return false;
        }
        //3.判断2个数组的长度是否一样,如果长度不一样,直接返回false
        if (arr1.length != arr2.length) {
            return false;
        }
        //4.两个数组的长度是一样的,接着比较它们的内容是否一样
        for (int i = 0; i < arr1.length; i++) {
            //判断当前位置2个数组的元素是否不一样,不一样直接返回false
            if (arr1[i] != arr2[i]) {
                return false;
            }
        }
        return true;
    }
}
//响应结果:
true
false
false
false
true

Process finished with exit code 0

👆注意这个方法里层层筛的思想!!!

方法重载

方法重载:同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法称为方法重载。

public class MethodOverload {
    public static void main(String[] args) {
        test();
        test1(100);
    }

    public static void test(){
        System.out.println("===test1===");
    }

    public static void test1(int a){
        System.out.println("===test2====" + a);
    }
}
//响应结果:
===test1===
===test2====100

Process finished with exit code 0

注意事项:

  • 一个类中,只要一些方法的名称相同形参列表不同,那么他们就是方法重载了,其他的都不管(如:修饰符,返回值类型是否一样都无所谓)
  • 形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称

方法重载的应用场景:

开发中我们经常需要为处理一类业务,提供多种解决方案,此时用方法重载来设计是很专业的。

例如:开发武器系统,功能需求如下:
①可以默认发一枚武器 ②可以指定地区发射一枚武器 ③可以指定地区发射多枚武器

public class MethodDemo8 {
    public static void main(String[] args) {
        fire();
        fire("Am");
        fire("Am", 5);
    }

    public static void fire(){
        System.out.println("发射一枚武器");
    }

    public static void fire(String country){
        System.out.println("向" + country + "发射一枚武器");
    }

    public static void fire(String country, int num){
        System.out.println("向" + country + "发射"+ num + "枚武器");
    }
}
//响应结果:
发射一枚武器
向Am发射一枚武器
向Am发射5枚武器

Process finished with exit code 0

单独使用return关键字

return; 可以用在无返回值的方法中,作用是:立即跳出并结束当前方法的执行

public class MethodDemo9 {
    public static void main(String[] args) {

        System.out.println("程序开始");
        division(10,0);
        System.out.println("程序结束");

    }

    public static void division(int a, int b){
        if (b == 0){
            System.out.println("您输入的分母为0");
            return;
        }
        System.out.println("结果为:" + a/b);
    }
}
//响应结果:
程序开始
您输入的分母为0
程序结束

Process finished with exit code 0

注意:

return; 跳出并立即结束所在方法的执行。
break; 跳出并结束当前所在循环的执行。
continue; 结束当前所在循环的当此继续,进入下一次执行。

  • 27
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值