36-参数:让 Merchandise 计算多件商品的总价
0. 目录
- 第二件半价哦!
- 参数:告诉商品实例要购买多少个
1. 第二件半价哦!
package com.bornforthis;
import com.bornforthis.supermarket.LittleSuperMarket;
import com.bornforthis.supermarket.MerchandiseV2;
import java.util.Scanner;
public class RunLittleSupperMarketAppMain {
public static void main(String[] args) {
// 创建一个小超市类
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
// 依次给超市的名字,地址,停车位赋值
littleSuperMarket.superMarketName = "有家小超市";
littleSuperMarket.address = "浦东新区世纪大道666号";
littleSuperMarket.parkingCount = 100;
// 给超市200种商品
littleSuperMarket.merchandises = new MerchandiseV2[200];
// 统计用的数组
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
MerchandiseV2[] all = littleSuperMarket.merchandises;
// 遍历并给200种商品赋值
for (int i = 0; i < all.length; i++) {
// 创建并给商品的属性赋值
MerchandiseV2 m = new MerchandiseV2();
m.name = "商品" + i;
m.count = 200;
m.purchasePrice = Math.random() * 200;
m.soldPrice = m.purchasePrice * (1 + Math.random());
m.id = "ID" + i;
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
all[i] = m;
}
// 创建一个Scanner读取输入
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("今日超市大特惠,所有商品第二件半价!选择要购买的商品索引:");
int index = scanner.nextInt();
if (index < 0) {
System.out.println("欢迎再次光临!");
break;
}
double price = littleSuperMarket.merchandises[index].purchasePrice;
System.out.println("商品单价为" + price);
System.out.println("请输入要购买的数量:");
int count = scanner.nextInt();
if (littleSuperMarket.merchandises[index].count < count) {
System.out.println("商品库存不足。");
continue;
}
int fullPriceCount = count / 2 + count % 2;
int halfPriceCount = count - fullPriceCount;
double totalCost = price * fullPriceCount + halfPriceCount * price / 2;
littleSuperMarket.merchandises[index].count -= count;
System.out.println("商品总价为:" + totalCost);
}
}
}
package com.geekbang;
import com.geekbang.supermarket.LittleSuperMarket;
import com.geekbang.supermarket.MerchandiseV2;
import java.util.Scanner;
public class RunLittleSupperMarketAppMainExample {
public static void main(String[] args) {
// 创建一个小超市类
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
// 依次给超市的名字,地址,停车位赋值
littleSuperMarket.superMarketName = "有家小超市";
littleSuperMarket.address = "浦东新区世纪大道666号";
littleSuperMarket.parkingCount = 100;
// 给超市200种商品
littleSuperMarket.merchandises = new MerchandiseV2[200];
// 统计用的数组
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
MerchandiseV2[] all = littleSuperMarket.merchandises;
// 遍历并给200种商品赋值
for (int i = 0; i < all.length; i++) {
// 创建并给商品的属性赋值
MerchandiseV2 m = new MerchandiseV2();
m.name = "商品" + i;
m.count = 200;
m.purchasePrice = Math.random() * 200;
m.soldPrice = m.purchasePrice * (1 + Math.random());
m.id = "ID" + i;
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
all[i] = m;
}
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("今日超市大特惠,所有商品第二件半价!选择要购买的商品索引:");
int index = scanner.nextInt();
if (index < 0) {
break;
}
if (index >= all.length) {
System.out.println("商品索引超出界限");
continue;
}
MerchandiseV2 m = all[index];
System.out.println("商品" + m.name + "售价为" + m.soldPrice + "。请问购买几个?");
int numToBuy = scanner.nextInt();
if (numToBuy > m.count) {
System.out.println("库存不足");
continue;
}
int fullPriceCount = numToBuy / 2 + numToBuy % 2;
int halfPriceCount = numToBuy - fullPriceCount;
double totalCost = fullPriceCount * m.soldPrice + (halfPriceCount * m.soldPrice / 2);
m.count -= numToBuy;
System.out.println("选购的商品总价为" + totalCost);
}
}
}
1.1 半件实现逻辑详解
count / 2 + count % 2;
公式解析,可以除的尽的,是偶数的倍数,那就是购买两件的数量。而余数则是:没有买两件「偶数」的件数。
让我们一步步分析:
fullPriceCount = count / 2 + count % 2
这行代码计算需要支付全价的商品数量
count / 2
是整数除法,得到商品总数的一半(向下取整)count % 2
是取余操作,当总数为奇数时等于1,偶数时等于0实际效果是:对于奇数个商品,全价商品会比半价商品多一个
举例:
如果
count = 5
count} / 2 = 2
(整数除法)count % 2 = 1
fullPriceCount} = 2 + 1 = 3
(需要支付全价的商品数)
halfPriceCount = count - fullPriceCount
这行简单地用总数减去全价商品数,得到半价商品数
继续上面的例子,
halfPriceCount = 5 - 3 = 2
totalCost = price * fullPriceCount + halfPriceCount * price / 2
计算总价:全价商品数量 × 单价 + 半价商品数量 × (单价/2)
实现一个"买二赠一半价"的促销策略,其中:
- 当总数为偶数时,正好各一半商品全价和半价
- 当总数为奇数时,全价商品会比半价商品多一个
让我用具体数字举例说明:
// 假设 price = 100
// 情况1:买5个
count = 5
fullPriceCount = 5/2 + 5%2 = 2 + 1 = 3 // 3个全价
halfPriceCount = 5 - 3 = 2 // 2个半价
totalCost = 100*3 + 2*100/2 = 300 + 100 = 400
// 情况2:买6个
count = 6
fullPriceCount = 6/2 + 6%2 = 3 + 0 = 3 // 3个全价
halfPriceCount = 6 - 3 = 3 // 3个半价
totalCost = 100*3 + 3*100/2 = 300 + 150 = 450
这种计算方式确保了:
- 商品总是尽可能平均分配为全价和半价
- 当数量为奇数时,多出的一个商品按全价计算
- 保证了商家在促销的同时维持基本利润
1.2 这种方式有哪些问题?
- 每个用到这个逻辑的地方,都要重复这段代码
- 如果告诉商品要买多少个,商品帮我算多少钱,就不用重复代码了
2. LittleSuperMarket 实现
package com.bornforthis.supermarket;
public class LittleSuperMarket {
public String superMarketName;
public String address;
public int parkingCount;
public double incomingSum;
public MerchandiseV2[] merchandises;
public int[] merchandiseSold;
public MerchandiseV2 getBiggestProfitMerchandise() {
MerchandiseV2 curr = null;
for (int i = 0; i < merchandises.length; i++) {
MerchandiseV2 m = merchandises[i];
// 这个逻辑有问题吗?相同的利润怎么判断?
if (curr == null || curr.calculateProfit() < m.calculateProfit()) {
curr = m;
}
}
return curr;
}
}
2.1 保留相同最大值的前后问题
先分析问题:在当前的代码实现中,if (curr == null || curr.calculateProfit() < m.calculateProfit())
这个条件只处理了两种情况:
curr 为空(第一个商品的情况)
当前商品的利润大于已保存商品的利润
这个逻辑确实存在一个问题:当两个商品的利润相同时,它会保留第一个遇到的最高利润商品。这可能不是最合理的处理方式,因为在利润相同的情况下,我们可能还需要考虑其他因素。
这里有几种可能的改进方案:
方案一:如果就是要保留第一个最高利润商品,那么当前逻辑是可以的,但最好明确注释说明这是有意为之:
// 当利润相同时,保留第一个最高利润的商品 if (curr == null || curr.calculateProfit() < m.calculateProfit()) { curr = m; }
【证明】保留的最大相同毛利润是保留第一个还是最后一个?
package com.bornforthis; public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5, 10, 9, 10, 8, 10}; int max = arr[0]; int maxIndex = 0; for (int i = 0; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; maxIndex = i; } } System.out.println(maxIndex); } } // 输出 5 // TODO:可知返回的是第一个最大值
不保留最后的相同的最大值下标是什么情况?因为不论是
>
还是<
都不会执行相同的情况(3 > 3 => false),只有在 (3 >= 3 => true)保留最后一个最大值,只需要修改如下代码:
if (arr[i] >= max)
方案二:如果要保留最后一个最高利润商品,可以改为:
if (curr == null || curr.calculateProfit() <= m.calculateProfit()) { curr = m; }
方案三:如果遇到相同利润要按照其他条件判断(比如销量、库存等),可以这样处理:
/* * @Time : 2024/12/31 10:12 * @Author : AI悦创 * @FileName: LittleSuperMarket.java * @Software: IntelliJ IDEA * @Version: V1.0 * @Blog : https://bornforthis.cn/ * Code is far away from bugs with the god animal protecting * I love animals. They taste delicious. */ package com.bornforthis.supermarket; public class LittleSuperMarket { public String superMarketName; public String address; public int parkingCount; public double incomingSum; public MerchandiseV2[] merchandises; public int[] merchandiseSold; public MerchandiseV2 getBiggestProfitMerchandise() { MerchandiseV2 curr = null; for (int i = 0; i < merchandises.length; i++) { MerchandiseV2 m = merchandises[i]; if (curr == null) { curr = m; } else { double currProfit = curr.calculateProfit(); double mProfit = m.calculateProfit(); if (currProfit < mProfit) { curr = m; } else if (currProfit == mProfit) { System.out.println("发现相同的利润商品,商品索引为:" + i); // TODO: 相同库存情况下,库存数量少的,表明销量高! if (curr.count > m.count) { curr = m; } } } } return curr; } }
建议选择哪种方案,取决于具体的业务需求:
- 如果只关心找出最高利润,不在意是第一个还是最后一个,用方案1或2都可以
- 如果在利润相同时还需要考虑其他因素,建议使用方案3
- 无论选择哪种方案,都建议添加注释说明处理相同利润的策略,以便其他开发者理解代码逻辑
3. 参数:告诉商品实例要购买多少个
看 MerchandiseV2 中的新方法,学习方法参数相关语法
package com.bornforthis.supermarket;
public class MerchandiseV2 {
public String name;
public String id;
public int count;
public double soldPrice;
public double purchasePrice;
public void describe() {
System.out.println("商品名字叫做" + name + ",id是" + id + "。 商品售价是" + soldPrice
+ "。商品进价是" + purchasePrice + "。商品库存量是" + count +
"。销售一个的毛利润是" + (soldPrice - purchasePrice));
}
// 计算利润💰
public double calculateProfit() {
double profit = soldPrice - purchasePrice;
if(profit <= 0){
return 0;
}
return profit;
}
// >> TODO 参数是定义在方法名字后面的括号里的
// >> TODO 参数定义的规范和变量一样,都是类型名字加标识符,这里的标识符我们叫做参数名。
// >> TODO 方法体中的代码可以使用参数
// >> TODO 参数的值在调用方法的时候需要给出,有的资料叫做实参(实际参数)
// TODO 对应的,方法定义这里的参数,叫做形参(形式参数)
// 如果返回值是负数,就代表购买失败,比如库存不足
public double buy(int countToBuy) {
if (count < countToBuy) {
System.out.println("商品库存不够");
return -1;
}
// FIXME: 销售应该用soldPrice而不是purchasePrice,谢谢 @Novichok 指出这个错误
System.out.println("商品单价为" + soldPrice);
int fullPriceCount = countToBuy / 2 + countToBuy % 2;
int halfPriceCount = countToBuy - fullPriceCount;
double totalCost = soldPrice * fullPriceCount + halfPriceCount * soldPrice / 2;
count -= countToBuy;
return totalCost;
}
}
/*
* @Time : 2024/12/31 11:55
* @Author : AI悦创
* @FileName: RunLittleSupperMarketAppMainV2.java
* @Software: IntelliJ IDEA
* @Version: V1.0
* @Blog : https://bornforthis.cn/
* Code is far away from bugs with the god animal protecting
* I love animals. They taste delicious.
*/
package com.bornforthis;
import com.bornforthis.supermarket.LittleSuperMarket;
import com.bornforthis.supermarket.MerchandiseV2;
import java.util.Scanner;
public class RunLittleSupperMarketAppMainV2 {
public static void main(String[] args) {
// 创建一个小超市类
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
// 依次给超市的名字,地址,停车位赋值
littleSuperMarket.superMarketName = "有家小超市";
littleSuperMarket.address = "浦东新区世纪大道666号";
littleSuperMarket.parkingCount = 100;
// 给超市200种商品
littleSuperMarket.merchandises = new MerchandiseV2[200];
// 统计用的数组
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
MerchandiseV2[] all = littleSuperMarket.merchandises;
// 遍历并给200种商品赋值
for (int i = 0; i < all.length; i++) {
// 创建并给商品的属性赋值
MerchandiseV2 m = new MerchandiseV2();
m.name = "商品" + i;
m.count = 200;
m.purchasePrice = Math.random() * 200;
m.soldPrice = m.purchasePrice * (1 + Math.random());
m.id = "ID" + i;
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
all[i] = m;
}
// 创建一个Scanner读取输入
Scanner scanner = new Scanner(System.in);
MerchandiseV2 m0 = all[0];
while (true) {
System.out.println("今日超市大特惠,所有商品第二件半价!选择要购买的商品索引:");
int index = scanner.nextInt();
if (index < 0) {
System.out.println("欢迎再次光临!");
break;
}
System.out.println("请输入要购买的数量:");
int count = scanner.nextInt();
MerchandiseV2 m = littleSuperMarket.merchandises[index];
double totalCost = m.buy(count);
System.out.println("商品总价为:" + totalCost);
}
}
}
4. 更多参数的语法
package com.geekbang.supermarket;
public class MerchandiseV2 {
public String name;
public String id;
public int count;
public double soldPrice;
public double purchasePrice;
public void describe() {
System.out.println("商品名字叫做" + name + ",id是" + id + "。 商品售价是" + soldPrice
+ "。商品进价是" + purchasePrice + "。商品库存量是" + count +
"。销售一个的毛利润是" + (soldPrice - purchasePrice));
}
public double calculateProfit() {
double profit = soldPrice - purchasePrice;
if(profit <= 0){
return 0;
}
return profit;
}
// >> TODO 参数是定义在方法名字后面的括号里的
// >> TODO 参数定义的规范和变量一样,都是类型名字加标识符,这里的标识符我们叫做参数名。
// >> TODO 方法体中的代码可以使用参数
// >> TODO 参数的值在调用方法的时候需要给出,有的资料叫做实参(实际参数)
// TODO 对应的,方法定义这里的参数,叫做形参(形式参数)
// 如果返回值是负数,就代表购买失败,比如库存不足
public double buy(int countToBuy) {
if (count < countToBuy) {
System.out.println("商品库存不够");
return -1;
}
// FIXME: 销售应该用soldPrice而不是purchasePrice,谢谢 @Novichok 指出这个错误
System.out.println("商品单价为" + soldPrice);
int fullPriceCount = countToBuy / 2 + countToBuy % 2;
int halfPriceCount = countToBuy - fullPriceCount;
double totalCost = soldPrice * fullPriceCount + halfPriceCount * soldPrice / 2;
count -= countToBuy;
return totalCost;
}
// >> TODO 一个方法可以有多个参数,多个参数之间用逗号隔开
// >> TODO 就是你购买并且再打印出来还剩多少个,使用一个参数 boolean printLeft 告诉方法要不要打印!
// 有时我们关心商品还剩多少个,有时候我们不关心还剩多少个;
// >> TODO 方法的返回值只能有一个,但是方法的参数可以有多个;
public double buyAndPrintLeft(int countToBuy, boolean printLeft) {
if (count < countToBuy) {
System.out.println("商品库存不够");
if (printLeft) {
System.out.println("商品剩余库存为" + count);
}
return -1;
}
// FIXME: 销售应该用soldPrice而不是purchasePrice,谢谢 @Novichok 指出这个错误
System.out.println("商品单价为" + soldPrice);
int fullPriceCount = countToBuy / 2 + countToBuy % 2;
int halfPriceCount = countToBuy - fullPriceCount;
double totalCost = soldPrice * fullPriceCount + halfPriceCount * soldPrice / 2;
count -= countToBuy;
if (printLeft) {
System.out.println("商品剩余库存为:" + count);
}
return totalCost;
}
}
/*
* @Time : 2024/12/31 11:55
* @Author : AI悦创
* @FileName: RunLittleSupperMarketAppMainV2.java
* @Software: IntelliJ IDEA
* @Version: V1.0
* @Blog : https://bornforthis.cn/
* Code is far away from bugs with the god animal protecting
* I love animals. They taste delicious.
*/
package com.bornforthis;
import com.bornforthis.supermarket.LittleSuperMarket;
import com.bornforthis.supermarket.MerchandiseV2;
import java.util.Scanner;
public class RunLittleSupperMarketAppMainV2 {
public static void main(String[] args) {
// 创建一个小超市类
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
// 依次给超市的名字,地址,停车位赋值
littleSuperMarket.superMarketName = "有家小超市";
littleSuperMarket.address = "浦东新区世纪大道666号";
littleSuperMarket.parkingCount = 100;
// 给超市200种商品
littleSuperMarket.merchandises = new MerchandiseV2[200];
// 统计用的数组
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
MerchandiseV2[] all = littleSuperMarket.merchandises;
// 遍历并给200种商品赋值
for (int i = 0; i < all.length; i++) {
// 创建并给商品的属性赋值
MerchandiseV2 m = new MerchandiseV2();
m.name = "商品" + i;
m.count = 200;
m.purchasePrice = Math.random() * 200;
m.soldPrice = m.purchasePrice * (1 + Math.random());
m.id = "ID" + i;
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
all[i] = m;
}
// 创建一个Scanner读取输入
Scanner scanner = new Scanner(System.in);
MerchandiseV2 m0 = all[0];
while (true) {
System.out.println("今日超市大特惠,所有商品第二件半价!选择要购买的商品索引:");
int index = scanner.nextInt();
if (index < 0) {
System.out.println("欢迎再次光临!");
break;
}
System.out.println("请输入要购买的数量:");
int count = scanner.nextInt();
// MerchandiseV2 m = littleSuperMarket.merchandises[index];
// double totalCost = m.buy(count);
// System.out.println("商品总价为:" + totalCost);
// TODO: 和上面 buy 的计算逻辑其实是一样的,只是添加了一个打印剩余库存的逻辑
MerchandiseV2 m = littleSuperMarket.merchandises[index];
// TODO: 这时候不添加 true,只添加 count,会发生什么?
// 会发现,会报错!
double totalCost = m.buyAndPrintLeft(count, true);
System.out.println("商品总价为:" + totalCost);
}
}
}
5. 参数可以是任何类型
参数可以是任何类型,包括自定义类型,甚至是自己的类型都没问题
// >> TODO 参数可以是任何类型,包括自定义类型,甚至是自己的类型都没问题
public boolean totalValueBiggerThan(MerchandiseV2 merchandiseV2) {
return count * purchasePrice > merchandiseV2.purchasePrice * merchandiseV2.count;
}
/*
* @Time : 2024/12/31 11:55
* @Author : AI悦创
* @FileName: RunLittleSupperMarketAppMainV2.java
* @Software: IntelliJ IDEA
* @Version: V1.0
* @Blog : https://bornforthis.cn/
* Code is far away from bugs with the god animal protecting
* I love animals. They taste delicious.
*/
package com.bornforthis;
import com.bornforthis.supermarket.LittleSuperMarket;
import com.bornforthis.supermarket.MerchandiseV2;
import java.util.Scanner;
public class RunLittleSupperMarketAppMainV2 {
public static void main(String[] args) {
// 创建一个小超市类
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
// 依次给超市的名字,地址,停车位赋值
littleSuperMarket.superMarketName = "有家小超市";
littleSuperMarket.address = "浦东新区世纪大道666号";
littleSuperMarket.parkingCount = 100;
// 给超市200种商品
littleSuperMarket.merchandises = new MerchandiseV2[200];
// 统计用的数组
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
MerchandiseV2[] all = littleSuperMarket.merchandises;
// 遍历并给200种商品赋值
for (int i = 0; i < all.length; i++) {
// 创建并给商品的属性赋值
MerchandiseV2 m = new MerchandiseV2();
m.name = "商品" + i;
m.count = 200;
m.purchasePrice = Math.random() * 200;
m.soldPrice = m.purchasePrice * (1 + Math.random());
m.id = "ID" + i;
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
all[i] = m;
}
// 创建一个Scanner读取输入
Scanner scanner = new Scanner(System.in);
MerchandiseV2 m0 = all[0]; // 不论怎么样,我们都使用第一个商品跟它比较
while (true) {
System.out.println("今日超市大特惠,所有商品第二件半价!选择要购买的商品索引:");
int index = scanner.nextInt();
if (index < 0) {
System.out.println("欢迎再次光临!");
break;
}
System.out.println("请输入要购买的数量:");
int count = scanner.nextInt();
// MerchandiseV2 m = littleSuperMarket.merchandises[index];
// double totalCost = m.buy(count);
// System.out.println("商品总价为:" + totalCost);
// TODO: 和上面 buy 的计算逻辑其实是一样的,只是添加了一个打印剩余库存的逻辑
MerchandiseV2 m = littleSuperMarket.merchandises[index];
// TODO: 这时候不添加 true,只添加 count,会发生什么?
// 会发现,会报错!
double totalCost = m.buyAndPrintLeft(count, true);
boolean m0BiggerThan = m0.totalValueBiggerThan(m); // 这里我们注重的不再是商品、超市的逻辑,更多的是注重方法的调用
System.out.println("m0的总价值比用户选择的要大:" + m0BiggerThan);
System.out.println("商品总价为:" + totalCost);
}
}
}
6. 自定义类型参数
// >> TODO 参数可以是任何类型,包括自定义类型
// >> TODO 当前的商品是不是超市当中,价值最高的商品!
public boolean isTheBiggestTotalValueOne(LittleSuperMarket littleSuperMarket) {
double totalValue = count * purchasePrice;
for (int i = 0; i < littleSuperMarket.merchandises.length; i++) {
MerchandiseV2 m = littleSuperMarket.merchandises[i];
double newTotalValue = m.count * m.purchasePrice;
if (totalValue < newTotalValue) { // 当然在 Java 中,我们是不推荐使用 double 进行比较
// 执行到return的时候,方法直接结束,不管是不是在循环中,是在第几层循环中。
return false;
}
}
return true;
}
package com.bornforthis;
import com.bornforthis.supermarket.LittleSuperMarket;
import com.bornforthis.supermarket.MerchandiseV2;
import java.util.Scanner;
public class RunLittleSupperMarketAppMainV2 {
public static void main(String[] args) {
// 创建一个小超市类
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
// 依次给超市的名字,地址,停车位赋值
littleSuperMarket.superMarketName = "有家小超市";
littleSuperMarket.address = "浦东新区世纪大道666号";
littleSuperMarket.parkingCount = 100;
// 给超市200种商品
littleSuperMarket.merchandises = new MerchandiseV2[200];
// 统计用的数组
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
MerchandiseV2[] all = littleSuperMarket.merchandises;
// 遍历并给200种商品赋值
for (int i = 0; i < all.length; i++) {
// 创建并给商品的属性赋值
MerchandiseV2 m = new MerchandiseV2();
m.name = "商品" + i;
m.count = 200;
m.purchasePrice = Math.random() * 200;
m.soldPrice = m.purchasePrice * (1 + Math.random());
m.id = "ID" + i;
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
all[i] = m;
}
// 创建一个Scanner读取输入
Scanner scanner = new Scanner(System.in);
MerchandiseV2 m0 = all[0];
while (true) {
System.out.println("今日超市大特惠,所有商品第二件半价!选择要购买的商品索引:");
int index = scanner.nextInt();
if (index < 0) {
System.out.println("欢迎再次光临!");
break;
}
System.out.println("请输入要购买的数量:");
int count = scanner.nextInt();
MerchandiseV2 m = littleSuperMarket.merchandises[index];
System.out.println("用户选择的商品是超市里价值最高的:" +
m.isTheBiggestTotalValueOne(littleSuperMarket));
double totalCost = m.buyAndPrintLeft(count, true);
boolean m0BiggerThan = m0.totalValueBiggerThan(m);
System.out.println("m0的总价值比用户选择的要大:" + m0BiggerThan);
System.out.println("商品总价为:" + totalCost);
}
}
}
7. 实参和形参
- 形参是方法定义时在方法头部声明的变量。它们是方法的“占位符”,用于接收调用该方法时传递的实际数据。
- 实参是调用方法时实际传递的值或变量。在调用方法时,实参会被传递给形参。
7.1 形参(形式参数)
- 形参是在定义方法时声明的参数。
- 它是方法的输入,占位符,用来接收调用者传递的实际值。
- 形参存在于方法的声明中,只有当方法被调用时,它才会被赋值。
例子:
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
在上面的代码中:String name
是形参,它定义了 greet 方法接受一个字符串类型的参数。
7.2 实参(实际参数)
- 实参是在调用方法时传递的值。
- 它是形参的实际值,用来完成具体的计算或逻辑。
- 实参会被赋值给对应的形参。
例子:
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.greet("Alice"); // "Alice" 是实参
}
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
}
在调用 greet("Alice")
时:"Alice"
是实参,它被传递给方法中的形参 name。
7.3 实参与形参的关系
- 方法调用时传递值:
- 当调用方法时,实参的值会被复制到形参中。
- Java 中的参数传递是按值传递的(即复制实参的值到形参)。
- 作用范围:
- 形参的作用范围仅限于方法内部。
- 方法执行完后,形参被销毁。
7.4 按值传递的演示
public class Main {
public static void main(String[] args) {
int number = 10;
System.out.println("Before calling method: " + number);
changeValue(number); // 实参传递
System.out.println("After calling method: " + number);
}
public static void changeValue(int num) {
num = 20; // 修改形参的值
System.out.println("Inside method: " + num);
}
}
Before calling method: 10
Inside method: 20
After calling method: 10
说明: 在 changeValue 方法中,形参 num 的值被修改为 20,但它不影响实参 number 的值,因为 num 是实参 number 的副本。
7.5 引用类型的参数传递
当参数是引用类型(如数组或对象)时,传递的也是引用的副本,但由于引用指向同一个内存地址,方法内的修改会影响到实际对象。
public class Main {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
System.out.println("Before calling method: " + numbers[0]);
changeArray(numbers); // 实参传递
System.out.println("After calling method: " + numbers[0]);
}
public static void changeArray(int[] arr) {
arr[0] = 99; // 修改数组第一个元素
System.out.println("Inside method: " + arr[0]);
}
}
Before calling method: 1
Inside method: 99
After calling method: 99
说明: 方法修改了数组的第一个元素,实参 numbers 的值也被改变了,因为数组引用指向的是同一块内存。
7.6 总结
- 形参:方法声明时定义的参数,是占位符。
- 实参:调用方法时实际传递的值。
- 参数传递:
- 基本类型:按值传递,方法内修改不会影响实参。
- 引用类型:传递引用的副本,方法内修改会影响原对象。
7.7 更多例子
public class Example {
// 定义方法时,a 和 b 是形参
public static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
// 在调用方法时,3 和 5 是实参
int result = add(3, 5);
System.out.println("结果是: " + result);
}
}
add
方法的定义中,a
和b
是形参,它们用于接收传递给方法的数据。在
main
方法中,当调用add(3, 5)
时,3
和5
就是实参,它们的值会传递给形参a
和b
,然后在方法内部进行运算。
欢迎关注我公众号:AI悦创,有更多更好玩的等你发现!
公众号:AI悦创【二维码】

AI悦创·编程一对一
AI悦创·推出辅导班啦,包括「Python 语言辅导班、C++ 辅导班、java 辅导班、算法/数据结构辅导班、少儿编程、pygame 游戏开发」,全部都是一对一教学:一对一辅导 + 一对一答疑 + 布置作业 + 项目实践等。当然,还有线下线上摄影课程、Photoshop、Premiere 一对一教学、QQ、微信在线,随时响应!微信:Jiabcdefh
C++ 信息奥赛题解,长期更新!长期招收一对一中小学信息奥赛集训,莆田、厦门地区有机会线下上门,其他地区线上。微信:Jiabcdefh
方法一:QQ
方法二:微信:Jiabcdefh
