@ -404,17 +404,209 @@ public class CircleWithPrivateDataFields {
## 6. 对象作为函数参数
值传递和引用传递
如果是基本类型的变量, 那么使用的是值传递, 上一章已经说明了。如果是引用类型( 大写的类型, 对象类型) , 那么使用的是引用传递。引用传递如同C语言的指针一样, 我们可以在函数的内部改变引用对象内部成员的值。
```java
class CircleWithPrivateDataFields {
/** The radius of the circle */
private double radius = 1;
/** The number of the objects created */
private static int numberOfObjects = 0;
/** Construct a circle with radius 1 */
CircleWithPrivateDataFields() {
numberOfObjects++;
}
/** Construct a circle with a specified radius */
public CircleWithPrivateDataFields(double newRadius) {
radius = newRadius;
numberOfObjects++;
}
// get radius
public double getRadius() {
return radius;
}
// set radius
public void setRadius(double radius) {
this.radius = radius;
}
/** Return numberOfObjects */
public static int getNumberOfObjects() {
return numberOfObjects;
}
/** Return the area of this circle */
public double getArea() {
return radius * radius * Math.PI;
}
}
public class TestPassObject {
/** Main method */
public static void main(String[] args) {
// Create a Circle object with radius 1
CircleWithPrivateDataFields myCircle = new CircleWithPrivateDataFields(1);
// Print areas for radius 1, 2, 3, 4, and 5.
int n = 5;
printAreas(myCircle, n);
// See myCircle.radius and times
System.out.println("\n" + "Radius is " + myCircle.getRadius());
System.out.println("n is " + n);
}
/** Print a table of areas for radius */
public static void printAreas(CircleWithPrivateDataFields c, int times) {
System.out.println("Radius \t\tArea");
while (times >= 1) {
System.out.println(c.getRadius() + "\t\t" + c.getArea());
c.setRadius(c.getRadius() + 1);
times--;
}
}
}
```
`printAreas` 函数接受两个参数,第一个参数是`CircleWithPrivateDataFields`类型的引用变量,第二个参数是循环的次数;主函数先生成一个`CircleWithPrivateDataFields`对象,然后使用`printAreas`函数;在`printAreas`函数内部, 进行了5次循环, 每次通过`CircleWithPrivateDataFields`的`setRadius`函数使得`CircleWithPrivateDataFields`对象的半径+1; 然后再打印`CircleWithPrivateDataFields`对象的面积;当`printAreas`函数执行完成后,我们在主函数中打印`CircleWithPrivateDataFields`对象`c`的半径, 发现半径已经变成了6( 初始值是1, 5次累加后变成6) 。
这个例子证明, 如果是引用变量, 在函数内部可以改变传入对象的成员变量值; 其实这里使用的是setter函数改变半径的, 因为半径是私有的; 如果半径是public的, 使用直接赋值也可以改变。
如果我么在`printAreas`函数执行完成后, 打印n这个变量( 作为参数times传入`printAreas`函数) , 会发现这个值还是5; 因为基本类型的变量使用的是值传递。
## 7. 对象数组
## 8. Immutable 类与对象
上一章我们学了数组,不过数组中元素的类型是基本类型。其实数组也是一个特殊的类(其变量也是引用变量),那么我们也可以在函数内部改变数组元素的值,无论数组内部是基本类型还是引用类型。
数组元素是基本类型:
```java
public class Test {
public static void main(String[] args) {
int a[] = { 1, 2, 3, 4, 5 };
System.out.printf("Before run changeArray, a[0] is %d\n", a[0]);
changeArray(a);
System.out.printf("After run changeArray, a[0] is %d\n", a[0]);
}
static void changeArray(int a[]) {
a[0] = 1000;
}
}
```
运行后, 我们发现a[0]的值已经被修改成了1000, 这种例子前面也遇到过。
下面看看数组中的元素是引用类型的情况,借用上个例子的`CircleWithPrivateDataFields`类型。
```java
public class TotalArea {
/** Main method */
public static void main(String[] args) {
// Declare circleArray
CircleWithPrivateDataFields[] circleArray;
// Create circleArray
circleArray = createCircleArray();
// Print circleArray and total areas of the circles
printCircleArray(circleArray);
}
/** Create an array of Circle objects */
public static CircleWithPrivateDataFields[] createCircleArray() {
CircleWithPrivateDataFields[] circleArray = new CircleWithPrivateDataFields[5];
for (int i = 0; i < circleArray.length ; i + + ) {
circleArray[i] = new CircleWithPrivateDataFields(Math.random() * 100);
}
// Return Circle array
return circleArray;
}
/** Print an array of circles and their total area */
public static void printCircleArray(CircleWithPrivateDataFields[] circleArray) {
System.out.printf("%-30s%-15s\n", "Radius", "Area");
for (int i = 0; i < circleArray.length ; i + + ) {
System.out.printf("%-30f%-15f\n", circleArray[i].getRadius(), circleArray[i].getArea());
}
System.out.println("-----------------------------------------");
// Compute and display the result
System.out.printf("%-30s%-15f\n", "The total areas of circles is", sum(circleArray));
}
/** Add circle areas */
public static double sum(CircleWithPrivateDataFields[] circleArray) {
// Initialize sum
double sum = 0;
// Add areas to sum
for (int i = 0; i < circleArray.length ; i + + )
sum += circleArray[i].getArea();
return sum;
}
}
```
1. 数组可以作为函数的返回值,例如`createCircleArray`函数, 生产了5个元素的数组, 其半径都随机的。
2. `CircleWithPrivateDataFields` 和`sum`函数都是数组作为参数。
你可以在函数中改变数组中引用对象内部成员的值,如同**对象作为函数参数**中一样。
## 8. Immutable 类与对象(了解)
If the contents of an object cannot be changed once the object is created, the object is called an immutable( 不变的) object and its class is called an immutable class. If you delete the set method in the Circle class in Listing 8.10, the class would be immutable because radius is private and cannot be changed without a set method.
这个概念需要了解, 我们目前使用到的Immutable类是Spring, 下一章中所有的 warp 类型也是 Immutable。
## 9. 变量作用域
The scope of instance and static variables is the entire class. They can be declared anywhere inside a class.
The scope of a local variable starts from its declaration and continues to the end of the block that contains the variable. A local variable must be initialized explicitly before it can be used.
## 10. This关键字
### 10.1. 构造函数重载
The this keyword is the name of a reference that refers to an object itself. One common use of the this keyword is reference a class’ s hidden data fields. Another common use of the this keyword to enable a constructor to invoke another constructor of the same class.
```java
public class Circle {
public double radius;
public Circle() {
this(1.0);
}
public Circle(double radius) {
this.radius = radius;
}
}
```
上个例子有两个构造函数, 这是构造函数的overload。在`public Circle(double radius)` 这个构造函数中,因为参数列表中有一个`radius`,这时在构造函数内部如果使用`radius`这个变量,则是指该函数参数列表中的`radius`变量。那么类`Circle`中的`radius`变量就无法直接访问了。因此使用this关键字代表**本对象**,那么`this.radius`就代表`Circle`的成员变量`radius`。最后`this.radius = radius;`就没有歧义了。
不带参数的构造函数`public Circle()`可以调用其他构造函数, 这里用this(1.0),表示调用该类中带参数的构造函数。
## 11. 本章重点