定義:
clone顧名思義就是克隆,即復制一個相等的對象,但是不同的引用地址;
clone方法是被native修飾的,簡單的講就是被Native修飾的方法在被調用時指向的是一個非java代碼的具體實現,這個實現可能是其他語言或者操作系統;
### clone規則
1、 基本類型如果變量是基本類型,則拷貝其值,比如int、float等。
2、 對象如果變量是一個實例對象,則拷貝其地址引用,也就是說新對象和原來對象是共用實例變量的。
3、 String字符串若變量為String字符串,則拷貝其地址引用。但是在修改時,它會從字符串池中重新生成一個新的字符串,原有的對象保持不變
分類
* 淺拷貝:對基本數據類型進行值傳遞,對引用數據類型進行引用傳遞般的拷貝
* 深拷貝:對基本數據類型進行值傳遞,對引用數據類型,創建一個新的對象,并復制其內容
### clone的工作原理
java.lang.Object提供了默認的clone方法實現,它聲明為protected和native。因此它的實現是取決于本地代碼,因為它約定返回對象是通過調用super.clone\(\)方法,任何克隆的過程最終都將到達java.lang.Object 的clone\(\)方法,它首先檢查這個相關的類是否實現了Cloneable接口,這個接口是一個標記接口,如果這個實例沒有實現cloneable接口,那么就會拋出CloneNotSupported異常,這個異常是一個checked異常,也就是說他在克隆對象的時候總需要被處理。如果沒有異常拋出,然后java.lang.Object的clone\(\)方法將創建一個拷貝返回給調用者。因為Object類的clone\(\)方法通過創建新對象來生成這個副本的,然后逐個域拷貝(field-by-filed),類似于賦值操作,這種操作對于原始類型(primitives)和不可變類型(immutable)來說是沒問題的,但是如果你的類包含一些可變的數據結構如:ArrayList或數組就不合適了,這種情況原始對象和副本對象將指向相同的堆,你可以通過一種叫深度克隆的技術防止這種事情發生
### 總結
* 克隆方法用于創建對象的拷貝,為了使用clone方法,類必須實現java.lang.Cloneable接口重寫protected方法clone,如果沒有實現Clonebale接口會拋出CloneNotSupportedException.
* 在克隆java對象的時候不會調用構造器
* java提供一種叫淺拷貝(shallow copy)的默認方式實現clone,創建好對象的副本后然后通過賦值拷貝內容,意味著如果你的類包含可變對象,那么原始對象和克隆都將指向相同的內部對象,這是很危險的,因為發生在可變的字段上任何改變將反應到原始對象和副本對象上。為了避免這種情況,重寫clone\(\)方法。
* 按照約定,實例的克隆應該通過調用super.clone\(\)獲取,這樣有助克隆對象的不變性建如:clone!=original和clone.getClass\(\)==original.getClass\(\),盡管這些不是必須的
* clone機制非常高效,比如clone一個包含100個元素的int\[\]數組,clone方法比靜態copy快近2倍;
### 通過序列化實現深拷貝
也可以通過序列化來實現深拷貝。序列化是干什么的?它將整個對象圖寫入到一個持久化存儲文件中并且當需要的時候把它讀取回來, 這意味著當你需要把它讀取回來時你需要整個對象圖的一個拷貝。這就是當你深拷貝一個對象時真正需要的東西。
請注意,當你通過序列化進行深拷貝時,必須確保對象圖中所有類都是可序列化的;
序列化這種方式有其自身的限制和問題:無法序列化transient變量, 使用這種方法將無法拷貝transient變量
- java演變
- JDK各個版本的新特性
- JDK1.5新特性
- JDK1.6新特性
- JDK1.7新特性
- JDK1.8新特性
- JAVA基礎
- 面向對象特性
- 多態
- 方法重載
- 方法重寫
- class
- 常量
- 訪問修飾符
- 類加載路徑
- java-equals
- 局部類
- java-hashCode
- Java類初始化順序
- java-clone方法
- JAVA對象實例化的方法
- 基礎部分
- JAVA基礎特性
- JAVA關鍵字
- javabean
- static
- 日期相關
- final
- interface
- 函數式接口
- JAVA異常
- 異常屏蔽
- try-with-resource資源泄露
- JAVA引用
- WeakReference
- SoftReference
- PhantomReference
- 位運算符
- try-with-resource語法糖
- JDK冷知識
- JAVA包裝類
- JAVA基本類型與包裝類
- java.lang.Boolean
- java.lang.Integer
- java.lang.Byte
- java.lang.Short
- java.lang.Long
- java.lang.Float
- java.lang.Double
- java.lang.Character
- 日期相關
- TemporalAdjusters
- String
- 字符串常量池
- String拼接
- String編譯期優化
- StringBuilder&StringBuffer
- intern
- 注解
- java標準注解
- 內置注解
- 元注解
- 自定義注解
- 注解處理器
- JVM注解
- Java8 Annotation新特性
- 反射-Reflective
- Reflection
- Class
- Constructor
- Method
- javabean-property
- MethodHandles
- 泛型
- 類型擦除
- bridge-method
- Accessor&Mutator方法
- enum
- JAVA數組
- finalize方法
- JAR文件
- JAVA高級編程
- CORBA
- JMX
- SPI
- Java SPI使用約定
- ServiceLoader
- 實際應用
- IO
- 工具類
- JDK常用工具類
- Objects
- System
- Optional
- Throwable
- Collections
- Array
- Arrays
- System
- Unsafe
- Number
- ClassLoader
- Runtime
- Object
- Comparator
- VarHandle
- 數據結構
- 棧-Stack
- 隊列(Queue)
- Deque
- PriorityQueue
- BlockingQueue
- SynchronousQueue
- ArrayBlockingQueue
- LinkedBlockingQueue
- PriorityBlockingQueue
- ConcurrentLinkedQueue
- 列表
- 迭代器
- KV鍵值對數據類型
- HashMap
- TreeMap
- Hash沖突
- ConcurrentHashMap
- JDK1.7 ConcurrentHashMap結構
- jdk7&jdk8區別
- 集合
- Vector
- Stack
- HashSet
- TreeSet
- ArrayList
- LinkedList
- ArrayList && LinkedList相互轉換
- 線程安全的集合類
- 集合類遍歷性能
- 并發容器
- CopyOnWriteArrayList
- ConcurrentHashMap
- 同步容器
- BitMap
- BloomFilter
- SkipList
- 設計模式
- 設計模式六大原則
- 單例模式
- 代理模式
- 靜態代理
- 動態代理
- JDK動態代理
- cglib動態代理
- spring aop
- 策略模式
- SpringAOP策略模式的運用
- 生產者消費者模式
- 迭代器模式
- 函數式編程
- 方法引用
- 性能問題
- Lambda
- Lambda類型檢查
- Stream
- findFirst和findAny
- reduce
- 原始類型流特化
- 無限流
- 收集器
- 并行流
- AOP
- 靜態織入
- aspect
- aspect的定義
- AspectJ與SpringAOP
- 動態織入
- 靜態代理
- 動態代理
- JDK動態代理
- CGLib動態代理
- Spring AOP
- SpringAOP五種通知類型
- @Before
- @AfterReturning
- @AfterThrowing
- @After
- @Around
- Aspect優先級
- SpringAOP切點表達式
- within
- execution
- 嵌套調用
- 系統優化與重構
- 重疊構造器模式
- 工具類構造器優化
- 常見面試題
- new Object()到底占用幾個字節
- 訪問修飾符
- cloneable接口實現原理
- 異常分類以及處理機制
- wait和sleep的區別
- 數組在內存中如何分配
- 類加載為什么要使用雙親委派模式,有沒有什么場景是打破了這個模式
- 類的實例化順序
- 附錄
- JAVA術語
- FAQ
- 墨菲定律
- 康威定律
- 軟件設計原則
- 阿姆達爾定律
- 字節碼工具
- OSGI