day05-Java方法和数组

今天主要学习如下内容:
  1.方法定义,方法调用,方法重载等内容
  2. 数组相关内容,以及有数组初始化引出的
  3. Jvm的运行时数据区的内存模型相关知识

 

一、方法

  • 引入:

    文件上传是做一个电商网站所必不可少的功能,比如每一个商品都需要上传若干商品图片,网站上各种品牌都需要上传其logo,用户在注册时可以上传头像…

  假设你现在已经写了100行代码完成了文件上传功能,但问题是网站的很多地方都要使用这一功能,比如管理商品数据的商品服务,管理用户数据的用户信息服务等等。

  问题来了,这些地方都要使用文件上传的功能,怎么办呢?

    方案1

      在每个用到文件上传功能的地方重写这些100行代码 但是方案1会引发一系列的问题!!

    方案2

      复用这100行代码,将这些代码放在一个{}中,并给它们起个名字,通过名字来复用这段代码

 

  方法定义:方法就是完成特定功能的代码块(在有些其他语 言中,也被成为函数)

  • 方法定义的格式:

修饰符 方法返回值类型 方法名(参数1类型 参数1名称, 参数2类型 参数2名称, ……) {

方法体语句;

return 返回值;

}

方法定义的格式说明:

  修饰符:现在先认为是固定的 public static

返回值类型:方法体中的代码执行结果的数据类型

方法名 :标识符

参数 :类比数学中函数的自变量 z = f(x, y)

方法体:实现具体功能的语句结合

return:跳转控制关键字

返回值:方法执行的到的最终结果 注意: return 返回值;这句并非必须

 

如何写一个方法呢?

两个明确 :

    1. 返回值类型----- 明确功能结果的数据类型
    2. 参数列表   --- -- 明确有几个参数,以及参数的类型

学习了方法的定义之后,如何使用方法,完成特定的功能呢? 此时,我们就需要学习,方法调用了。 对于方法的调用,又分了两种情况:

  • 有返回值的方法调用
  • 没有返回值的方法调用

方法调用注意事项:

    1. 方法不调用不执行
    2. 方法与方法是平级关系,不能嵌套定义
    3. 方法定义的时候参数之间用逗号隔开
    4. 方法调用的时候不用再传递数据类型
    5. 如果方法有明确的返回值,一定要有return带回一个值

 

 

                                                                     图:一次方法调用的过程  

 

/**
 *  方法定义:方法就是完成特定功能的代码块(在有些其他语 言中,也被成为函数function)

    方法定义的格式

    修饰符  方法返回值类型 方法名(参数1类型 参数1名称,参数2类型 参数2名称, ……) {
        方法体语句;
        return 返回值;
    }

    方法定义的格式说明:
    修饰符:现在先认为是固定的 public static
    返回值类型:方法体中的代码执行结果的数据类型
    方法名 :标识符
    参数 :类比数学中函数的自变量 z = f(x, y)
    方法体:实现具体功能的语句结合
    return:跳转控制关键字
    返回值:方法执行的到的最终结果

    定义方法:两数求和(int)

    如何写一个方法呢?两个明确
    返回值类型 明确功能结果的数据类型
    参数列表 明确有几个参数,以及参数的类型

    对于方法的调用,又分了两种情况:
    1.有返回值的方法调用
    2.没有返回值的方法调用

    方法调用注意事项:
    1.方法不调用不执行
    2.方法与方法是平级关系,不能嵌套定义
    3.方法定义的时候参数之间用逗号隔开
    4.方法调用的时候不用在传递数据类型
    5.如果方法有明确的返回值,一定要有return带回一个值
 *
 *
 */
public class MethodDemo1 {

  public static void main(String[] args) {
    //用变量接收有返回值的方法调用
    int result = add(3, 4);
    System.out.println(result);

    //输出调用
    System.out.println(add(3,4));

    //直接调用 有返回值的方法调用没有意义
    add( 3, 4);

    //调用方法没有返回值的方法, 只能使用直接调用
    print("void 你好");
  }

  //定义方法 执行 3 + 4
  //public static int add1 () {
  //  int result = 3 + 4;
  //  return result;
  //}

  // 定义实现两数求和的加法运算
  public static int add (int x, int y) {
    int result = x + y;
    return result;
  }

  //定义没有返回值的方法  void表示方法没有返回值
  public static void print (String s) {
    System.out.println("我自己来输出" + s);
    //return; //可以有可以没有
  }


}

 

练习: 键盘录入一个数据n(1<=n<=9),输出对应的nn乘法表

 

import java.util.Scanner;

/**
 *
 * 练习:
    键盘录入一个数据n(1<=n<=9),输出对应的nn乘法表
 */
public class Exercise {

  public static void main(String[] args) {
    //调用方法
    // 2 x 2乘法表
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    printMulti(n);

  }


  //定义一个方法来完成输出n x n乘法表
  public static void printMulti(int n) {
    for (int i = 1; i <= n; i++) {

      for (int j = 1; j <= i; j++) {
        System.out.print(j + "x" + i + "=" + j * i + "  ");
      }
      System.out.println();
    }
  }

}

 

 

方法重载(overload)

在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数\参数类型不同\参数顺序不同)

为什么呢?1. 二义性 2. 方法签名

package com.method.overloads;

/**
 *
 * 方法重载(overload) 在同一个类中,允许存在一个以上的同名方法,
 *  a.只要它们的参数个数
 *  b.参数类型不同
 *  c.参数顺序不同: 不是指形式参数的变量名顺序不同,而是指形式参数类型顺序
 *
 * 编译器如何秋分方法呢? 通过方法签名 方法签名:
 * 方法名 + 参数列表 比如 add(int, int)
 *                     add(double, dobule)
 */
public class OverLoadDemo {

  public static void main(String[] args) {

    int a = 1;
    int b = 2;
    //int add = add(a, b, 10);
    //double c = 1.1;
    //double d = 2.2;
    //double doubleAdd = add(c, d);
    //
    //add(1,2);

    //int call = add(a, b);
    //add(a, b);
  }

  //两数相加
  public static int add(int x, int y) {
    System.out.println("int add");
    return x + y;
  }

  //public static double add(int x, int y) {
  //  return x + y;
  //}


  //实现3数相加
  public static int add(int x, int y, int z) {
    return add(x, y) + z;
  }

  //参数类型不同
  public static double add(double x, double y) {
    System.out.println("double add");
    return x + y;
  }

  //参数顺序不同
  public static int add(int y, byte x) {
    return x + y;
  }

  public static int add(byte y, int x) {
    return x + y;
  }

}

 

 

注意:

与返回方法重载与返回值类型无关,只看方法名和参数列表。(为什么呢?思考一下)

 

package com.method.overloads;

/**
 *
 * 比较两个数据是否相等。
 * 参数类型分别为 两个byte类型,
 *              两个short类型,
 *              两个int类型
 *              两个long类型
 * 并在main方法中进行测试

 */
public class Exercise {

  public static void main(String[] args) {

    byte b = 1;
    short c = 2;
    long a  = 1L;
    long d = 100L;
    equals(b,c);//equals(byte,short)调用equals(short,short),不需要完全一样,JVM会自己选择;
    equals(a,d);
  }


  public static boolean equals(byte a, byte b) {
    System.out.println("byte equals");
    return a == b;
  }


  public static boolean equals(short a, short b) {
    System.out.println("short equals");
    return a == b;
  }


  public static boolean equals(int a, int b) {
    System.out.println("int equals");
    return a == b;
  }

  public static boolean equals(long a, long b) {
    System.out.println("long equals");
    return a == b;
  }
}

 

方法重载练习

比较两个数据是否相等。参数类型分别为两个byte类型,两个short类型,两个int类型,两个long类型,并在main方法中进行测试

二、数组

假设一个班有80个人,我们现在需要统计,其某一门课程的平均成绩,思路很简单,先求和,在平均,想一想,如果使用我们之前所学的知识,该怎么做呢?

大致想一想都会觉得真的好麻烦!!!

为了应对以上的使用场景,我们就需要学习数组。

 

package com.array;

/**
 *
 *
 *假设一个班有80个人,我们现在需要统计,其某一门课程的平均成绩
 */
public class Demo1Intruduction {

  public static void main(String[] args) {
    // 1.定义80个变量
    // 2.用这80个变量存储80个同学的成绩
    // 3. 求和表达式 80变量的求和  a1 + a2 + ... + a80

  }

}

 

数组的概念(一组数据) 相同数据类型的数据元素的有序集合

存储多个数据元素 这多个数据元素的数据类型必须一致(为什么呢?)

数组的定义格式

格式1:

数据类型[ ] 数组名;

格式2:

  数据类型 数组名[ ];

  注意,这只是数组的定义,如何给定义好的数组“赋值”呢

 

 

 图:数组的概念

 

package com.array;

/**
 *
 * 数组中究竟可以存储哪些类型的数据呢?
   基本类型数据  byte short int char double float…
   引用类型数据  对象  对象数组

    数组的定义格式
    格式1:数据类型[] 数组名;   有点变量定义  int a = 1; int a = 1;
    格式2:数据类型 数组名[];

    数组的初始化
    1.Java中的数组必须先初始化,然后才能使用。
    2.所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋初值

    动态初始化
    初始化时程序猿只指定数组长度,由jvm为数组分配初始值。

    静态初始化
    初始化时指定每个数组元素的初始值,由系统决定数组长度。
    int[] a = {1, 2, 3}

    数组的动态初始化
    格式: 数据类型[] 数组名 = new 数据类型[数组长度];
    数组长度其实就是数组中元素的个数。
    int[]  arr = new int[3];

 */
public class Demo2Array {

  public static void main(String[] args) {
    //数组定义的格式  存放int类型值的数组
    //格式1
    int[] arr;  //官方推荐的写法

    //格式2 声明int类型的数组
    int arr1[];

    // 声明了数组,使用之前必须赋予初值
    //System.out.println(arr);

    {
      int a;
    }
    //System.out.println(a);

    //数组的动态初始化
    //格式: 数据类型[] 数组名 = new 数据类型[数组长度];
    int[] array = new int[3];
  }

}

 

数组的初始化

Java中的数组必须先初始化,然后才能使用。

所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋初值

数组的初始化方式

  • 动态初始化-------初始化时程序猿只指定数组长度,由系统为数组分配初始值。
  • 静态初始化-------初始化时指定每个数组元素的初始值,由系统决定数组长度。

 

数组的动态初始化

  格式: 数据类型[] 数组名 = new 数据类型[数组长度];

      数组长度其实就是数组中元素的个数。

      int[] arr = new int[3];

  如果清楚地了解数组的初始化过程,那我们就必须知道,数组初始化过程中,究竟在Java虚拟机内存中做了哪些工作。

 

Java虚拟机内存模型

  一个Java程序在虚拟机运行的过程中,

    1. 在内存中需要保存很多中类型的数据。比如局部变量,数组等等。局部变量:定义在方法体中的变量
    2. 不同类型的数据,其使用方式和生命周期,都不相同。
    3. 为了更好的管理这些不同类型的数据,jvm将自己的内存空间划分为不同的内存区域,各个区域针对不同类型的数据,其内存空间有不同的管理方式。
  • 栈 存储局部变量             迄今为止我们代码中几乎所有的变量都在栈(Stack)
  • 堆 存储new出来的东西             数组,对应的存储空间在堆中(Heap)
  • 方法区 (后面讲)
  • 本地方法栈 (系统相关)       java语言   可以调用c/c++
  • 程序计数器               指明代码执行的位置       

 

 

图:栈上变量和堆上变量的不同

 

 

 

 图:JVM内存模型

 

 

 

 

 

 图:数组的动态初始化

 

Java中数组的内存图解

图解1: 定义一个数组,输出数组名及元素。然后给数组中的元素赋值,再次输出数组名及元素。

package com.array;

/**
 *
 * 图解1:
     定义一个数组,输出数组名及元素。然后给数组中的元素赋值,再次输出数组名及元素。
 */
public class Demo3ArrayMap {

  public static void main(String[] args) {

    //定义一个数组,输出数组名及元素。然后给数组中的元素赋值,再次输出数组名及元素。
    int[] a = new int[3];
    //输出数组名
    System.out.println(a); // [I@4554617c   [表示一维数组  I整数类型  4554617c数组实际存储的首地址
    //输出
    System.out.println(a[0]);
    System.out.println(a[1]);
    System.out.println(a[2]);

    //给数组元素赋值
    a[0] = 10;
    a[1] = 100;
    System.out.println(a[0]);
    System.out.println(a[1]);
    System.out.println(a[2]);

  }

}

 

图:单个数组 

 

 

图解2: 定义两个数组,分别输出数组名及元素。然后分别给数组中的元素赋值,分别再次输出数组名及元素。

 

 1 package com.array;
 2 
 3 /** 6  *    图解2:
 7         定义两个数组,分别输出数组名及元素。
 8         然后分别给数组中的元素赋值,分别再次输出数组名及元素。
 9  */
10 public class Demo4ArrayMap {
11 
12   public static void main(String[] args) {
13 
14     int[] arr1 = new int[3];
15     System.out.println(arr1); //[I@4554617c
16 
17     System.out.println(arr1[0]);
18     System.out.println(arr1[1]);
19     System.out.println(arr1[2]);
20     System.out.println("--------------------------------------");
21 
22     int[] arr2 = new int[2]; //[I@74a14482
23     System.out.println(arr2);
24     System.out.println(arr2[0]);
25     System.out.println(arr2[1]);
26 
27     arr1[0] = -100;
28     System.out.println(arr1); //[I@4554617c
29     System.out.println(arr1[0]);
30     System.out.println(arr1[1]);
31     System.out.println(arr1[2]);
32 
33     arr2[1] = 30;
34     System.out.println(arr2); //[I@74a14482
35     System.out.println(arr2[0]);
36     System.out.println(arr2[1]);
37 
38 
39   }
40 
41 }

 

 

 

 图:多个数组


图解3: 定义两个数组,先定义一个数组,赋值,输出。然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组。然后给第二个数组赋值,再次输出两个数组的数组名及元素。

 1 package com.array;
 2 
 3 /** 6  *
 7  *   图解3:
 8         定义两个数组,先定义一个数组,赋值,输出。
 9         然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组。
10         然后给第二个数组赋值,再次输出两个数组的名及元素。
11  */
12 public class Demo5ArrayMap {
13 
14   public static void main(String[] args) {
15 
16     byte[] bytes1 = new byte[2];
17     bytes1[0] = 10;
18     bytes1[1] = 20;
19     System.out.println(bytes1); //[B@4554617c
20     System.out.println(bytes1[0]);
21     System.out.println(bytes1[1]);
22 
23     //然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组。
24     byte[] bytes2 = bytes1;
25     bytes2[0] = -10;
26     bytes2[1] = 110;
27     System.out.println("------------------第一个数组--------------------");
28     System.out.println(bytes1);  //[B@4554617c
29     System.out.println(bytes1[0]);
30     System.out.println(bytes1[1]);
31     System.out.println("-------------------第一个数组-------------------");
32 
33     System.out.println("------------------第二个数组--------------------");
34     System.out.println(bytes2); //[B@4554617c
35     System.out.println(bytes2[0]);
36     System.out.println(bytes2[1]);
37     System.out.println("-------------------第二个数组-------------------");
38 
39   }
40 
41 }

 

 图:多个引用变量指向同一个数组

 

数组的静态初始化:

  初始化时指定每个数组元素的初始值,由系统决定数组长度。

格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};

   int[] arr = new int[]{1,2,3};

简化写法:

   int[] arr = {1,2,3};

注意: 简化写法只在数组定义时有效!

 

package com.array;

/**
 *
 * 数组的静态初始化:
    初始化时指定每个数组元素的初始值,由系统决定数组长度。

    格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};
    int[] arr = new int[]{1,2,3};
    简化写法:
    int[] arr = {1,2,3}; //只有在声明数组的时候才能使用
 */
public class Demo6SaticInit {

  public static void main(String[] args) {

    //静态初始化,可以指定数组的元素初值,无法指定数组长度
    int[] arr = new int[]{1,2,3};
    //                    0 1 2

    int[] arr1 = {10, 21, 53};
    System.out.println(arr1[0]);
    System.out.println(arr1[1]);
    System.out.println(arr1[2]);

    //只有在声明数组的时候才能使用
    //arr = {10, 21, 53};
  }

}

 

 图:静态初始化

 

 

数组操作中,常见的两个问题:

    • 数组索引越界 ArrayIndexOutOfBoundsException
    • 空指针异常 NullPointerException

 

 图:空指针异常

 

 1 package com.array;
 2 
 3 /**
 4  *
 5  *  数组常见异常:
 6  *  数组索引越界  ArrayIndexOutOfBoundsException
 7     空指针异常  NullPointerException
 8 
 9  */
10 public class Demo7ArrayException {
11 
12   public static void main(String[] args) {
13 
14     //数组索引越界
15     //java.lang.ArrayIndexOutOfBoundsException: 3
16     int[] arr = new int[3]; //包含的元素 位置 0 1 2
17     //访问了数组中并不存在的索引对应的元素
18     //System.out.println(arr[3]);
19 
20     //空指针异常  NullPointerException
21     arr = null; // null空常量
22     System.out.println(arr[0]);
23   }
24 
25 }

 

数组遍历(依次输出数组中的每一个元素)

数组元素逆序

对取值范围在1~100的数据集合排序

数组获取最值(获取数组中的最大值最小值)

数组查表法(根据键盘录入索引,查找对应星期)

数组元素查找(查找指定元素第一次在数组中出现的索引)

posted @ 2020-04-10 22:17  dust--  阅读(184)  评论(0编辑  收藏  举报