一、Java的数据类型分类
Java的数据类型分为两类:Primitive类型(原始类型)和引用类型。其中Primitive类型指的是8个基本类型,它们都有自己的封装类型:
主值 大小 最小值 最大值 封装类型
boolean 1 位 - - Boolean
char 16位 Unicode 0 Unicode 2的16次方减1 Character
byte 8位 -128 127 Byte
short 16位 -2的15次方 +2的15次方减1 Short
int 32位 -2的31次方 +2的31次方减1 Integer
long 64位 -2的63次方 +2的63次方减1 Long
float 32位 IEEE754 IEEE754 Float
double 64位 IEEE754 IEEE754 Double
除了原始类型,剩下的都是引用类型,包括String,但String类型稍特殊一些。引用类型的一个特点是:数据存储在堆空间中,引用在栈空间中。
二、深复制和浅复制
浅复制:
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制:
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
Java的clone()方法实现的是浅复制,也就是引用类型的clone只是复制了引用而已(String类型是个例外)。
三、clone方法
Object类有如下方法:
protected Object clone ()
Creates and returns a copy of this Object. The default implementation returns a so-called "shallow" copy: It creates a new instance of the same class and then copies the field values (including object references) from this instance to the new instance. A "deep" copy, in contrast, would also recursively clone nested objects. A subclass that needs to implement this kind of cloning should call super.clone() to create the new instance and then create deep copies of the nested, mutable objects.
Returns
a copy of this object.
Throws
CloneNotSupportedException if this object's class does not implement the Cloneable interface.
需要注意以下几点:
1.这个方法是protected,因此我们需要在其子类中将访问级别改为public,这样我们才可以调用这个方法。
关于Override有几点要注意的地方:
(1).被覆盖方法的访问控制级别可以不一样。
父类的访问级别为protected的,而子类覆盖的方法访问级别为public是可以的,也就是子类的访问级别必须要高于父类被覆盖方法的访问级别,如果父类是public的而子类是protected的则是错误的。
(2).方法被定义为private或static或final的则不能被覆盖。
(3).方法的返回类型:子类的返回类型可以是更具体的对象。
(4).在方法调用时先会在子类中找覆盖的方法,如果子类中没有则会在父类中去找。
2.如果在子类中复写clone这个方法,则应该实现Cloneable接口,否则总会抛出异常。
如注释所说:如果这个类没有实现Cloneable接口,就会抛出CloneNotSupportedException。
注:Cloneable接口中并没有任何方法需要去实现。
Throws CloneNotSupportedException if this object's class does not implement the Cloneable interface.
3.clone是浅复制
The default implementation returns a so-called "shallow" copy
这意味着如果这个类中包含除了8个原始类型及其封装类型和String类型外的其它类型,那么通过这个方法只是复制了引用,实际仍在堆中共享数据空间。
4.clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
(1)对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
(2)对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
(3)如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
但是这些都不是强制的。
我们需要什么样的clone就搞出什么样的clone好了。
一般而言,我们要的clone应该是这样的。copy和原型的内容一样,但是又是彼此隔离的。即在clone之后,改变其中一个不影响另外一个。
四、如何clone
在派生类中实现Cloneable接口
在派生类中覆盖基类的clone()方法,并声明为public
在派生类的clone()方法中,调用super.clone()
对引用类型进行深复制
//1.实现Cloneable接口
public class Prototype implements Cloneable{
private String name;
private int age;
private Car car;
//2.Override clone方法并声明为public
//????声明为protected也可以在外部引用,为什么?????
@Override
//protected Prototype clone() throws CloneNotSupportedException {
public Prototype clone() throws CloneNotSupportedException {
//3.调用super.clone()方法
Prototype prototype = (Prototype)super.clone();
//4.car是引用类型,需要进行深复制:继续调用Car的clone方法,这意味着Car类也需要能够clone
prototype.car = this.car.clone();
return prototype;
}
}
public class Car implements Cloneable{
private String type;
private float price;
@Override
public Car clone() throws CloneNotSupportedException {
return (Car)super.clone();
}
}