目录
1.方法概述
方法是一种语法结构,它可以把一段代码封装成一个功能,以便重复调用。
//目标:掌握定义方法的完整格式,搞清楚使用方法的好处。
public class MethodDemo1 {
public static void main(String[] args) {
// 需求:假如现在很多程序员都要进行2个整数求和的操作。
// 1、李工。
int rs = sum(10, 20);
System.out.println("和是:" + rs);
// 2、张工。
int rs2 = sum(30, 20);
System.out.println("和是:" + rs2);
}
public static int sum(int a,int b) {
int c = a + b;
return c;
}
}
2.方法的其他形式
-
如果方法不需要返回数据,返回值类型必须申明成void(无返回值申明), 此时方法内部不可以使用return返回数据。
-
方法如果不需要接收外部传递进来的数据,则不需要定义形参,且调用方法时也不可以传数据给方法。
-
没有参数,且没有返回值类型(void)的方法,称为值无参数、无返回值方法。此时调用方法时不能传递数据给方法。
3.方法的常见问题
- 1. 方法在内存中没有先后顺序,但是不能把一个方法定义在另一个方法中。
- 2. 方法的返回值类型写void(无返回申明)时,方法内不能使用return返回数据,
如果方法的返回值类型写了具体类型,方法内部则必须使用return返回对应类型的数据。
- 3. return语句的下面,不能编写代码,属于无效的代码,执行不到这儿。
- 4. 方法不调用就不会执行, 调用方法时,传给方法的数据,必须严格匹配方法的参数情况。
- 5. 调用有返回值的方法,有3种方式:
① 可以定义变量接收结果
② 或者直接输出调用
package com.itheima.create;
public class MethodDemo1 {
public static void main(String[] args) {
// int max = getMax(10,15);
// System.out.println(max);
System.out.println("最大值为:" + getMax(15,10));
}
public static int getMax (int a ,int b){
int max = a > b ? a : b;
return max;
}
}
③ 甚至直接调用
- 6. 调用无返回值的方法,只有1种方式: 只能直接调用。
4.方法的案例
定义方法时先思考以下几个问题,然后进行方法的定义。
package com.itheima.create;
public class Test1 {
public static void main(String[] args) {
System.out.println("1到100的和为:" + sum(100));
}
public static int sum(int n){
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
}
5.方法在计算机中的执行原理
1.确保方法调用其他方法之后可以回来
2.确保方法执行完毕后可以释放栈内存
我们知道Java程序的运行,都是在内存中执行的,而内存区域又分为栈、堆和方法区。那Java的方法是在哪个内存区域中执行呢?
答案是栈内存。 每次调用方法,方法都会进栈执行;执行完后,又会弹栈出去
方法进栈和弹栈的过程,就类似于手枪子弹夹,上子弹和击发子弹的过程。先进后出
假设在main方法中依次调用A方法、B方法、C方法,在内存中的执行流程如下:
-
每次调用方法,方法都会从栈顶压栈执行
-
每个方法执行完后,会从栈顶弹栈出去
5.1 有返回值的方法,内存分析
下面我们分析一下,求两个整数和的代码,在内存中的执行原理。
public class MethodDemo {
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;
}
}
5.2 无返回值的方法,内存分析
刚才我们分析的是有有参数有返回值的方法内存原理。下面再分析一个无返回值、无参数的内存原理。
public class Demo2Method {
public static void main(String[] args) {
study();
}
public static void study(){
eat();
System.out.println("学习");
sleep();
}
public static void eat(){
System.out.println("吃饭");
}
public static void sleep(){
System.out.println("睡觉");
}
}
方法的运行区域在栈内存中,栈的特点是先进后出,保证一个方法调用完另一个方法之后,可以回来继续执行。
6.方法参数的传递机制
Java的参数传递机制都是:值传递
6.1 参数传递的基本类型数据
Java的参数传递机制都是:值传递,传递的是实参存储的值的副本。
6.3 参数传递的是引用数据类型
看一下方法的参数是引用类型的数据时,内存中是怎么执行的。
我们发现调用change方法时参数是引用类型,实际上也是值传递,只不过参数传递存储的地址值。此时change方法和main方法中两个方法中各自有一个变量arrs,这两个变量记录的是同一个地址值[I@4c873330,change方法把数组中的元素改了,main方法在访问时,元素已经被修改了。
基本类型和引用类型的参数在传递的时候有什么不同?
= 都是值传递
- 基本类型的参数传递存储的数据值。
- 引用类型的参数传递存储的地址值。
7.案例
需求:比较两个int类型的数组是否一样,返回true或者false
分析:
1.方法是否需要接收数据进行处理?
因为,方法中需要两个int数组比较,但是需求并不明确是哪两个数组;
所以,需要接收两个int类型的数组,形参声明为:int[] arr1,int[] arr22.方法是否需要返回数据?
因为,方法最终的结果需要true或者false;
所以,返回值类型是boolean
3. 方法内部的业务:判断两个数组内容是否一样。
public class Demo4 {
public static void main(String[] args) {
int[] a1 = null;
int[] a2 = null;
System.out.println(compare(a1,a2));
int[] b1 = {11,22};
int[] b2 = {11,22,33,44};
System.out.println(compare(b1,b2));
int[] c1 = {11,22,33};
int[] c2 = {11,24,33};
System.out.println(compare(c1, c2));
int[] d1 = {11,24,33};
int[] d2 = {11,24,33};
System.out.println(compare(d1, d2));
}
public static boolean compare(int[] arr1, int[] arr2){
if (arr1 == null || arr2 == null) {
return false;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if(arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
}
要判断所有数组可能出现的情况,避免不必要的bug。
8.方法的重载
一个类中,出现多个相同的方法名,但是它们的形参列表是不同的,那么这些方法就称为方法重载了。
注意:形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称。
public class MethodOverLoadDemo1 {
public static void main(String[] args) {
// 目标:认识方法重载,并掌握其应用场景。
test();
test(100);
}
public static void test(){
System.out.println("===test1===");
}
public static void test(int a){
System.out.println("===test2===" + a);
}
void test(double a){
}
void test(double a, int b){
}
void test(int b, double a){
}
int test(int a, int b){
return a + b;
}
}
9.return跳出方法
在方法中单独使用return语句,可以用来提前结束方法的执行。
如,下面的divide方法中,当除数为0时,就提前结束方法的执行。
注意:return跳出方法只能用于返回值类型为void的方法
public class Return {
public static void main(String[] args) {
System.out.println("开始。。。");
divide(10,0);
System.out.println("结束。。。");
}
public static void divide(int a,int b){
if (b == 0){
System.out.println("您的除数不能为零");
return;//直接跳出并结束当前divide方法的执行
}
int c = a / b;
System.out.println(c);
}
}
补充:
/*
需求:
数字是有绝对值的,负数的绝对值是它本身取反,非负数的绝对值是它本身。
请定义一个方法,方法能够得到一个小数类型数字的绝对值并返回。请定义方法并测试
比如:
小数数字 -6.6 的绝对值是 6.6
小数数字 6.6 的绝对值是 6.6
三要素:
1.方法名称: abs
2.是否有未知数据参加运算: double num
3.是否产生结果数据: double
其实很多功能在java中已经定义完毕了
java.lang.Math类: 专门用来完成各种数学运算的
abs方法:求绝对值的
pow(m,n)方法: 计算m的n次方的
*/
public class Test03 {
public static void main(String[] args) {
double a = 3.3;
System.out.println("3.3的绝对值: " + Test03.abs(a));
//abs和main处于同一个类中,可以省略类名
System.out.println("3.3的绝对值: " + abs(a));
System.out.println("3.3的绝对值: " + Math.abs(a));
double b = -3.3;
System.out.println("-3.3的绝对值: " + Test03.abs(b));
//abs和main处于同一个类中,可以省略类名
System.out.println("-3.3的绝对值: " + abs(b));
System.out.println("-3.3的绝对值: " + Math.abs(b));
//153是不是水仙花数?
System.out.println((1*1*1 + 5*5*5 + 3*3*3)==153);
System.out.println((Math.pow(1,3)+Math.pow(5,3)+Math.pow(3,3))==153);
}
public static double abs(double num) {
return (num < 0.0) ? -num : num;
}
}
10.案例-抢红包
1.首先,考虑方法是否需要接收数据处理?
需要接收5个红包,至于是哪5个红包,可以有调用者传递;把5个红包的数值,用数组来存储。 所以,参数就是一个数组
2.接着,考虑方法是否需要有返回值?
按照需求的效果,抢完红包就直接打印了,不需要返回值3.最后,考虑方法内部的业务逻辑是怎么的?
思考:红包实际上是数组中的元素,抢红包实际上随机获取数组中的元素;而且一个红包只能抢一次,怎么做呢?我们可以把数组中获取到元素的位置,置为0,下次再或者这个位置的元素一判断为0,再重新获取新的元素,依次内推,直到把数组中所有的元素都获取完。
我们我们把抽红包的思路再整理一下:
1)首先,写一个循环,循环次数为数组的长度
2)每次循环,键盘录入,提示"用户录入任意键抽奖:"
3)随机从数组中产生一个索引,获取索引位置的元素,这个元素就表示抽的红包
如果值不为0,则打印如:"恭喜您,您抽中了520元",把这个位置元素置为0
如果值为0,则说明这个红包被抽过,重新循环到第2步,重新抽奖
【注意:如果当前这一次没有抽中,这一次抽奖机会被浪费掉了,我们可以把控 制循环的次数自减一下】
public class Test6 {
public static void main(String[] args) {
int[] moneys = {100,999,50,520,1314};
start(moneys);
}
//开始抽奖
public static void start(int[] moneys){
//1)首先,写一个循环,循环次数为数组的长度
for (int i = 0; i < moneys.length; i++) {
//2)每次循环,键盘录入,提示"用户录入任意键抽奖:"
while (true){
Scanner sc = new Scanner(System.in);
System.out.print("用户录入任意键抽奖:");
String msg = sc.next();
//3)随机从数组中产生一个索引,获取索引位置的元素,这个元素就表示抽的红包
Random r = new Random();
int index = r.nextInt(moneys.length);
int money = moneys[index];
if(money!=0){
//如果值不为0,则打印如:"恭喜您,您抽中了520元"
System.out.println("恭喜您,您抽中了"+money+"元");
moneys[index] = 0;
break;
}
}
}
}
}
11.案例-找素数(!!!)
再思考题目需求该怎么做?打印输出101~200之间的素数,并求有多少个?,我们也是把这个需求写成一个方法,还是按照三个步骤分析方法如何编写。
1.首先,考虑方法是否需要接收数据处理?
该方法是求一个范围内的素数,一个范围需要两个数据来确定,比如:101~200
所以,方法需要两个参数来接收范围的开始值start,和范围的结束值end2.接着,考虑方法是否需要返回值?
该方法需要求一个范围内的素数的个数
所以,返回值就是素数的个数3.最后,考虑方法内部的业务逻辑
思考:怎么判断一个数是素数呢?要仅仅抓住素数的要求:“只能被1和本身整除的数是素数”。我们可以从反向思考,如果这个数只要能被除了1和本身以外的数整除,那么这个数就不是素数。
方法一:
public class Test7 {
public static void main(String[] args) {
System.out.println(getcount(101, 200));
}
public static int getcount(int a,int b){
int count = 0;
//先循环打印出每一个数字
for (int i = a; i <= b; i++) {
//信号位思想
boolean isPrime = true;
//在每一个数字循环时判断它能不能被除了1和它本身的其他数字整除
//从1到它本身的1/2进行遍历,看是否存在此外的数字能被他整除
if (i <= 1){
isPrime = false;//假设当前遍历的数据为素数
}
for (int j = 2; j <= i / 2; j++) {
if (i % j == 0) {
//遍历完所有小于它本身一半的数字之后发现有能被它整除的数字才能确定它此时不是素数
isPrime = false;
}
// if (i % j != 0) {
count++; //这种写法是错误的,本应该是遍历完所有小于它1/2的数字之后才能
// 确定到底是不是素数,可是现在只要碰到第一个不是零就当他是素数,并没有把所有数字遍历完
// //所以应该采用信号位思想
// }
}
if (isPrime){
System.out.println(i);
count++;
}
}
return count;
}
}
方法二:
独立功能,独立成方法
public class Test8 {
public static void main(String[] args) {
for (int i = 101; i <= 200; i++) {
//i = 101 102 103 ... 199 200
//每遍历到一个数据,都可以把这个数据交给一个方法判断是否是素数,是则输出
//独立功能,独立成方法
if (isSushu(i)){
System.out.println(i);
}
}
}
//是素数返回真,不是素数返回假
public static boolean isSushu(int number){
for (int i = 2; i <= number / 2 ; i++) {
if(number % i == 0){
return false;//遍历完所有的数字发现有能被其整除的数字,所以不是素数
}
}
return true;//是素数
}
}
12.案例-双色球
判断是否中奖:
编写一个方法,判断用户的彩票号码是否中奖,具体中奖规则如下
-
6个红球+1个蓝球 ,奖金1000万
-
6个红球+0个蓝球,奖金500万
-
5个红球+1个蓝球,奖金3000块
-
5个红球+0个蓝球,或者4个红球+1个蓝球,奖金200块
-
4个红球+0个蓝球,或者3个红球+1个蓝球,奖金10块
-
小于3个红球+1个蓝球,奖金5块
-
如果前面的都不成立,就中奖,算你为福利事业做贡献了。
快捷键:ctrl + alt + t 把选中的代码嵌入循环中
import java.util.Random;
import java.util.Scanner;
public class DoubleBall {
public static void main(String[] args) {
//目标:完成双色球系统的开发
int[] userNumbers = userSelectNumber();
System.out.println("您投注的号码:");
//System.out.println(userNumber);//这样的写法是错误的打印出来是地址,必须要写打印方法
printArray(userNumbers);
int[] luckNumbers = createLuckNumber();
System.out.println("中奖的号码:");
printArray(luckNumbers);
judge(userNumbers,luckNumbers);
}
public static void printArray(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
System.out.print(i == arr.length - 1 ? arr[i] : arr[i] + ",");
}
System.out.println("]");
}
/**
* 1.设计一个方法,用于让用户投注一组号码并返回(前6个是红球号码,最后1个是蓝球号码)
*/
public static int[] userSelectNumber() {
//2.创建一个整型数组,用于存储用户投注的7个号码
int[] numbers = new int[7];
//number = {0,0,0,0,0,0,0}
//3.遍历前六个位置让用户依次投注6个红球号码,存入
Scanner sc = new Scanner(System.in);
for (int i = 0; i < numbers.length - 1; i++) {
//4.开始让用户为当前位置投注一个红球号码(1-33之间,不能重复)
while (true) {
System.out.println("请您输入第" + (i + 1) + "个红球号码(1-33之间,不能重复)");
int number = sc.nextInt();
//5.先判断用户输入的红球号码是否在1-33之间
if (number < 1 || number > 33) {
System.out.println("对不起,您输入的红球号码吗不在1-33之间,请确认!");
} else {
//号码是在1-33之间了,接着判断号码是否重复
if (exist(numbers, number)) {
//number当前这个红球号码是重复了
System.out.println("对不起!您当前输入的红球号码前面选择过,重复了,请确认!");
} else {
//number记住的这个号码没有重复了,就可以直接使用了
numbers[i] = number;
break;//结束当前死循环
}
}
}
}
//6.投注最后一个蓝球号码
while (true) {
System.out.println("请您输入最后一个蓝球号码(1-16):");
int number = sc.nextInt();
if (number < 1 || number > 16) {
System.out.println("对不起,您输入的蓝球号码范围不对!");
} else {
numbers[6] = number;
break;//蓝球号码录入成功,结束死循环
}
}
return numbers;
}
private static boolean exist(int[] numbers, int number) {
//需求:判断number这个数字是否在numbers数组中存在
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == 0) {
break;//优化:不再判断数组数字为0的情况
}
if (numbers[i] == number) {
return true;
}
}
return false;
}
/**
* 2.设计一个方法:随机一组中奖号码出来(6个红球号码,1个蓝球号码)
*/
public static int[] createLuckNumber() {
//1.创建一个整型数组,用于存储这7个号码
int[] numbers = new int[7];
Random r = new Random();
//2.遍历前6个位置处,依次随机一个红球号码存入(1-33不重复)
for (int i = 0; i < numbers.length - 1; i++) {
while (true) {
//3.为当前位置随机一个红球号码出来并存入
int number = r.nextInt(33) + 1;
//4.判断是否重复
if (!exist(numbers, number)) {
//number不重复
numbers[i] = number;
break;//结束死循环
}
}
}
//5.录入一个蓝球号码(1-16)
numbers[6] = r.nextInt(16) + 1;
return numbers;
}
/**
* 3.传入两个号码,用来判断用户投注号码的中奖情况
*/
public static void judge(int[] userNumbers, int[] luckNumbers) {
//userNumbers = {12,14,16,18,23,26,8}
//userNumbers = {16,17,18,19,26,32,8}
//分别定义两个变量分别记住红球记住了几个,蓝球命中了几个
int redCount = 0;
int blueCount = 0;
//先判断红球命中数量
for (int i = 0; i < userNumbers.length - 1; i++) {
for (int i1 = 0; i1 < luckNumbers.length - 1; i1++) {
if (userNumbers[i] == luckNumbers[i1]) {
redCount++;
break;//命中之后不需要再往后找,直接跳出内部循环
}
}
}
//3.判断蓝球是否命中了
blueCount = userNumbers[6] == luckNumbers[6] ? 1 : 0;
System.out.println("您命中的红球数量是:" + redCount);
System.out.println("您命中的蓝球数量是:" + blueCount);
//4.判断中奖详情,并输出结果
if (redCount == 6 && blueCount == 1) {
System.out.println("恭喜您,中奖1000万");
}else if (redCount == 6 && blueCount == 0) {
System.out.println("恭喜您,中奖500万");
}else if (redCount == 5 && blueCount == 1){
System.out.println("恭喜您,中奖3000元,出去吃小龙虾把");
}else if (redCount == 5 && blueCount ==0 || redCount == 4 && blueCount == 1){
System.out.println("恭喜您,中奖200元小奖");
}else if (redCount == 4 && blueCount == 0 || redCount == 3 && blueCount == 1){
System.out.println("恭喜您,中奖10元");
}else if (redCount < 3 && blueCount == 1){
System.out.println("恭喜您,中奖5元");
}else {
System.out.println("感谢您为福利事业做出的巨大贡献!!!");
}
}
}