目录
第一章 方法
1.1方法概述
在java中,方法就是为了实现某一功能或者解决某一问题的办法。方法可能包含很多条语句。
例如打火机,一般人们不会关注其组成结构,原理等方面,人们知道如何使用就可以。打火机也是一个方法,解决了点火问题,其里面也有很多原件。
Java中的方法与c语言中的函数很类似,不同的是Java的方法多了继承,重载等功能。(Java中无函数一说,只有方法一说)
1.2方法的语法格式
java中,方法的具体语法格式:
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,......){
执行语句
………
return 返回值;
}
public static int getArea(int w,int h) {
//实现方法的功能主体
return w*h;
}
- 修饰符:方法的修饰符比较多,有对访问权限进行限定的,有静态修饰符static,还有最终修饰符final等,这些修饰符在面向对象中再详细讲。
- 返回值类型:方法在运算后,结果的数据类型
- 方法名:自定义名字,满足标识符规范,方法名首字母小写,后面每个单词首字母大写
- 参数列表:方法的运算过程中,是否有未知的数据,如果有未知的数据,定义在参数列表上(定义变量)
- return:方法的返回,将计算的结果返回。结束方法
/*
方法的定义格式
修饰符 返回值类型 方法的名字 (参数列表...){
方法的功能主体
循环,判断,变量,比较,运算
return ;
}
修饰符:固定写法 public static 在面向对象中再讲
返回值类型:方法在运算后,结果的数据类型
方法名:自定义名字,满足标识符规范,方法名首字母小写,后面每个单词首字母大写
参数列表:方法的运算过程中,是否有未知的数据,如果有未知的数据,定义在参数列表上(定义变量)
return:方法的返回,将计算的结果返回。结束方法
*/
package day5;
public class MethodDemo {
public static void main(String[] args) {
//调用方法,执行方法
//在方法main中调用getArea
int area = getArea(5,6);
System.out.println(area);
/*
要求:计算一个长方形的面积
定义一个方法来解决这个要求
分析方法定义过程:
1.明确方法计算后结果的数据类型 int(返回值类型)
2.方法计算过程中,有没有未知的数据(长和宽 int型)
3.方法必须写在类中,但不能写在另一个方法的里面(main是一个方法不可以写main中)
*/
}
public static int getArea(int w,int h) {
//实现方法的功能主体
return w*h;
}
}
结果:
1.3方法调用图解
- 程序运行时,将main作为程序的入口,开始执行程序。
- 执行main中的代码。
- 调用方法,getArea,传递参数5,6(此处的参数称为实际参数)
- 方法getArea开始运行,计算w*h=30
- return 30(返回return后面的数值,返回给方法的调用者。此处的方法调用者是main)
- 方法getArea定义后,参数w,h是无具体内容的,被称为形式参数。
回顾一下Java基础(四)中所讲的,getArea
JVM划分:
- 寄存器:内存与cpu之间的操作。
- 本地方法栈:有些功能jvm完成不了,需要调用操作系统的中的功能。
- 方法和数据共享区:运行时期.class文件进入内存的地方。(程序运行的是.class文件)
- 方法栈:所有的方法运行的时候,进入的内存区域。(程序运行时main方法存储的地方)
- 堆:存储的是容器和对象
具体执行步骤如下:
- 程序运行时期,程序进入内存(运行时,编译后的class文件进入内存)
- JVM虚拟机调用main方法,main方法进方法栈运行
- 开始执行main方法中的代码,调用getArea方法,传递参数
- getArea方法进方法栈运行,计算结束后,将结果返回给调用者main
- getArea方法结束,出栈,释放内存资源。(getArea在栈顶,main在栈底,因此getArea先出栈,main程序结束后才出栈)
- main获取到了getArea的返回结果30.
练习:
分别定义如下方法:
- 定义无返回值无参数方法,如打印3行,每行3个*号的矩形
- 定义有返回值无参数方法,如键盘录入得到一个整数
- 定义无返回值有参数方法,如打印指定M行,每行N个*号的矩形
- 定义有返回值有参数方法,如求三个数的平均值
代码实现:
package day5;
import java.util.Scanner;
public class MethodDemo_1 {
// 1.无返回值无参数方法,如打印3行,每行3个*号的矩形
public static void printRect() {
for(int i =0;i<3;i++) {
for(int j =0;j<3;j++) {
System.out.print("*");
}
System.out.println();
}
}
//2.定义有返回值无参数方法,如键盘录入得到一个整数
public static int getNumber() {
System.out.println("请输入一个整数:");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
return i;
}
//3.定义无返回值有参数方法,如打印指定M行,每行N个*号的矩形
public static void printRect2(int m,int n) {
for(int i =0;i<m;i++) {
for(int j =0;j<n;j++) {
System.out.print("*");
}
System.out.println();
}
}
//4.定义有返回值有参数方法,如求三个数的平均值
public static double getAvg(double a,double b,double c) {
double avg = (a+b+c)/3;
return avg;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// printRect();
//System.out.println(getNumber());
//printRect2(3,6);
System.out.println(getAvg(4,5,6));
}
}
方法定义和使用的注意事项
1.方法不能定义在另外一个方法里面(注意main也为方法,注意其他方法不能写在main中)
2.写错方法名,写错了参数类型\格式
3.方法返回值是void,方法中可以省略return不写。
4.方法的返回值类型和return后面的数据类型必须匹配。
1.4方法的重载
我们假设要在程序中实现一个对数字求和的方法,由于参与求和数字的个数和类型都不确定,因此要针对不同的情况去设计不同的方法。但是,由于每个方法的名称都不相同,在调用时就很难分清该调用哪个方法。
为了解决这个问题,Java允许在一个类中定义多个名称相同的方法,但是参数的类型或个数必须不同,这就是方法的重载。
下面的三个方法互为重载关系
- public static int add(int x,int y) {逻辑} //两个整数加法
- public static int add(int x,int y,int z) {逻辑} //三个整数加法
- public static int add(double x,double y) {逻辑} //两个小数加法
注意:
方法的重载与返回值类型无关,它只有两个条件:
一是方法名相同。
二是参数个数或参数类型不相同。
JDK下的src.zip——>java——>io——>PrintStream中存有println的源码。
println方法就是重载。
1.4.1 重载的注意事项
重载方法参数必须不同:
参数个数不同
参数类型不同
参数顺序不同,如method(int x,double y)与method(double x,int y)不同
重载和参数的变量名无关,如method(int x,double y)与method(int a,double b)相同。
重载和返回值类型无关,如public static void method(int x,double y)与public static int method(int x,double y)不能同时出现,因为在调用method(2,2.5)时不知道调用哪个。
重载与修饰符无关
技巧:重载只看参数列表和方法名。
1.4.2参数传递(基本数据类型、引用数据类型)
a.方法参数是基本数据类型:
// 方法参数是基本数据类型
public class MethodDemo_3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 1;
int b = 2;
change(a,b);
System.out.println(a); //1,因为a,b的定义范围在main方法中
System.out.println(b); // 2
}
public static int change(int a,int b){
a = a+b;
b = b+a;
return a;
}
}
结果:
b.方法参数是引用数据类型:
//方法参数是引用类型, 传递的是内存地址!
package day5;
public class MethodDemo_3{
public static void main(String[] args){
/*int a = 1;
int b = 2;
change(a,b);
System.out.println(a); //1
System.out.println(b); // 2
*/
int[] arr = {1,2,3,4};
System.out.println(arr[2]); // 3
change(arr);
System.out.println(arr[2]); // 100
}
public static void change(int[] arr){
arr[2] = 100;
}
public static void change(int a,int b){
a = a+b;
b = b+a;
}
}
结果:
存储分析:
方法参数是基本类型时,调用前后值不做修改(与参数定义范围有关)
方法传递的引用类型的数组,则调用时传递的地址,进入方法后改掉了原数据的值,因此再调用时,值已经改变。
通过上面的两段程序可以得出如下结论:
- 当调用方法时,如果传入的数值为基本数据类型(包含String类型),形式参数的改变对实际参数不影响
- 当调用方法时,如果传入的数值为引用数据类型(String类型除外),形式参数的改变对实际参数有影响
举例1:随机点名器
随机点名器明确地分为了三个功能。如果将多个独立功能的代码写到一起,则代码相对冗长,我们可以针对不同的功能可以将其封装到一个方法中,将完整独立的功能分离出来。
/*
实现随机点名器
1. 存储所有学生姓名
2. 预览所有学生姓名,遍历数组
3. 随机数作为索引,到数组中找元素
*/
import java.util.Random;
public class CallName {
//1.存储所有同学姓名
public static void addStudent(String[] names) {
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
names[3] = "李蕾";
names[4] = "韩梅梅";
names[5] = "小名";
names[6] = "老王";
names[7] = "小华";
}
public static void printStudentName(String[] names){
for(int i = 0 ; i < names.length ;i++){
System.out.println(names[i]);
}
}
public static String randomStudentName(String[] names){
Random rc = new Random();
int i = rc.nextInt(names.length);
return names[i];
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String[] names = new String[8];
addStudent(names);
System.out.println(randomStudentName(names));
}
}
结果:
举例2:库存管理案例
题目要求:
管理员能够进行的操作有3项(查看、修改、退出),我们可以采用(switch)菜单的方式来完成。
-------------库存管理------------
1.查看库存清单
2.修改商品库存数量
3.退出
请输入要执行的操作序号:
每一项功能操作,我们采用方法进行封装,这样,可使程序的可读性增强。
选择“1.查看库存清单”功能,则控制台打印库存清单
选择“2.修改商品库存数量”功能,则对每种商品库存数进行更新
选择“3.退出”功能,则退出库存管理,程序结束
/*
实现商品的库存管理
功能:
1. 展示用户选择功能清单
2. 根据选择的功能编号,进行不同的操作
A. 展示所有库存
B. 修改库存数量
分析:
1. 展示用户清单:
输出语句, 用户输入, 选择功能序号
2. 根据选择,调用不同的方法
switch语句
case 1 2 3
A 展示库存
将存储商品的数组,遍历
B 修改库存
修改所有的库存数量
*/
package day5;
import java.util.Scanner;
public class shopp {
public static void main(String[] args) {
//使用数组保存商品信息
//品名、尺寸、价格、库存数,定义4个数组
String[] brand = {"MacBookAir","ThinkpadT450"};
double[] size = {13.3,15.6};
double[] price = {4399.99,6399.99};
int[] count = {0,0};
while(true) {
int choose = chooseFunction();
switch(choose) {
case 1:
//调用查看库存清单方法
printStore(brand,size,price,count);
break;
case 2:
//修改库存的方法
update(brand,count);
break;
case 3:
return;
default:
System.out.println("没有这个功能");
break;
}
}
}
/*
* 定义方法,修改所有商品的库存
* 用户输入一个,修改一个
* 返回值,无
* 参数,库存数的数组,品名数组
*/
public static void update(String[] brand,int[] count) {
//变量数组,遍历一个,修改一个
Scanner sc = new Scanner(System.in);
//遍历数组
for(int i=0;i<brand.length;i++) {
System.out.println("请输入"+brand[i]+"的库存数");
int newCount = sc.nextInt();
count[i] = newCount;
}
}
/*
* 定义方法,展示所有的库存清单,遍历
* 返回值,无
* 参数,4个数组
*/
public static void printStore(String[] brand,double[] size,double[] price,int[] count) {
System.out.println("---------------------------查看库存清单--------------------------");
System.out.println("品牌型号 尺寸 价格 库存数");
//定义变量,计算总库存数和总价格
int totalCount=0;
int totalMoney = 0;
//遍历数组,将数组中所有的商品信息打印
for(int i=0;i<brand.length;i++) {
System.out.println(brand[i]+" "+size[i]+" "+price[i]+" "+count[i]);
totalCount +=count[i];
totalMoney+=price[i]* count[i];
}
System.out.println("总库存数: "+totalCount);
System.out.println("商品库存总金额: "+totalMoney);
}
/*
* 定义方法,实现用户的选择功能,功能的需要返回来
* 返回值 int
* 参数,无
*/
public static int chooseFunction() {
System.out.println("-------------库存管理------------");
System.out.println("1.查看库存清单");
System.out.println("2.修改商品库存数量");
System.out.println("3.退出");
System.out.println("请输入要执行的操作序号:");
//接收键盘输入的功能选项序号
Scanner sc = new Scanner(System.in);
int chooseNumber = sc.nextInt();
return chooseNumber;
}
}
结果: