1. 类的方法
类似 C/C++ 的函数
1.1 实例方法
类内部各个实例方法之间可以相互调用,也可直接读写类内变量。
实例方法可以调用静态变量和静态方法。
1.1.1 getter 与 setter
实例方法中,getter 与 setter 方法是类成员属性提供读取和修改的方法。
以下例子参考 5. 构造方法 中的无参构造方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public class Constructor {
public static void main(String[] args) {
Character character = new Character();
character1.setName("MicroLOONG");
character1.setAge(20);
System.out.println(character.getName() + " " + character.getAge());
}
}
class Character {
private String name;
private int age;
/**
* 获取名字
* @return name
*/
public String getName() {
return name;
}
/**
* 设置名字
* @param name 名字
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取年龄
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置年龄
* @param age 年龄
*/
public void setAge(int age) {
this.age = age;
}
}
|
结果为:
以上例子中,类中属性定义为 private 并使用 get() 与 set() 进行访问和修改,能利于统一控制和体现面向对象的封装性。
1.1.2 this 关键字
可见,上面的例子出现了一个关键字 this。
this 关键字用来表示当前对象本身,或当前类的一个实例,通过 this 可以调用本对象的所有方法和属性。
创建对象后 JVM 会给这个对象分配一个引用自身的指针,即 this,因此 this 只能出现在实例方法中。
this 有以下用法:
① 区分同名变量
在上面例子中,出现了方法内部变量名和成员变量重名的情况,在方法内需要使用 this 访问类中的成员变量。
没有重名情况或无局部变量时 this 可省略。
② 作为方法名来初始化对象
this 可调用本类的其它构造方法,它必须作为构造方法的第一句。
以下例子参考 5. 构造方法 中的有参构造方法,结果相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public class Constructor {
public static void main(String[] args) {
Character character = new Character();
System.out.println(character.getName() + " " + character.getAge());
}
}
class Character {
private String name;
private int age;
/**
* 调用有参构造方法
*/
public Character() {
this("MicroLOONG", 20);
}
/**
* 有参构造方法
* @param name 名字
* @param age 年龄
*/
public Character(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取名字
* @return name
*/
public String getName() {
return name;
}
/**
* 获取年龄
* @return age
*/
public int getAge() {
return age;
}
}
|
③ 作为参数传递
将当前对象的一个引用作为参数传递:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public class This {
public static void main(String[] args) {
new A();
}
}
class A {
public A() {
new B(this).print();
}
public void print() {
System.out.println("From A");
}
}
class B {
A a;
public B(A a) {
this.a = a;
}
public void print() {
a.print();
System.out.println("From B");
}
}
|
结果为:
类 A 中 new B(this) 把对象 A 自己作为参数传递给了对象 B 的构造函数,new B(this).print(); 使用了匿名对象调用了 print 方法。
1.2 静态方法 (类方法)
静态方法调用 非静态方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class Circle {
public static void main(String[] args) {
Circle circle = new Circle();
double area = circle.area(2);
System.out.println("半径为2的圆面积是:" + area);
}
/**
* 计算圆面积
* @param r 半径
* @return 面积
*/
public double area(double r) {
return 3.14 * r * r;
}
}
|
注:静态方法不能访问非静态的成员变量。
或不实例化对象直接使用静态方法(静态方法调用静态方法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class Circle {
public static void main(String[] args) {
double area = area(2);
System.out.println("半径为2的圆面积是:" + area);
}
/**
* 计算圆面积
* @param r 半径
* @return 面积
*/
public static double area(double r) {
return 3.14 * r * r;
}
}
|
2. 方法的重载
多个同名的方法在一个类中共存,要求这些方法的参数不同,如参数的个数或参数数据类型不一样,也可以是参数的顺序不一样。
重载可存在于同一个类或者继承关系中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class Overload {
public static void main(String[] args) {
Overload ol = new Overload();
// test1
System.out.println(ol.test());
// test2
ol.test(1);
// test3
System.out.println(ol.test(1,"test3"));
// test4
System.out.println(ol.test("test4",1));
}
public int test() {
System.out.println("test1");
return 1;
}
public void test(int a) {
System.out.println("test2");
}
public String test(int a, String s) {
System.out.println("test3");
return "return test3";
}
public String test(String s, int a) {
System.out.println("test4");
return "return test4";
}
}
|
结果为:
1
2
3
4
5
6
7
|
test1
1
test2
test3
return test3
test4
return test4
|
3. 方法的可变参数
可变参数是指参数的长度可变,与方法的重载不同。
优点:有多个不同参数调用方法时更方便。
限制:一个方法最多只能有一个可变参数,可变参数必须是方法的最后一个参数。
形参格式: 类型... 参数名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public class Varargs {
public static void main(String[] args) {
System.out.println("普通数组 1+2+3 = " + sum1(new int[]{1,2,3}));
// 可变参数,传递任意数量的参数
System.out.println("无参数 sum = " + sum2());
System.out.println("可变参数 1 = " + sum2(1));
System.out.println("可变参数 1+2 = " + sum2(1, 2));
System.out.println("可变参数 1+2+3 = " + sum2(1, 2, 3));
}
/**
* 普通数组
* @param arr 数组
* @return sum
*/
public static int sum1(int[] arr) {
int sum = 0;
for (int i : arr) {
sum += i;
}
return sum;
}
/**
* 可变参数用法
* @param arr 数组
* @return sum
*/
public static int sum2(int... arr) {
int sum = 0;
for (int i : arr) {
sum += i;
}
return sum;
}
}
|
结果为:
1
2
3
4
5
|
普通数组 1+2+3 = 6
无参数 sum = 0
可变参数 1 = 1
可变参数 1+2 = 3
可变参数 1+2+3 = 6
|
int... arr 相当于 sum1 方法的 int[] arr
而 sum2 方法的调用相当于:
1
2
3
4
|
sum2(new int[0]);
sum2(new int[] {1});
sum2(new int[] {1, 2});
sum2(new int[] {1, 2, 3});
|
这个例子实现用同一个方法进行不同数的运算。
4. 参数绑定
调用方把参数传递给实例方法时,调用时传递的值会按参数的位置一一绑定
4.1 基本类型参数绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class paramBind {
public static void main(String[] args) {
Person p = new Person();
int n = 15;
p.setAge(n);
n = 20;
System.out.println(p.getAge());
System.out.println(p.getAge());
}
}
class Person {
private int age;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
|
结果为:
原因是 setAge() 方法获得的参数,复制了 n 的值。因此,p.age 和局部变量 n 互不影响。
结论:基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。
4.2 引用类型参数绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class paramBind {
public static void main(String[] args) {
Person p = new Person();
String[] fullName = new String[] { "Steve", "Jobs" };
p.setName(fullName);
System.out.println(p.getName());
fullName[0] = "Paul";
System.out.println(p.getName());
}
}
class Person {
private String[] name;
public String getName() {
return this.name[0] + " " + this.name[1];
}
public void setName(String[] name) {
this.name = name;
}
}
|
结果为:
原因是这里修改了数组元素的内容,但数组变量指向的内存地址没有变。
结论:引用类型参数的传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方。
另外一种情况:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public class Main {
public static void main(String[] args) {
Person p = new Person();
String bob = "Bob";
p.setName(bob);
System.out.println(p.getName());
bob = "Alice";
System.out.println(p.getName());
}
}
class Person {
private String name;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
|
结果为:
原因是 bob = "Alice"; 改变了 bob 的指向,但是 p.name 的指向并没有改变,与修改前指向的是相同的内存空间,没有改变先传入方法中的对象。
5. 构造方法
构造方法的作用:创建类的对象并初始化
-
构造方法名称必须与类名相同。
-
构造方法没有返回类型,void 也不能有。
-
构造方法不能被继承,不能被覆写,不能被直接调用,可以被重载。
-
类没定义构造方法时编译器会自动生成一个默认构造方法,但是如果自定义了一个构造方法,那么编译器就不再自动创建默认构造方法。
-
构造方法可以私有,不能被 abstract、static、final 等修饰。
以下给出无参构造方法和有参构造方法的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
public class Constructor {
public static void main(String[] args) {
// 调用无参构造方法
Character character1 = new Character();
character1.setName("MicroLOONG");
character1.setAge(20);
System.out.println(character1.getName() + " " + character1.getAge());
// 调用有参构造方法
Character character2 = new Character("MicroLOONG", 20);
System.out.println(character2.getName() + " " + character2.getAge());
}
}
class Character {
private String name;
private int age;
/**
* 无参构造方法
*/
public Character() {
}
/**
* 有参构造方法
* @param name 名字
* @param age 年龄
*/
public Character(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取名字
* @return name
*/
public String getName() {
return name;
}
/**
* 设置名字(有参构造方法非必要)
* @param name 名字
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取年龄
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置年龄(有参构造方法非必要)
* @param age 年龄
*/
public void setAge(int age) {
this.age = age;
}
}
|
结果为:
1
2
|
MicroLOONG 20
MicroLOONG 20
|
这是一个无参和有参构造方法并存的例子。
其中,new Character(); 的调用匹配了无参构造方法 public Character(),
而 new Character("MicroLOONG", 20); 的调用匹配了有参构造方法 public Character(String name, int age)。
实际上两种方法可以相互独立,不过由于有参构造方法属于自定义构造方法,故默认构造方法 public Character() 不再自动创建或被覆盖,如果需要重载无参构造方法则必须自行给出默认构造方法。
无参构造方法需要使用 set() 方法访问类 Character 里的变量,并进行赋值;而有参构造方法直接在创建对象时使用构造器传递参数。