Skip to content

Commit e1a3fa2

Browse files
committed
新增 Java 章节内容:39-隐藏的 this 自引用,包含参数和返回值的详细示例
1 parent e1e4cb2 commit e1a3fa2

File tree

5 files changed

+961
-0
lines changed

5 files changed

+961
-0
lines changed

src/.DS_Store

0 Bytes
Binary file not shown.

src/Java/chapter02/37.md

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,292 @@ footer: 长期招收编程一对一学员!微信:Jiabcdefh, <a href="https:/
3232
- 看代码,学习参数传递;
3333
- 看代码,学习返回值的传递;
3434

35+
## 2. 代码示例
36+
37+
::: code-tabs
38+
39+
@tab RunLittleSupperMarketAppMainV2
40+
41+
```java
42+
package com.geekbang;
43+
44+
import com.geekbang.supermarket.LittleSuperMarket;
45+
import com.geekbang.supermarket.MerchandiseV2;
46+
47+
public class RunLittleSupperMarketAppMainV2 {
48+
public static void main(String[] args) {
49+
// 创建一个小超市类
50+
LittleSuperMarket littleSuperMarket = new LittleSuperMarket();
51+
// 依次给超市的名字,地址,停车位赋值
52+
littleSuperMarket.superMarketName = "有家小超市";
53+
littleSuperMarket.address = "浦东新区世纪大道666号";
54+
littleSuperMarket.parkingCount = 100;
55+
// 给超市200种商品
56+
littleSuperMarket.merchandises = new MerchandiseV2[3];
57+
// 统计用的数组
58+
littleSuperMarket.merchandiseSold = new int[littleSuperMarket.merchandises.length];
59+
60+
// 为了使用方便,创建一个商品数组引用,和littleSuperMarket.merchandises指向同一个数组对象
61+
MerchandiseV2[] all = littleSuperMarket.merchandises;
62+
63+
MerchandiseV2 giftNoodle = new MerchandiseV2();
64+
giftNoodle.name = "赠品-面条";
65+
giftNoodle.count = 2000;
66+
giftNoodle.purchasePrice = 5;
67+
giftNoodle.soldPrice = 0.05;
68+
giftNoodle.id = "GIFT001";
69+
70+
MerchandiseV2 giftBowl = new MerchandiseV2();
71+
giftBowl.name = "赠品-碗";
72+
giftBowl.count = 2000;
73+
giftBowl.purchasePrice = 8;
74+
giftBowl.soldPrice = 0.08;
75+
giftBowl.id = "GIFT002";
76+
77+
// 遍历并给200种商品赋值
78+
for (int i = 0; i < all.length; i++) {
79+
// 创建并给商品的属性赋值
80+
MerchandiseV2 m = new MerchandiseV2();
81+
m.name = "商品" + i;
82+
m.count = 200;
83+
m.purchasePrice = (i + 1) * 100;
84+
m.soldPrice = m.purchasePrice * (1 + Math.random());
85+
m.id = "ID" + i;
86+
m.gift = giftNoodle;
87+
// 用创建的商品,给商品数组的第i个引用赋值,all和小超市的商品数组引用指向的是同一个数组对象
88+
all[i] = m;
89+
m.describe();
90+
}
91+
92+
int index = 0;
93+
94+
MerchandiseV2 m = littleSuperMarket.merchandises[index];
95+
96+
int c = 7;
97+
98+
// --------- 参数 ---------
99+
100+
// >> TODO 参数的传递,其实就是赋值。左边是形参,右边是括号里的实参。
101+
// TODO 类似于buy(int countToBuy = (c + 2) * 5)
102+
// >> TODO 参数本身可以是一个表达式,只要表达式的值类型可以和参数类型匹配就可以
103+
double totalCost = m.buy((c + 2) * 5);
104+
System.out.println("商品总价为:" + totalCost);
105+
106+
// >> TODO 对于引用类型,参数同样是一个表达式
107+
boolean biggerThan = m.totalValueBiggerThan(littleSuperMarket.merchandises[index + 1]);
108+
System.out.println(biggerThan);
109+
110+
// >> TODO 方法里的代码并不能改变实参的值。
111+
// TODO 方法里使用的参数相当于一个局部变量。使用方法前,会用实参给局部变量赋值。
112+
MerchandiseV2 paramRef = littleSuperMarket.merchandises[2];
113+
int paramPrime = 7;
114+
115+
System.out.println("调用前");
116+
System.out.println(paramPrime);
117+
System.out.println(paramRef);
118+
119+
m.willOutsideValueChangeIfParameterValueChangeHerePrime(paramPrime);
120+
// 效果类似如下代码
121+
// 形参实参赋值:int intVal = paramPrime;
122+
// 方法里执行:intVal = 99999999;
123+
m.willOutsideValueChangeIfParameterValueChangeHereRef(paramRef);
124+
// 效果类似如下代码
125+
// 形参实参赋值:MerchandiseV2 m2 = paramRef;
126+
// 方法里执行:m2 = gift;
127+
128+
System.out.println("调用后");
129+
System.out.println(paramPrime);
130+
System.out.println(paramRef);
131+
132+
// ------ 返回值 -------
133+
134+
// >> TODO 可以把有返回值的方法,当成一个成员变量,当成一个类型为返回值类型的成员变量
135+
// TODO 关注于返回值并忽略方法执行的部分,使用返回值,就好像在使用一个成员变量
136+
double soldPrice = m.getSoldPrice();
137+
138+
System.out.println(soldPrice);
139+
m.describe();
140+
141+
142+
// >> TODO 给返回值赋值,并不会影响用来充当返回值的变量
143+
144+
System.out.println("调用getGiftAndHowCanOutsideChangeIt和getSoldPrice之前");
145+
146+
m.describe();
147+
148+
MerchandiseV2 giftOfM = m.getGiftAndHowCanOutsideChangeIt();
149+
150+
giftOfM = giftBowl;
151+
152+
double mSoldPrice = m.getSoldPrice();
153+
154+
mSoldPrice = 9999999;
155+
156+
System.out.println("能改变m本身的gift吗?能改变m的soldPrice吗?");
157+
158+
m.describe();
159+
}
160+
}
161+
```
162+
163+
@tab MerchandiseV2
164+
165+
```java
166+
package com.geekbang.supermarket;
167+
168+
public class MerchandiseV2 {
169+
170+
public String name;
171+
public String id;
172+
public int count;
173+
public double soldPrice;
174+
public double purchasePrice;
175+
176+
// describe方法变了一下
177+
public void describe() {
178+
System.out.println("商品名字叫做" + name + ",id是" + id + "。 商品售价是" + soldPrice
179+
+ "。商品进价是" + purchasePrice + "。赠品是" + gift.name + "。价值" + gift.purchasePrice);
180+
}
181+
182+
public double calculateProfit() {
183+
double profit = soldPrice - purchasePrice;
184+
if (profit <= 0) {
185+
return 0;
186+
}
187+
return profit;
188+
}
189+
190+
// >> TODO 参数是定义在方法名字后面的括号里的
191+
// >> TODO 参数定义的规范和变量一样,都是类型名字加标识符,这里的标识符我们叫做参数名。
192+
// >> TODO 方法体中的代码可以使用参数
193+
// >> TODO 参数的值在调用方法的时候需要给出,有的资料叫做实参(实际参数)
194+
// >> TODO 对应的,方法定义这里的参数,叫做形参(形式参数)
195+
public double buy(int countToBuy) {
196+
if (count < countToBuy) {
197+
System.out.println("商品库存不够");
198+
return -1;
199+
}
200+
201+
System.out.println("商品单价为" + purchasePrice);
202+
203+
int fullPriceCount = countToBuy / 2 + countToBuy % 2;
204+
int halfPriceCount = countToBuy - fullPriceCount;
205+
double totalCost = purchasePrice * fullPriceCount + halfPriceCount * purchasePrice / 2;
206+
207+
count -= countToBuy;
208+
209+
return totalCost;
210+
}
211+
212+
// >> TODO 一个方法可以有多个参数,多个参数之间用逗号隔开
213+
public double buyAndPrintLeft(int countToBuy, boolean printLeft) {
214+
if (count < countToBuy) {
215+
System.out.println("商品库存不够");
216+
if (printLeft) {
217+
System.out.println("商品剩余库存为" + count);
218+
}
219+
return -1;
220+
}
221+
222+
System.out.println("商品单价为" + purchasePrice);
223+
224+
int fullPriceCount = countToBuy / 2 + countToBuy % 2;
225+
int halfPriceCount = countToBuy - fullPriceCount;
226+
double totalCost = purchasePrice * fullPriceCount + halfPriceCount * purchasePrice / 2;
227+
228+
count -= countToBuy;
229+
230+
if (printLeft) {
231+
System.out.println("商品剩余库存为:" + printLeft);
232+
}
233+
234+
return totalCost;
235+
}
236+
237+
// >> TODO 参数可以是任何类型,包括自定义类型,甚至是自己的类型都没问题
238+
public boolean totalValueBiggerThan(MerchandiseV2 merchandiseV2) {
239+
return count * purchasePrice > merchandiseV2.purchasePrice * merchandiseV2.count;
240+
}
241+
242+
// >> TODO 参数可以是任何类型,包括自定义类型,甚至是自己的类型都没问题
243+
public boolean isTheBiggestTotalValueOne(LittleSuperMarket littleSuperMarket) {
244+
double totalValue = count * purchasePrice;
245+
for (int i = 0; i < littleSuperMarket.merchandises.length; i++) {
246+
MerchandiseV2 m = littleSuperMarket.merchandises[i];
247+
double newTotalValue = m.count * m.purchasePrice;
248+
if (totalValue < newTotalValue) {
249+
// >> TODO 执行到return的时候,方法直接结束,不管是不是在循环中,是在第几层循环中。
250+
return false;
251+
}
252+
}
253+
return true;
254+
}
255+
256+
// ---------------------------新增加的内容---------------------------
257+
258+
public MerchandiseV2 gift;
259+
260+
public double getSoldPrice() {
261+
return soldPrice;
262+
}
263+
264+
public String getName() {
265+
return name;
266+
}
267+
268+
public MerchandiseV2 getGiftAndHowCanOutsideChangeIt() {
269+
return gift;
270+
}
271+
272+
273+
public void willOutsideValueChangeIfParameterValueChangeHereRef(MerchandiseV2 m2) {
274+
m2 = gift;
275+
}
276+
277+
public void willOutsideValueChangeIfParameterValueChangeHerePrime(int intVal) {
278+
intVal = 99999999;
279+
}
280+
281+
public void changeToTheSameGift(MerchandiseV2 m2) {
282+
m2.gift = gift;
283+
}
284+
285+
}
286+
```
287+
288+
@tab LittleSuperMarket
289+
290+
```java
291+
package com.geekbang.supermarket;
292+
293+
public class LittleSuperMarket {
294+
public String superMarketName;
295+
public String address;
296+
public int parkingCount;
297+
public double incomingSum;
298+
public MerchandiseV2[] merchandises;
299+
public int[] merchandiseSold;
300+
301+
public MerchandiseV2 getBiggestProfitMerchandise() {
302+
MerchandiseV2 curr = null;
303+
for (int i = 0; i < merchandises.length; i++) {
304+
MerchandiseV2 m = merchandises[i];
305+
// 这个逻辑有问题吗?相同的利润怎么判断?
306+
if (curr == null || curr.calculateProfit() < m.calculateProfit()) {
307+
curr = m;
308+
}
309+
}
310+
return curr;
311+
}
312+
}
313+
```
314+
315+
316+
317+
:::
318+
319+
320+
35321

36322

37323

465 KB
Loading

0 commit comments

Comments
 (0)