2009-07-16 23 views

Respuesta

90

El hecho de que el clon esté protegido es extremadamente dudoso, así como el hecho de que el método clone no está declarado en la interfaz Cloneable.

Se hace el método bastante inútil para la toma de copias de datos porque no se puede decir:

if(a instanceof Cloneable) { 
    copy = ((Cloneable) a).clone(); 
} 

creo que el diseño de Cloneable es ahora ampliamente considerado como un error (cita más adelante). Normalmente me gustaría poder hacer implementaciones de una interfaz Cloneable pero no necesariamente hacen la interfaz Cloneable (similar al uso de Serializable). Esto no puede hacerse sin la reflexión:

ISomething i = ... 
if (i instanceof Cloneable) { 
    //DAMN! I Need to know about ISomethingImpl! Unless... 
    copy = (ISomething) i.getClass().getMethod("clone").invoke(i); 
} 

cita de Effective Java de Josh Bloch:.
"La interfaz Cloneable fue concebido como una interfaz mixin para objetos para anunciar que permiten la clonación Por desgracia, falla para servir a este propósito ... Este es un uso muy atípico de las interfaces y no uno para ser emulado ... Para que la implementación de la interfaz tenga algún efecto en una clase, ella y todas sus superclases deben obedecer un bastante complejo , protocolo inaplicable y en gran parte indocumentado "

+2

Si el objeto no es clonable, el clon de Object() lanzará CloneNotSupportedException. Por lo tanto, necesita ser Clonable si va a llamar a super.clone() (lo que hace que se llame a Object.clone()). No veo cómo se puede serializar un objeto sin implementar Serializable. –

+0

"Creo que el diseño de Cloneable ahora se considera en gran medida como un error". [citación necesitada] –

+0

Lo siento - no estaba implicando eso. Simplemente estaba implicando que el "buen" diseño es * no * hacer que una interfaz se extienda 'Serializable' - depende de las implementaciones decidir si implementar 'Serializable'. Estaba extendiendo esto a 'Cloneable', no es algo que una interfaz debería extenderse, pero una implementación de una interfaz es libre de ser' Cloneable'. El problema es que, si tiene un parámetro del tipo de interfaz, pregunte si es clonable; ¡pero en realidad no puedes clonarlo! –

6

cloneclone está protegido porque es algo que se debe anular para que sea específico para la clase actual. Si bien sería posible crear un método público clone que clonaría cualquier objeto, esto no sería tan bueno como un método escrito específicamente para la clase que lo necesita.

+0

pero ¿por qué tiene que estar protegido para eso? – Janusz

+2

Está protegido por lo que no usa el que está en el objeto (de todos modos, lanzará una excepción). Quieren que lo anules en una clase, luego lo haces público. (Respondió un par de veces más abajo también) –

+1

Y inútil al considerar las interfaces según mi punto por debajo –

4

El método de clonación no se puede utilizar directamente en ningún objeto, por lo que la subclase debe modificarlo.

Por supuesto, podría ser público y arrojar una excepción apropiada cuando la clonación no sea posible, pero creo que sería engañoso.

La manera en que se implementa clon ahora te hace pensar por qué quieres usar el clon y cómo quieres que se clone tu objeto.

2

Está protegido porque la implementación predeterminada realiza una copia superficial de todos los campos (incluido el privado), eludiendo el constructor. Esto no es algo que un objeto podría estar diseñado para manejar en primer lugar (por ejemplo, podría hacer un seguimiento de las instancias de objetos creados en una lista compartida, o algo similar).

Por la misma razón, la implementación predeterminada de clone() se lanzará si el objeto al que se llama no implementa Cloneable. Es una operación potencialmente insegura con consecuencias de largo alcance, y por lo tanto el autor de la clase debe optar explícitamente.

+0

En realidad, la implementación predeterminada (en el objeto) arroja una excepción según los documentos ... –

+2

No, no solo arroja. Desde su JavaDoc: "El método clonar para la clase Object realiza una operación de clonación específica. Primero, si la clase de este objeto no implementa la interfaz Cloneable, se lanza una CloneNotSupportedException. Tenga en cuenta que se considera que todas las matrices implementan la interfaz Cloneable. De lo contrario, este método crea una nueva instancia de la clase de este objeto e inicializa todos sus campos con exactamente los contenidos de los campos correspondientes de este objeto, como por asignación, los contenidos de los campos no son clonados. " –

2

Desde el javadoc de clonable.

* By convention, classes that implement this interface (cloneable) 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. 

* 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. 

Por lo que podría llamar clon en cada objeto, pero esto le daría mayor parte del tiempo no los resultados que desea o una excepción. Pero solo se recomienda si implementa clonable.

+2

¡No se puede llamar a clonar en todos los objetos, porque está protegido! –

+0

Perdón por mi un poco confuso las últimas dos oraciones ... – Janusz

23

La interfaz Clonable es solo un marcador que indica que la clase puede admitir clonar. El método está protegido porque no debe llamarlo en el objeto, puede (y debe) anularlo como público.

De Sol:

En la clase Object, el método clone() se declara protegidos. Si todo lo que hace es implementar Cloneable, solo las subclases y los miembros del mismo paquete podrán invocar clone() en el objeto. Para habilitar cualquier clase en cualquier paquete para acceder al método clone(), tendrá que anularlo y declararlo público, como se hace a continuación. (Cuando anula un método, puede hacerlo menos privado, pero no más privado. Aquí, el método clone() protegido en Object se anula como un método público.)

+0

Lo que está bien, * hasta que traigas interfaces a la mezcla * - intenta e intenta clonar una implementación desconocida de 'Set' –

+0

@oxbow_lakes: pero tal vez algunas implementaciones de El conjunto no es clonable – newacct

+2

No se puede clonar nada que no implemente la interfaz Clonable; es un marcador que dice "Esta clase es apropiadamente clonable", muy similar a la interfaz Serializable. Por cierto, hay una manera de clonar clases a través de la serialización que funciona bien, google algo así como "clonación de serialización java" y probablemente encontrarás varias maneras de obtener una copia profunda de tu objeto. –

-2

Sí, el mismo problema que conocí. Pero resolverlo mediante la implementación de este código

public class Side implements Cloneable { 
    public Side clone() { 

     Side side = null; 
     try { 
      side = (Side) super.clone(); 
     } catch (CloneNotSupportedException e) { 
      System.err.println(e); 
     } 
     return side; 
    } 
} 

Así como el antes de que alguien dijo.

+1

CloneNotSupportedException es otro ejemplo de una excepción comprobada que debe desmarcarse (es decir, debe extender RuntimeException, no Exception). Aunque el método clone() en la clase Side implementa Cloneable y, por lo tanto, nunca lanzará CloneNotSupportedException, Side.clone() aún debe capturar o declarar la excepción. Esto simplemente agrega ruido de manejo de excepciones superfluo al método clone(). –

-3

Una vez más, el marco de Java JDK muestra brillante pensamiento:

interfaz Cloneable no contiene un "clon T pública();" método porque actúa más como un atributo (por ejemplo, Serializable) que permite que una instancia sea clonada.

No hay nada malo con este diseño porque:

  1. Object.clone() no va a hacer lo que quiera con su clase personalizada definidos.

  2. Si tiene Myclass implementa Cloneable => sobrescribe clone() con "clon MiClase pública()"

  3. Si tiene MyInterface extiende Cloneable y algunos myclasses ejecución MyInterface: simplemente definen "MyInterface pública clon();" en la interfaz y cada método que use objetos MyInterface podrá clonarlos, sin importar su clase MyClass.

+2

si su clase es heredada, su implementación de clon de clase derivada no será segura hasta que las implementaciones de su clase base proporcionen métodos seguros de clonación. Además, es un tipo de condición de diseño inusual tener una interfaz sin método/atributo. Esta interfaz no obliga a la clase a implementar el clon. – prap19

-2

Bueno, también los desarrolladores de sol son sólo humanos, y que, efectivamente, hacen gran error para implementar el método clone como protegida, el mismo error que ellos implementaron un método clon que no funciona en ArrayList! Por lo tanto, en general, existe un malentendido mucho más profundo incluso de los programadores de Java experimentados sobre el método de clonación.

Sin embargo, he encontrado recientemente una solución rápida y fácil de copiar cualquier objeto con todo su contenido, no importa cómo se construye y lo que contiene, véase mi respuesta aquí: Bug in using Object.clone()

2

mi humilde opinión, es tan simple ya que esto:

  • #clone no se permite llamar en objetos no Cloneable, por lo tanto no se haga pública la
  • #clone tiene que ser llamado por subclases ob Object que implementan Cloneable para obtener la copia superficial del cla derecha ss

¿Cuál es el alcance correcto para los métodos que se pueden llamar por subclases, pero no por otras clases?

Es protected.

Las clases que implementan Cloneable por supuesto harán que este método sea público para que pueda ser llamado desde otras clases.

Cuestiones relacionadas