首页编程java编程java克隆有什么用途?详细讲述Java中的克隆

java克隆有什么用途?详细讲述Java中的克隆

编程之家2023-10-14111次浏览

大家好,今天给各位分享java克隆有什么用途的一些知识,其中也会对详细讲述Java中的克隆进行解释,文章篇幅可能偏长,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在就马上开始吧!

java克隆有什么用途?详细讲述Java中的克隆

简述java中引用和克隆的区别

深克隆与浅克隆

大家知道,对象是互相引用的,即对象中可能包含了另一个对象的引用,举例如:有一个Order对象,Order对象中又包含了LineItems对象,然后LineItems对象又包含了Item对象。

好了,现在我有一个Order对象order1,它包含了一个LineItems对象items,这表示的是有一个订单order1,订单的内容是items。

java克隆有什么用途?详细讲述Java中的克隆

好的,现在有另一个客户想要一份订单,内容跟order1完全一样,那么在系统的逻辑层我们怎么做呢?很简单,order2=order1.clone().我们知道clone方法是在内存中生成一个新的对象,而不是只得到原对象的引用。这时候,有人说话了:“哦,明白了我们对order2的成员变量进行修改,是不会影响order1的。”很可惜,这句话只对了一半。

假设order类有一个成员变量name,当然改变order2.name不会影响order1.name,因为他们在不同的内存区域。但是如果改变 order1.items呢?很遗憾,简单地使用order1.clone,是会影响到order2.items的。原因很简单,就是因为clone方法默认的是浅克隆,即不会克隆对象引用的对象,而只是简单地复制这个引用。所以在上例中,items对象在内存中只有一个,order1和order2都指向它,任何一个对象对它的修改都会影响另一个对象。

那相对浅克隆,深克隆自然就是会克隆对象引用的对象了。也就是说,在上例中,改变order1.items并不会影响order2.items了。因为内存中有两个一样的items。

java克隆有什么用途?详细讲述Java中的克隆

如果实现深克隆?

一个方法自然是重写clone方法,添加如order.items=(LineItems)items.clone()的语句,也就是人为地添加对引用对象的复制。这个方法的缺点是如果引用对象有很多,或者说引用套引用很多重,那么太麻烦了。业界常用的方法是使用串行化然后反串行化的方法来实现深克隆。由于串行化后,对象写到流中,所有引用的对象都包含进来了,所以反串行化后,对等于生成了一个完全克隆的对象。绝!

这个方法的要求是对象(包括被引用对象)必须事先了Serializable接口,否则就要用transient关键字将其排除在复制过程中。

Java中导入java.util.Date这样的声明有什么样的意义

建议使用Calendar类

在JDK 5.0版本中对java.util.Date类的方法说明如下:

java.util

类 Date

所有已实现的接口:

Serializable, Cloneable, Comparable<Date>

直接已知子类:

Date, Time, Timestamp

类 Date表示特定的瞬间,精确到毫秒。另请参见:

DateFormat, Calendar, TimeZone

构造方法:

Date

public Date()分配 Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。

另请参见:

System.currentTimeMillis()

Date

public Date(long date)分配 Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970年 1月 1日 00:00:00 GMT)以来的指定毫秒数。

参数:

date-自 1970年 1月 1日 00:00:00 GMT以来的毫秒数。

另请参见:

System.currentTimeMillis()

Date

@Deprecated

public Date(int year,

int month,

int date)已过时。从 JDK 1.1开始,由 Calendar.set(year+ 1900, month, date)或 GregorianCalendar(year+ 1900, month, date)取代。

分配 Date对象并初始化此对象,以表示由 year、month和 date参数指定的一天的开始时间(本地时间晚上 12时)。

参数:

year-减 1900的年份。

month- 0-11的月份。

date-一月中 1-31之间的某一天。

另请参见:

Calendar

Date

@Deprecated

public Date(int year,

int month,

int date,

int hrs,

int min)已过时。从 JDK 1.1开始,由 Calendar.set(year+ 1900, month, date, hrs, min)或 GregorianCalendar(year+ 1900, month, date, hrs, min)取代。

分配 Date对象并初始化此对象,以表示本地时区中由 year、month、date、hrs和 min参数指定的分钟的开始瞬间。

参数:

year-减 1900的年份。

month- 0-11之间的月份。

date-一月中 1-31之间的某一天。

hrs- 0-23之间的小时数。

min- 0-59之间的分钟数。

另请参见:

Calendar

Date

@Deprecated

public Date(int year,

int month,

int date,

int hrs,

int min,

int sec)已过时。从 JDK 1.1开始,由 Calendar.set(year+ 1900, month, date, hrs, min, sec)或 GregorianCalendar(year+ 1900, month, date, hrs, min, sec)取代。

分配 Date对象,并初始化此对象,以表示本地时区中由 year、month、date、hrs、min和 sec参数指定的秒的开始瞬间。

参数:

year-减 1900的年份。

month- 0-11之间的月份。

date-一月中 1-31之间的某一天。

hrs- 0-23之间的小时数。

min- 0-59之间的分钟数。

sec- 0-59之间的秒数。

另请参见:

Calendar

Date

@Deprecated

public Date(String s)已过时。从 JDK 1.1开始,由 DateFormat.parse(String s)取代。

分配 Date对象并初始化此对象,以表示字符串 s指出的日期和时间,就像通过 parse(java.lang.String)方法解释一样。

参数:

s-日期的字符串表示形式。

另请参见:

DateFormat, parse(java.lang.String)

方法详细信息

clone

public Object clone()返回此对象的副本。

覆盖:

类 Object中的 clone

返回:

此实例的一个克隆。

另请参见:

Cloneable

UTC

@Deprecated

public static long UTC(int year,

int month,

int date,

int hrs,

int min,

int sec)已过时。从 JDK 1.1开始,由 Calendar.set(year+ 1900, month, date, hrs, min, sec)或 GregorianCalendar(year+ 1900, month, date, hrs, min, sec)取代,使用 UTC TimeZone,后跟 Calendar.getTime().getTime()。

根据参数确定日期和时间。这些参数被解释为年份、月份、月中某一天、一天中的某一小时、小时中某一分钟和分钟中的某一秒。除了相对于 UTC而不是本地时区解释这些参数之外,该方法与带 6个参数的 Date构造方法完全相同。该方法将返回指示的时间,用该时间与历元(1970年 1月 1日,00:00:00 GMT)的时间差来表示(以毫秒为单位)。

参数:

year-减 1900的年份。

month- 0-11之间的月份。

date-一月中 1-31之间的某一天。

hrs- 0-23之间的小时数。

min- 0-59之间的分钟数。

sec- 0-59之间的秒数。

返回:

对于参数指定的日期和时间,返回自 1970年 1月 1日 00:00:00 GMT以来的毫秒数。

另请参见:

Calendar

parse

@Deprecated

public static long parse(String s)已过时。从 JDK 1.1开始,由 DateFormat.parse(String s)取代。

尝试把字符串 s解释为日期和时间的表示形式。如果尝试成功,则返回指示的时间,用该时间与历元(1970年 1月 1日,00:00:00 GMT)的时间差来表示(以毫秒为单位)。如果尝试失败,则抛出 IllegalArgumentException。

它接受许多语法;特别是它识别 IETF标准日期语法:"Sat, 12 Aug 1995 13:30:00 GMT"。它也了解美国大陆时区缩写,但对于一般用途,应该使用时区偏移量:"Sat, 12 Aug 1995 13:30:00 GMT+0430"(比格林威治子午线晚 4小时 30分)。如果没有指定时区,则假定用本地时区。GMT和 UTC被认为是相同的。

系统将从左到右处理字符串 s,从中查找相应的数据。s中包括在 ASCII括号字符(和)中的任何内容都将被忽略。括号可以进行嵌套。另外,s中只允许使用以下 ASCII字符:

abcdefghijklmnopqrstuvwxyz

ABCDEFGHIJKLMNOPQRSTUVWXYZ

0123456789,+-:/以及空白字符。

连续的十进制位序列被当成十进制数:

如果数字前面有+或-,并且已经识别了年份,那么数字就是一个时区偏移量。如果数字少于 24,那么它是以小时进行测量的偏移量。否则,它被认为是以分钟进行测量的偏移量,用没有标点的 24小时时间格式来表示。前面的-意味着向西的偏移量。时区偏移量始终相对于 UTC(格林威治)。因此,例如,在字符串中出现的-5意味着“比格林威治时间晚 5小时”,+0430将意味着“比格林威治时间早 4小时 30分”。允许字符串冗余地指定 GMT、UT或 UTC——例如,GMT-5或 utc+0430。

如果下面条件之一为真,数字就被认为是年数:

数字等于或大于 70,并且后跟一个空格、逗号、斜杠或结束字符串

数字小于 70,并且已经识别月份和月中的某一天

如果被识别的年数小于 100,它就被解释为相对于其日期所在世纪的缩写年,缩写年的日期位于初始化 Date类的时间的 80年以前和 19年以后之间。在调整年数后,从其减去 1900。例如,如果当前的年份是 1999,那么范围 19至 99的年数就被假定表示 1919至 1999,而 0至 18的年数就被假定表示 2000至 2018。注意,这与 SimpleDateFormat中使用的小于 100的年份具有稍微不同的解释。

如果数字后跟一个冒号,则认为是小时,如果小时已经被识别,则认为是分钟。

如果数字后跟一个斜杠,则认为是月份(把它减 1,以便产生范围 0至 11的数字),如果月份已经被识别,则认为它是月中的某一天。

如果数字后跟空白、逗号、连字符或结束字符串,那么如果小时已识别但分钟未识别,则认为是分钟;否则,如果分钟已识别,而秒没有识别,则认为是秒;否则,它被认为是月中的某一天。

连续的字母序列被认为是单词,并按以下方法进行处理:

忽略匹配 AM(忽略大小写)的单词(但如果小时尚未识别,或者小时小于 1或大于 12,则分析失败)。

匹配 PM(忽略大小写)的单词,添加 12到小时(但如果小时尚未识别,或者小时小于 1或大于 12,则分析失败)。

忽略匹配 SUNDAY、MONDAY、TUESDAY、WEDNESDAY、THURSDAY、FRIDAY或 SATURDAY的任何前缀(忽略大小写)的任何单词。例如,sat、Friday、TUE和 Thurs会被忽略。

否则,匹配 JANUARY、FEBRUARY、MARCH、APRIL、MAY、JUNE、JULY、AUGUST、SEPTEMBER、OCTOBER、NOVEMBER或 DECEMBER的任何前缀(忽略大小写,并按这里给出的顺序考虑它们)的任何单词都被识别为指定月份,并被转换成一个数字(0至 11)。例如,aug、Sept、april和 NOV被识别为月份。Ma也是这样,它被识别为 MARCH,而不是 MAY。

匹配 GMT、UT或 UTC(忽略大小写)的任何单词都认为是指 UTC。

匹配 EST、CST、MST或 PST(忽略大小写)的任何单词都被认为是指北美的时区,该时区分别比格林威治时间晚 5、6、7或 8小时。匹配 EDT、CDT、MDT或 PDT(忽略大小写)的任何单词都被识别为在夏令时期间分别指相同的时区。

一旦扫描了整个字符串,就以两种方式之一把它转换成时间结果。如果已经识别时区或时区偏移量,那么年、月、月中某一天、小时、分钟和秒以 UTC进行解释,然后应用时区偏移量。否则,年、月、月中某一天、小时、分钟和秒用本地时区进行解释。

参数:

s-要解析为日期的字符串。

返回:

自 1970年 1月 1日 00:00:00 GMT以来字符串参数表示的毫秒数。

另请参见:

DateFormat

getYear

@Deprecated

public int getYear()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.YEAR)- 1900取代。

返回一个值,此值是从包含或开始于此 Date对象表示的瞬间的年份减去 1900的结果(用本地时区进行解释)。

返回:

日期表示的年份减去 1900。

另请参见:

Calendar

setYear

@Deprecated

public void setYear(int year)已过时。从 JDK 1.1开始,由 Calendar.set(Calendar.YEAR, year+ 1900)取代。

把此 Date对象的年份设置为指定的值加 1900。修改此 Date对象,以便它用与以前相同的月份、日期、小时、分钟和秒表示指定年份中的时间点(用本地时区进行解释)。(当然,例如,如果日期是 2月 29日,并且年份被设置到非闰年,那么新日期将被看作 3月 1日。)

参数:

year-年份值。

另请参见:

Calendar

getMonth

@Deprecated

public int getMonth()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.MONTH)取代。

返回表示月份的数字,该月份包含或开始于此 Date对象所表示的瞬间。返回的值在 0和 11之间,值 0表示 1月。

返回:

此日期所表示的月份。

另请参见:

Calendar

--------------------------------------------------------------------------------

setMonth

@Deprecated

public void setMonth(int month)已过时。从 JDK 1.1开始,由 Calendar.set(Calendar.MONTH, int month)取代。

把此日期的月份设置为指定值。修改此 Date对象,以便它用与以前一样的年份、日期、小时、分钟和秒表示指定月份中的时间点(用本地时区进行解释)。例如,如果日期是 10月 31日,并将月份设置为 6月,那么新日期将被看作 7月 1日,因为 6月只有 30天。

参数:

month- 0-11之间的月份值。

另请参见:

Calendar

--------------------------------------------------------------------------------

getDate

@Deprecated

public int getDate()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.DAY_OF_MONTH)取代。

返回此 Date对象表示的月份中的某一天。返回的值在 1和 31之间,表示包含或开始于此 Date对象表示的时间的月份中的某一天(用本地时区进行解释)。

返回:

此日期所表示的月份中的某一天。

另请参见:

Calendar

--------------------------------------------------------------------------------

setDate

@Deprecated

public void setDate(int date)已过时。从 JDK 1.1开始,由 Calendar.set(Calendar.DAY_OF_MONTH, int date)取代。

把此 Date对象的月份中的某一天设置为指定值。修改此 Date对象,以便它用与以前一样的年份、月份、小时、分钟和秒表示月份中指定某一天中的时间点(用本地时区进行解释)。例如,如果日期是 4月 30日,并且日期被设置为 31,那么它将被看作 5月 1日,因为 4月只有 30天。

参数:

date-月份中 1-31之间的某一天。

另请参见:

Calendar

--------------------------------------------------------------------------------

getDay

@Deprecated

public int getDay()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.DAY_OF_WEEK)取代。

返回此日期表示的周中的某一天。返回值(0= Sunday, 1= Monday, 2= Tuesday, 3= Wednesday, 4= Thursday, 5= Friday, 6= Saturday)表示一周中的某一天,该周包含或开始于此 Date对象所表示的瞬间(用本地时区进行解释)。

返回:

此日期所表示的一周中的某一天。

另请参见:

Calendar

--------------------------------------------------------------------------------

getHours

@Deprecated

public int getHours()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.HOUR_OF_DAY)取代。

返回此 Date对象表示的小时。返回值是一个数字(0至 23),表示包含或开始于此 Date对象表示的瞬间的一天中的小时(用本地时区进行解释)。

返回:

此日期所表示的小时。

另请参见:

Calendar

--------------------------------------------------------------------------------

setHours

@Deprecated

public void setHours(int hours)已过时。从 JDK 1.1开始,由 Calendar.set(Calendar.HOUR_OF_DAY, int hours)取代。

把此 Date对象的小时设置为指定值。修改此 Date对象,以便它用与以前一样的年份、月份、日期、分钟和秒表示某一天指定小时中的时间点(用本地时区进行解释)。

参数:

hours-小时值。

另请参见:

Calendar

--------------------------------------------------------------------------------

getMinutes

@Deprecated

public int getMinutes()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.MINUTE)取代。

返回此日期所表示的小时已经过去的分钟数(用本地时区进行解释)。返回值在 0和 59之间。

返回:

此日期所表示的小时已经过去的分钟数。

另请参见:

Calendar

--------------------------------------------------------------------------------

setMinutes

@Deprecated

public void setMinutes(int minutes)已过时。从 JDK 1.1开始,由 Calendar.set(Calendar.MINUTE, int minutes)取代。

把此 Date对象的分钟数设置为指定值。修改此 Date对象,以便它用与以前一样的年份、月份、日期、小时和秒表示小时的指定分钟中的时间点(用本地时区进行解释)。

参数:

minutes-分钟值。

另请参见:

Calendar

--------------------------------------------------------------------------------

getSeconds

@Deprecated

public int getSeconds()已过时。从 JDK 1.1开始,由 Calendar.get(Calendar.SECOND)取代。

返回此日期所表示的分钟已经过去的秒数。返回的值在 0和 61之间。值 60和 61只可能发生在考虑了闰秒的 Java虚拟机上。

返回:

此日期表示的分钟已经过去的秒数。

另请参见:

Calendar

--------------------------------------------------------------------------------

setSeconds

@Deprecated

public void setSeconds(int seconds)已过时。从 JDK 1.1开始,由 Calendar.set(Calendar.SECOND, int seconds)取代。

把此 Date的秒数设置为指定值。修改此 Date对象,以便它用与以前一样的年份、月份、日期、小时和分钟表示分钟的指定秒数中的时间点(用本地时区进行解释)。

参数:

seconds-秒数值。

另请参见:

Calendar

--------------------------------------------------------------------------------

getTime

public long getTime()返回自 1970年 1月 1日 00:00:00 GMT以来此 Date对象表示的毫秒数。

返回:

自 1970年 1月 1日 00:00:00 GMT以来此日期表示的毫秒数。

--------------------------------------------------------------------------------

setTime

public void setTime(long time)设置此 Date对象,以表示 1970年 1月 1日 00:00:00 GMT以后 time毫秒的时间点。

参数:

time-毫秒数。

--------------------------------------------------------------------------------

before

public boolean before(Date when)测试此日期是否在指定日期之前。

参数:

when-日期。

返回:

当且仅当此 Date对象表示的瞬间比 when表示的瞬间早,才返回 true;否则返回 false。

抛出:

NullPointerException-如果 when为 null。

--------------------------------------------------------------------------------

after

public boolean after(Date when)测试此日期是否在指定日期之后。

参数:

when-日期。

返回:

当且仅当此 Date对象表示的瞬间比 when表示的瞬间晚,才返回 true;否则返回 false。

抛出:

NullPointerException-如果 when为 null。

--------------------------------------------------------------------------------

equals

public boolean equals(Object obj)比较两个日期的相等性。当且仅当参数不为 null,并且是一个表示与此对象相同的时间点(到毫秒)的 Date对象时,结果才为 true。

因此,当且仅当 getTime方法对于两个 Date对象返回相同的 long值时,这两个对象才是相等的。

覆盖:

类 Object中的 equals

参数:

obj-要与之比较的对象。

返回:

如果对象相同,则返回 true;否则,返回 false。

另请参见:

getTime()

--------------------------------------------------------------------------------

compareTo

public int compareTo(Date anotherDate)比较两个日期的顺序。

指定者:

接口 Comparable<Date>中的 compareTo

参数:

anotherDate-要比较的 Date。

返回:

如果参数 Date等于此 Date,则返回值 0;如果此 Date在 Date参数之前,则返回小于 0的值;如果此 Date在 Date参数之后,则返回大于 0的值。

抛出:

NullPointerException-如果 anotherDate为 null。

从以下版本开始:

1.2

--------------------------------------------------------------------------------

hashCode

public int hashCode()返回此对象的哈希码值。结果是 getTime()方法返回的基本 long值的两部分的异或。也就是说,哈希码就是以下表达式的值:

(int)(this.getTime()^(this.getTime()>>> 32))

覆盖:

类 Object中的 hashCode

返回:

此对象的哈希码值。

另请参见:

Object.equals(java.lang.Object), Hashtable

--------------------------------------------------------------------------------

toString

public String toString()把此 Date对象转换为以下形式的 String:

dow mon dd hh:mm:ss zzz yyyy其中:

dow是一周中的某一天(Sun, Mon, Tue, Wed, Thu, Fri, Sat)。

mon是月份(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)。

dd是一月中的某一天(01至 31),显示为两位十进制数。

hh是一天中的小时(00至 23),显示为两位十进制数。

mm是小时中的分钟(00至 59),显示为两位十进制数。

ss是分钟中的秒数(00至 61),显示为两位十进制数。

zzz是时区(并可以反映夏令时)。标准时区缩写包括方法 parse识别的时区缩写。如果不提供时区信息,则 zzz为空,即根本不包括任何字符。

yyyy是年份,显示为 4位十进制数。

覆盖:

类 Object中的 toString

返回:

此日期的字符串表示形式。

另请参见:

toLocaleString(), toGMTString()

--------------------------------------------------------------------------------

toLocaleString

@Deprecated

public String toLocaleString()已过时。从 JDK 1.1开始,由 DateFormat.format(Date date)取代。

以与实现相关的方式创建此 Date对象的字符串表示形式。其目的是这种形式应该为所有 Java应用程序的用户所熟悉,而不管它运行在何处。它类似于 ISO C的 strftime()函数支持的"%c"格式。

返回:

此日期的字符串表示形式(使用语言环境约定)。

另请参见:

DateFormat, toString(), toGMTString()

--------------------------------------------------------------------------------

toGMTString

@Deprecated

public String toGMTString()已过时。从 JDK 1.1开始,由 DateFormat.format(Date date)取代,使用 GMT TimeZone。

创建此 Date对象的字符串表示形式,如下: d mon yyyy hh:mm:ss GMT

其中:

d是一月中的某一天(1至 31),显示为一位或两位十进制数。

mon是月份(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec)。

yyyy是年份,显示为 4位十进制数。

hh是一天中的小时(00至 23),显示为两位进制数。

mm是小时中的分钟(00至 59),显示为两位十进制数。

ss分钟中的秒数(00至 61),显示为两位十进制数。

GMT就是 ASCII字母"GMT",代表格林威治标准时(Greenwich Mean Time)。

结果不依赖于本地时区。

返回:

此日期的字符串表示形式(使用 Internet GMT约定)。

另请参见:

DateFormat, toString(), toLocaleString()

--------------------------------------------------------------------------------

getTimezoneOffset

@Deprecated

public int getTimezoneOffset()已过时。从 JDK 1.1开始,由-(Calendar.get(Calendar.ZONE_OFFSET)+ Calendar.get(Calendar.DST_OFFSET))/(60* 1000)取代。

返回相对于 UTC(相应于此 Date对象表示的时间)的本地时区的偏移量(以分钟为单位)。

例如,在马萨诸塞州,比格林威治时间晚 5个时区:

new Date(96, 1, 14).getTimezoneOffset()返回 300因为在 1996年 2月 14日,使用标准时间(东部标准时间),此时间和 UTC有 5小时的偏移量;但是:

new Date(96, 5, 1).getTimezoneOffset()返回 240因为在 1996年 6月 1日,使用夏令时(东部日光时间),此时间和 UTC只有 4小时的偏移量。

此方法产生与以下计算方式相同的结果:

(this.getTime()- UTC(this.getYear(),

this.getMonth(),

this.getDate(),

this.getHours(),

this.getMinutes(),

this.getSeconds()))/(60* 1000)

返回:

当前时区的时区偏移量(以分钟为单位)。

另请参见:

Calendar.ZONE_OFFSET, Calendar.DST_OFFSET, TimeZone.getDefault()

详细讲述Java中的克隆

经常听到有人说java中没有指针事实如此吗?no java是有指针的只不过换了个名字而已也就是我们经常提到的引用我们知道在java中一切都是对象那么我们如何操控对象?如何在成千上万的对象中找到我们所需的那个对象呢?又是如何让对象按照我们的意思来完成任务的呢?

Object o= new Object()

这是java中最常见的语句了在这句话中做了三件事首先声明一个Object类型的变量o在内存中为对象划分一块地址new Object()将声明的变量指向内存中的对象如此一来我们就可以通过o来操纵对象了就好像孩子们玩的遥控飞机在空中飞行的是飞机而使它做出优美动作的却是孩子们手中的摇控器

克隆是如今听到的较多的词汇听说已经将某只羊克隆了好几份了但愿这种技术不要在人身上实验 java中也有克隆与现实世界的克隆一样将一个实际存在的对象拷贝几份如下

//倒霉的羊public class Sheep implements Cloneable{private String name;public void setName(String arg){name= arg;}public String getName(){return name;}public Object clone() throws CloneNotSupportedException{return super clone();}}//克隆public class Main{public static void main(String[] args) throws CloneNotSupportedException{Sheep sheep= new Sheep();//先得到那只羊的实例sheep setName(我是真的);//给它做个记号System out println( sheep getName()=+ sheep getName());Sheep sheepClone=(Sheep)sheep clone();//开始克隆System out println( sheepClone getName()=+ sheepClone getName());}}

运行程序结果为

sheep getName()=我是真的

sheepClone getName()=我是真的

两只羊是一模一样的(哪怕那只羊瘸腿)让我们来看看代码首先要注意的是Sheep类实现了Cloneable接口(该接口属于java lang包默认已经导入了)该接口中并没有定义要实现的方法是个空接口起标志作用也就是说实现了这个接口的羊就不再是只普通的羊它是一只可以被克隆的羊再往下看有个clone方法返回Object类型的对象并抛出CloneNotSupportedException异常该方法覆写了父类(Object)的clone方法并在最后调用了super clone()这也意味着无论clone类继承结构是什么样的 super clone()都会直接或间接调用Object类的clone()方法看看jdk帮助文档会发现 Object类的clone()是一个native方法我们知道 native方法的效率一般来说都是远高于java中的非native方法这也说明了new一个对象然后将原对象中的数据导入到新创建的对象中去的做法是多么愚蠢必须说明的是Object中的clone方法是protected的所以要使用clone就必须继承Object类(默认)并且为了可以使其它类调用该方法必须将其作用域设置为public

以上只是一个简单clone的实现明天说说影子clone和深度clone

夜深了何为影子clone?先看一下例子

//倒霉的羊public class Sheep implements Cloneable{private String name;public void setName(String arg){name= arg;}public String getName(){return name;}public Object clone() throws CloneNotSupportedException{return super clone();}}//羊圈public class Sheepfold implements Cloneable{public Sheep sheep;public String name;public Sheepfold(){sheep= new Sheep();}public Object clone() throws CloneNotSupportedException{return super clone();}}//克隆public class Main{public static void main(String[] args) throws Exception{Sheepfold fold= new Sheepfold();fold name=小羊圈;fold sheep setName(小羊);Sheepfold fold=(Sheepfold)fold clone();System out println( fold name=+ fold name);System out println( fold sheep getName()=+ fold sheep getName());fold name=大羊圈;fold sheep setName(大羊);System out println(=====================================);System out println( fold name=+ fold name);System out println(* fold sheep getName()=+ fold sheep getName());System out println( fold name=+ fold name);System out println(* fold sheep getName()=+ fold sheep getName());System out println(=====================================);}}

在这个例子中有三个类 Sheep和Sheepflod都实现了Cloneable接口并且覆写了Object类的clone方法说明这两个类是具有克隆能力的注意一点在Sheepflod中持有一个Sheep的实例并在Main类中对其进行克隆结果如下

fold<fp class='fp-3p43k'></fp><fp class='fp-6kh1w'></fp>name=小羊圈fold<fp class='fp-3p43k'></fp><fp class='fp-szkq0'></fp>sheep<fp class='fp-6kh1w'></fp>getName()=小羊=====================================fold<fp class='fp-4kby3'></fp><fp class='fp-5w0yq'></fp>name=大羊圈* fold<fp class='fp-3p43k'></fp><fp class='fp-5w0yq'></fp>sheep<fp class='fp-y11o7'></fp>getName()=大羊fold<fp class='fp-5w0yq'></fp>name=小羊圈* fold<fp class='fp-y11o7'></fp>sheep<fp class='fp-5w0yq'></fp>getName()=大羊=====================================

请注意一下结果中带有*号的两条结果语句 fold sheep和fold sheep的name都变为了大羊很奇怪是吗?在此之前我们只对fold sheep的name赋过值为什么fold sheep的name也变为了大羊呢?原因很简单因为它们是指向同一个对象的不同引用从中可以看出调用Object类中clone()方法时首先在内存中划分一块同原对象相同的空间然后将原对象的内容原样拷贝至新对象我们知道 java中有基本数据类型对于基本数据类型这样的操作是没有问题的但对非基本类型变量它们保存的仅仅是对象的引用这也是为什么clone后非基本类型变量和原对象中的变量指向同一个对象的原因可能你已经注意到程序中用到了String类型即对象为什么没有出现引用指向同一地址的情况?这是因为String是一个不可更改的类(immutable class)每次给它赋值时都会产生一个新的String对象如 String str= a str+= b在这两句代码中当执行str+= b时实际上是重新成生了一个值为 ab的 String对象即重新分配了一块内存空间以上clone方法通常被称为影子clone影子clone给我们留下了一个问题即多个引用指向同一个对象如何解决该问题呢?答案为深度clone把上面的例子改成深度clone很简单只需将Sheepfold的clone()方法改为如下即可很简单只需将Sheepfold的clone()方法改为如下即可

public Object clone() throws CloneNotSupportedException{Sheepfold fold=(Sheepfold)super clone();sheep=(Sheep)fold sheep clone();return fold;}

lishixinzhi/Article/program/Java/gj/201311/27342

如果你还想了解更多这方面的信息,记得收藏关注本站。

java中map在什么包中,java中几种Map在什么情况下使用,并简单介绍原因及原理javascript计时器频率是什么,怎样用javascript做一个计时器