目录
方法
引例:文件上传是做一个电商网站所必不可少的功能,比如每一个商品都需要上传若干商品图片,网站上各种品牌都需要上传其logo,用户在注册时可以上传头像... 假设你现在已经写了100行代码完成了文件上传功能,但问题是网站的很多地方都要使用这一功能,比如管理商品数据的商品服务,管理用户数据的用户信息服务等等。
问题来了,这些地方都要使用文件上传的功能,怎么办呢?
方案1:在每个用到文件上传功能的地方重写这些100行代码,但是方案1会引发一系列的问题!!
方案2:复用这100行代码,将这些代码放在一个{ }中,并给它们起个名字,通过名字来复用这段代码
方法定义:完成特定功能的代码块(相当于c语言的函数)
格式:
修饰符 方法返回值类型 方法名(参数1类型 参数1名称, 参数2类型 参数2名称, ...){
方法体语句;
return 返回值;
}
方法定义的格式说明:
1.修饰符: 现在先认为是固定的public static
2.返回值类型: 方法体中的代码执行结果的数据类型
3.方法名: 标识符
4.参数: 类比数学中函数的自变量 z = f(x, y)
5.方法体: 实现具体功能的语句结合
6.return: 跳转控制关键字
7.返回值: 方法执行的到的最终结果
注意: return 返回值; (这句并非必须)
方法调用有两种:
1)有返回值的方法调用
2)没有返回值的方法调用
两式求和(add)
//定义方法 执行 3 + 4
public static int add1() {
int result = 3 + 4;
return result;
}
//定义方法 执行 5 + 6
public static int add2() {
int result = 5 + 6;
return result;
}
//以上两数求和都是固定数不方便,优化
//声明两个参数变量,让他们来传数进行运算
//定义实现两数求和的加法运算
public static int add(int x, int y) {
int result = x + y;
return result;
}
//不需要先声明后使用
public static void main(String[] args) {
//用变量接收有返回值的方法调用
int result = add(3, 4);
System.out.println(result);// 7
System.out.println(add(3, 4));// 7
add(3, 4);//可以调用,但有返回值的方法调用无意义
}
如何写一个方法呢?
返回值类型 明确功能结果的数据类型
参数列表 明确有几个参数,以及参数的类型
方法执行过程:
定义没有返回值的方法,void 表示方法没有返回值
public static void main(String[] args) {
//调用没有返回值的方法
print("你好");
}
public static void print(String s) {
System.out.println("我是没有返回值的方法:" + s);
//return;//可以有可以没有,通常省略
}
//输出: 我是没有返回值的方法:你好
注意:方法体中不能定义方法(不能嵌套)
练习:键盘录入一个数据n(1<=n<=9),输出对应的nn乘法表
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
printMulti(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();
}
}
/*
输入:3
1 x 1 = 1
1 x 2 = 2 2 x 2 = 4
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
*/
方法重载
同一个类中定义多个同名方法,方法名相同,参数列表:个数不同、数据类型、顺序不同(数据类型的顺序)
数组(一维)
引例:假设一个班有80个人。我们现在需要统计,其某一门课程的平均成绩, 思路很简单,先求和,在平均,想一想,如果使用我们之前所学的知识,该怎么做呢?
//1.定义80个变量
//2.用这80个变量存储80个同学的成绩
//3.求和表达式 80变量的求和 al + a2 + ... + a80
大致想一想都会觉得真的好麻烦!! ! 为了应对以上的使用场景,我们就需要学习数组。
数组的概念(一组数据)
相同数据类型的数据元素的有序集合(容器)
存储多个数据元素
这多个数据元素的数据类型必须一致(为什么呢?)
数据宽度:数据占的字节的数量 随机存取(数组的访问特征):访问数组内任意一个元素的时间都相同
要想实现随机存取,必须数据类型相同,不然用不了上面公式
数组中究竟可以存储哪些类型的数据呢?
基本类型数据:byte short int char double float
引用类型数据:对象
数组的定义格式
格式1: 数据类型[ ] 数组名;
格式2: 数据类型 数组名[ ];
注意,这只是数组的定义,如何给定义好的数组“赋值”呢
//存放int类型值的数组 官方推荐的写法
int[] arr;
//声明int类型的数组
int arr1[];
//使用之前必须赋初值
System.out.println(arr);//报错:Variable "arr" might not have been initialized
数组的初始化
Java中的数组必须先初始化,然后才能使用。
所谓初始化:就是为数组中的数组元素分配内存空间,并为每个数组元素赋初值
数组的初始化方式
动态初始化
初始化时程序猿只指定数组长度,由系统(JVM)为数组分配初始值。
静态初始化
初始化时指定每个数组元素的初始值,由系统决定数组长度。 int[] a = {1, 2, 3}
数组的动态初始化
格式:数据类型[] 数组名 = new 数据类型[数组长度];(数组长度就是数组中元素的个数)
int[] arr = new int[3];
jvm虚拟机
栈(Stack):存储局部变量 (迄今为为止我们代码中几乎所有的变量都在栈)【Java没有全局变量】
堆(Heap):存储new出来的东西 (数组对应的存储空间在这里)
方法区:(后面讲)
本地方法栈:(系统相关)Java语言调用的C/C++语言存储的
程序计数器:(最无用的东西)指明代码的执行位置,记录java代码运行到哪
一行代码在 jvm 中做了什么事情?
图解1:
定义一个数组,输出数组名及元素。然后给数组中的元素赋值,再次输出数组名及元素。
图解2:
定义两个数组,分别输出数组名及元素。然后分别给数组中的元素赋值,分别再次输出数组名及元素。
图解3:
定义两个数组,先定义一个数组,赋值,输出。然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组。然后给第二个数组赋值,再次输出两个数组的名及元素。
//图解1:定义一个数组,输出数组名及元素。然后给数组中的元素赋值,再次输出数组名及元素。
int[] a = new int[3];
//输出数组名
System.out.println(a);//[I@4554617c:[表示一维数组 I整数类型 4554617c数组实际存储的首地址
//输出
System.out.println(a[0]);//0
System.out.println(a[1]);//0
System.out.println(a[2]);//0
//给数组中的元素赋值
a[0] = 10;
a[1] = 20;
System.out.println(a);//[I@4554617c
System.out.println(a[0]);//10
System.out.println(a[1]);//20
System.out.println(a[2]);//0
//图解2:定义两个数组,分别输出数组名及元素。然后分别给数组中的元素赋值,分别再次输出数组名及元素。
int[] arr1 = new int[3];
System.out.println(arr1);//[I@4554617c
System.out.println(arr1[0]);//0
System.out.println(arr1[1]);//0
System.out.println(arr1[2]);//0
System.out.println("------------------------");
int[] arr2 = new int[2];
System.out.println(arr2);//[I@74a14482
System.out.println(arr2[0]);//0
System.out.println(arr2[1]);//0
arr1[0] = -100;
System.out.println(arr1);//[I@4554617c
System.out.println(arr1[0]);//-100
System.out.println(arr1[1]);//0
System.out.println(arr1[2]);//0
arr2[1] = 30;
System.out.println(arr2);//[I@74a14482
System.out.println(arr2[0]);//0
System.out.println(arr2[1]);//30
//图解3:定义两个数组,先定义一个数组,赋值,输出。
byte[] bytes1 = new byte[2];
bytes1[0] = 10;
bytes1[1] = 20;
System.out.println(bytes1);//[B@4554617c
System.out.println(bytes1[0]);//10
System.out.println(bytes1[1]);//20
//然后定义第二个数组的时候把第一个数组的地址赋值给第二个数组。
//然后给第二个数组赋值,再次输出两个数组的元素。
byte[] bytes2 = bytes1;
bytes2[0] = -10;
bytes2[1] = 110;
System.out.println("---------第一个数组----------");
System.out.println(bytes1);//[B@4554617c
System.out.println(bytes1[0]);//-10
System.out.println(bytes1[1]);//110
System.out.println("---------第一个数组----------");
System.out.println("---------第二个数组----------");
System.out.println(bytes2);//[B@4554617c
System.out.println(bytes2[0]);//-10
System.out.println(bytes2[1]);//110
System.out.println("---------第二个数组----------");
数组的静态初始化
!!!初始化时指定每个数组元素的初始值,由系统决定数组长度。
格式:数据类型[ ] 数组名 = new 数据类型[ ]{元素1, 元素2, ...};
int[] arr = new int[]{1, 2, 3};
//简化写法:
int[] arr = {1,2,3};
arr = {1,2,3};//错误
注意: 简化写法只在数组定义时有效!
数组操作中,常见的两个问题:
1、数组索引越界 ArrayIndexOutOfBoundsException
2、空指针异常 NullPointerException
//数组索引越界
int[] arr = new int[2];//包含的元素 位置 0、1、2
//访问了数组中并不存在的索引对应的元素
System.out.println(arr[2]);//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
//空指针异常
arr = null;
System.out.println(arr[0]);//Exception in thread "main" java.lang.NullPointerException
练习:
1、数组遍历(依次输出数组中的每一个元素)
2、数组元素逆序
3、对取值范围在1~100的数据集合排序
4、数组获取最值(获取数组中的最大值最小值)
5、数组查表法(根据键盘录入索引,查找对应星期)
6、数组元素查找(查找指定元素第一次在数组中出现的索引)
答案:
public static void main(String[] args) {
/*//1、数组遍历
int[] arr1 = new int[10];
arr1[0] = 1;
arr1[1] = 2;
traverse(arr1);*/
//len10
//1 2 0 0 0 0 0 0 0 0
/*//2、数组逆序
int[] arr2 = {1, 2, 6, 7};
reverseArray(arr2);
//Arrays.toString()将数组里的元素拼接成字符串后返回
System.out.println(Arrays.toString(arr2));*/
//[7, 6, 2, 1]
/*//3、对取值范围在1~100的数据集合排序
int[] arr3 = {1, 3, 5, 2, 1, 1, 55};
sort(arr3);
System.out.println(Arrays.toString(arr3));
//[1, 1, 1, 2, 3, 5, 55]
//4、数组获取最值
System.out.println(findMax(arr3));*/
//55
/*//5、数组查表法(根据键盘录入索引,查找对应星期)
System.out.println(findDayOfWeek(7));*/
//星期日
/*//6、数组元素查找(查找指定元素第一次在数组中出现的索引)
int location = findLocation(arr2, 1);
System.out.println(location);*/
//1
}
//1、数组遍历方法(依次输出数组中的每一个元素)
public static void traverse(int[] arr) {
//数组有一个属性length(数组长度,不是元素个数),数组取值范围:[0, length-1]
int len = arr.length;
System.out.println("len" + len);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
//2、数组元素逆序 [1,2,3,6,7]->[7,6,3,2,1]
//奇数个元素:关于3对称,交换对称的位置
//偶数个元素:交换对称的位置
//思路:对称位置元素交换位置,先遍历数组
public static void reverseArray(int[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
int tmp;
tmp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = tmp;
}
}
//3、计数排序:对取值范围在1~100的数据集合排序
public static void sort(int[] arr) {
//1、根据题意创建包含101个元素的数组
int[] countArray = new int[101];
//2、遍历待排序集合,在countArray中,对待排序的数据计数
for (int i = 0; i < arr.length; i++) {
//得到待排序集合中当前元素的值
int resultIndex = arr[i];
countArray[resultIndex]++;
}
//3、在原数组中排序
int index = 0;
for (int i = 0; i < countArray.length; i++) {
for (int j = 0; j < countArray[i]; j++) {
arr[index++] = i;
}
}
}
//4、数组获取最值(获取数组中的最大值最小值)
public static int findMax(int[] arr) {
//存储数组中最大值,假设第一个最大
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
//5、数组查表法(根据键盘录入索引,查找对应星期)
public static String findDayOfWeek(int index) {
String[] daysOfWeek = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日",};
return daysOfWeek[index - 1];
}
//6、数组元素查找(查找指定元素第一次在数组中出现的索引)
public static int findLocation(int[] arr, int value) {
int resultIndex = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value) {
resultIndex = i;
break;
}
}
return resultIndex + 1;
}
二维数组
我们已经学习了基本的一维数组,可以持有大量数据。
思考如下场景:
假设我现在要统计,学校中某个年级中,各班的数学成绩的平均分。
思考一下,用一维数组可以吗?会遇到什么问题?
分析一下出现问题的原因是什么呢?不同的维度
看起来,该问题的解决:
用一个一维数组,存储所有班级(每一个班级本身的数据,又需要用一个一维数组存储)
看起来就好像,我们定义了这样一个一维数组:
这个一维数组的,每一个存储单元,又存储了一个一维数组
定义了一个一维数组的数组——二维数组
二维数组的实质:一维数组的数组 二维数组的初始化格式1:
数据类型[][] 变量名 = new 数据类型[m][n];
//m代表二维数组中一维数组的个数
//n代表二维数组中包含的每个一维数组,所能包含的元素个数
特征:二维数组中每一个一维数组包含的元素的个数相同(格式1)
//例如:
int[][] arr = new int[2][2];
//在简单看下其内存映象
//1、输出二维数组引用变量的值
System.out.println(arr);//[[I@1540e19d [[:表示一个二维数组
//2、输出二维数组中,第一个一维数组的引用的值
System.out.println(arr[0]);//[I@677327b6
//3、访问二维数组中,一维数组的元素值
System.out.println(arr[1][0]);//0
arr[1][0] = 10;
System.out.println(arr[1][0]);//10
二维数组定义的格式2:
数据类型[][] 变量名 = new 数据类型[m][];
//m表示这个二维数组有多少个一维数组
//这一次没有直接给出一维数组的元素个数,可以动态的给出。
举例:
int[] arr2 = new int[2][];
arr[0] = new int[1];
arr[1] = new int[2];
//注意:这种方式从存储角度讲更加灵活!
二维数组定义的格式3:
数据类型[][] 变量名 = new 数据类型[][]{{元素...},{元素...},{元素...}};
//简化版格式:
数据类型[][] 变量名 = {{元素...},{元素...},{元素...}};
//注意:简化版只能在定义数组的引用变量时使用!
public static void main(String[] args) {
//三个一维数组,每个数组的初值都已经被指定
int[][] arr3 = {{1}, {2, 3}, {4, 5, 6}};
trverseTwoDeimensionArray(arr3);
/*1
2 3
4 5 6 */
}
public static void trverseTwoDeimensionArray(int[][] arr) {
//arr指向的是代表二维数组的那个一维数组 arr.length 表示二维数组中的一维数组个数
for (int i = 0; i < arr.length; i++) {
//arr[i]代表二维数组中的第i个一维数组 arr[i].length 表示的就是二维数组中第i个一维数组的元素个数
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
练习:
1、二维数组遍历
公司年销售额求和,某公司按照季度和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99
public static void main(String[] args) {
int[][] arr = {{22, 66, 44}, {77, 33, 88}, {25, 45, 65}, {11, 66, 99}};
System.out.println(sum(arr));//641
}
public static int sum(int[][] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
return sum;
}
2、打印杨辉三角形(行数可以键盘录入)
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] yanghui = yanghui(n);
for (int i = 0; i < yanghui.length; i++) {
for (int j = 0; j < yanghui[i].length; j++) {
System.out.print(yanghui[i][j] + " ");
}
System.out.println();
}
/*5
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1 */
}
//对于杨辉三角,第一行和第二行是固定的
//每一行元素个数和行数相同
//每一行的第一个和最后一个元素值固定,都是1
// 每一行出首尾位置之外,其他位置的元素值都有规律:
// 第i行第j列 = 第i-1行第j列的值 + 第i-1行j-1列
public static int[][] yanghui(int n){
if (n==1){
return new int[][]{{1}};
}
if (n==2){
return new int[][]{{1},{1,1}};
}
//最终返回的二维数组的结果
int[][] result=new int[n][];
result[0]=new int[]{1};
result[1]=new int[]{1,1};
//计算并初始化每一行数据
for (int i=2;i<n;i++){
//对于杨辉三角的第i行数据,初始化首尾元素的值
result[i]=new int[i+1];
result[i][0]=1;
result[i][i]=1;
for (int j=1;j<i;j++){
result[i][j]=result[i-1][j-1]+result[i-1][j];
}
}
return result;
}
值传递
(引用数据类型和基本数据类型)
在java语言中,不管参数的类型,是引用类型,还是基本数据类型,在实际参数和形式参数进行值传递的方式只有一种: 实际参数的值复制一份赋值给形式参数 所以,实参的值,其实就有两份,调用方法中一份,被调用方法中一份
1.当方法的参数是基本数据类型的参数的时候,参数有两份,同时参数对应的数据的值,也有两份 2.当方法的参数是引用数据类型的时候参数值有两份,但是两个数组类型引用变量,对应的值(数组),只有一个