论坛首页 Java企业应用论坛

我发现了一个悖论

浏览 8920 次
精华帖 (0) :: 良好帖 (9) :: 新手帖 (0) :: 隐藏帖 (6)
作者 正文
   发表时间:2011-08-22   最后修改:2011-08-23
我还在加班,好烦呀。。。

今天,我发现了一个java的悖论。

在java.lang.Object类中,对于clone方法的注释描述中,有如下一段话:

*The class <tt>Object</tt> does not itself implement the interface 
* <tt>Cloneable</tt>, so calling the <tt>clone</tt> method on an object 
* whose class is <tt>Object</tt> will result in throwing an
* exception at run time.


这是一个本地化方法。

既然Object本身没有实现Cloneable接口,为啥要将Cloneable设计为标记接口,而又将clone方法放入Object类中呢?

为啥不向Runnable这样,里面写个方法clone呢。

像下面这样子:


/*
 * @(#)Cloneable.java	1.17 05/11/17
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang;

/**
 * A class implements the <code>Cloneable</code> interface to 
 * indicate to the {@link java.lang.Object#clone()} method that it 
 * is legal for that method to make a 
 * field-for-field copy of instances of that class. 
 * <p>
 * Invoking Object's clone method on an instance that does not implement the 
 * <code>Cloneable</code> interface results in the exception 
 * <code>CloneNotSupportedException</code> being thrown.
 * <p>
 * By convention, classes that implement this interface should override 
 * <tt>Object.clone</tt> (which is protected) with a public method.
 * See {@link java.lang.Object#clone()} for details on overriding this
 * method.
 * <p>
 * Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
 * Therefore, it is not possible to clone an object merely by virtue of the
 * fact that it implements this interface.  Even if the clone method is invoked
 * reflectively, there is no guarantee that it will succeed.
 *
 * @author  unascribed
 * @version 1.17, 11/17/05
 * @see     java.lang.CloneNotSupportedException
 * @see     java.lang.Object#clone()
 * @since   JDK1.0
 */
public interface Cloneable<T> { 

     /**
      * Blalala..
      */
     public T clone();

}


   发表时间:2011-08-22  
object带的clone不是开发者自己实现的clone,所以跟clonable没有关系。
Runnable是需要用户自己实现的。

and 如果加个这么的接口,
你也该是

public Object clone();

你clone不能void啊
0 请登录后投票
   发表时间:2011-08-23  
Joshua Bloch提到过这个问题。

算是历史遗留问题吧。
0 请登录后投票
   发表时间:2011-08-23  
H_eaven 写道
Joshua Bloch提到过这个问题。

算是历史遗留问题吧。



其实是小弟看了本坛的一篇帖子,也来学着多读代码。

首先就仔细读了Object类,发现了这个疑问。

没想到又被人在投隐藏。
0 请登录后投票
   发表时间:2011-08-23  
隐藏很可怕吗?
0 请登录后投票
   发表时间:2011-08-23  
jackra 写道
隐藏很可怕吗?

不可怕 但是对发帖者是一个不小的打击~

PS:为什么我不能投票
0 请登录后投票
   发表时间:2011-08-23  
这个问题主要是不想让所有的对象都具有clone的能力,所以是Object的clone方法是protected,这样就无法实现Cloneable接口了,因为方法的访问权限不能被降低。

但是如果不在Object中实现默认的clone,那么像你说类似于Runable的,但用户无法实现Cloneable接口,因为clone是需要通过本地方法来实现copy。

当然可以提供一个Clone的Utils工具方法实现Clone,但在Object添加clone方法和实现Cloneable标记接口显得更加OO和自然一些。
0 请登录后投票
   发表时间:2011-08-23  
fuliang 写道
这个问题主要是不想让所有的对象都具有clone的能力,所以是Object的clone方法是protected,这样就无法实现Cloneable接口了,因为方法的访问权限不能被降低。

但是如果不在Object中实现默认的clone,那么像你说类似于Runable的,但用户无法实现Cloneable接口,因为clone是需要通过本地方法来实现copy。

当然可以提供一个Clone的Utils工具方法实现Clone,但在Object添加clone方法和实现Cloneable标记接口显得更加OO和自然一些。



感谢讨论!

方法clone是protected修饰,protected是对本类、同包的类和子类可访问的,所以说clone方法是完全可以override的,因为java中所有的类和接口都是继承自Object类的。

对于clone这个本地方法做的事,确实如你所说,用接口去定义是无法直接实现copy功能,至少我不知道仅用java怎么去实现copy。但是是否可以通过一些方法,首先实例化一个同样的类实例,然后将原来实例的所有属性值进行copy呢,就像赋值语句那样?这样做可能在效率上或者安全方面比较欠缺。

对于更加OO的观点,我觉得对于这个问题来说,每个人有每个人的答案。
1 请登录后投票
   发表时间:2011-08-24  
clone()是个本地方法,而接口里只能定义public abstract的方法,不能定义native方法。java.lang.Cloneable接口跟java.io.Serializable一样只是个标志接口。楼主说的对,对于OO的观点,每个人都有每个人的答案,我的观点是这样的:clone()放到Object类中,可选择性的让需要克隆的类实现Cloneable接口。克隆是每个对象都应该拥有的功能,而这个功能应该放到一个可实例化的类中,而Cloneable接口作为一个标志接口,相当于一个证件。举一个我觉得有点类似的例子,比如现实生活中“出国”一样,按理来说,众生平等,人人都可以拥有“出国”的想法和行动,但是在政策的制约下必须得有签证才行。比如定义一个接口是"拿到签证的人",一个类“人”,一个方法“出国()”.“出国()”应该定义到“人”这个类里更合适吧。
0 请登录后投票
   发表时间:2011-08-24  
zhoujianghai 写道
clone()是个本地方法,而接口里只能定义public abstract的方法,不能定义native方法。java.lang.Cloneable接口跟java.io.Serializable一样只是个标志接口。楼主说的对,对于OO的观点,每个人都有每个人的答案,我的观点是这样的:clone()放到Object类中,可选择性的让需要克隆的类实现Cloneable接口。克隆是每个对象都应该拥有的功能,而这个功能应该放到一个可实例化的类中,而Cloneable接口作为一个标志接口,相当于一个证件。举一个我觉得有点类似的例子,比如现实生活中“出国”一样,按理来说,众生平等,人人都可以拥有“出国”的想法和行动,但是在政策的制约下必须得有签证才行。比如定义一个接口是"拿到签证的人",一个类“人”,一个方法“出国()”.“出国()”应该定义到“人”这个类里更合适吧。



这个例子举得很形象,深表赞同。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics