Java重难点

1. 静态方法与实例方法的区别

实例方法,对象的成员函数,必须实例化对象之后(new Object()),才能通过实例对象调用该对象的实例方法。

静态方法,使用static关键字声明,如main函数:

1
public static void main(String[] args)

静态方法可以直接访问,而不需要实例化对象,访问形式为:类名.静态方法名。如:System.out.println(),其调用System包中的out类中的println()静态方法。

注意:类中的静态方法只能访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法。

2. 浅拷贝与深拷贝

拷贝,指将一个对象的内容复制到另一个对象。常利用拷贝构造函数,或原型模式完成该操作。

浅拷贝,是指在对象拷贝的过程中,只将对象A的成员变量的值复制到对象B的成员变量中。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
class People {
String name;
int age;

People(String name, int age) {
this.name = name;
this.age = age;
}
People(People p) {
this.name = p.name;
this.age = p.age;
}
}

浅拷贝在成员变量都是值类型(String类不算一般引用类型)时,是完全没问题的。

但是,如果类中存在引用类型的成员变量,那这样浅拷贝是会出现问题的。如:

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
//-----------Demo.java----------------
public class Demo {
String name;
People peo; // 类中存在引用类型的成员变量

Demo(String name, People p) {
this.name = name;
this.peo = p;
}
// 浅拷贝构造函数
Demo(Demo de) {
this.name = de.name;
this.peo = de.peo;
}
void printInfo() {
System.out.println(name);
peo.printPeopleInfo();
}
}

class People {
String name;
int age;

People(String name, int age) {
this.name = name;
this.age = age;
}
People(People p) {
this.name = p.name;
this.age = p.age;
}
void printPeopleInfo() {
System.out.println(name + " " + age);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//----------------Main.java--------------------
public class Main {
public static void main(String argv[]) {
Demo A = new Demo("demo1", new People("Tom", 12));
A.printInfo(); // 输出:demo1 Tom 12

Demo B = new Demo(A); // B的peo成员变量与A的peo成员变量都指向同一个类
B.name = "demo2";
B.peo.name = "ki";
B.peo.age = 20;
B.printInfo(); // 输出:demo2 ki 20

// A中peo变量指向的对象也被改变了
A.printInfo(); // 输出:demo1 ki 20
}
}

浅拷贝后,两个对象的引用类型成员变量指向同一个内存区域。因此,一个被修改后,另一个也会被影响。

为了避免这种bug的出现,就需要深拷贝了。如果熟悉C语言的话,其实这就是指针直接赋值的问题。

深拷贝,是为对象B(拷贝目的对象)的引用成员变量重新申请内存空间,并将对象A(拷贝源对象)的引用成员变量所指向的内容,深拷贝到对象B中引用成员变量所指向的新内存空间。

对上述示例的Demo类的拷贝构造函数做如下修改:

1
2
3
4
Demo(Demo de) {
this.name = de.name;
this.peo = new People(de.peo); // 新建成员对象,并将被拷贝对象的
}

运行后,输出变成:

1
2
3
4
5
6
demo1
Tom 12
demo2
ki 20
demo1
Tom 12

可以看到,改变B.pe对象中的值后并没有影响到A.pe对象中的值。

java中拷贝对象时,应根据适当场景使用对应拷贝方式。

3. 内部类