2009-06-27 21 views
6

He escrito este método de clonación cuando el padre de la clase Employee es abstracto y el método clone() en la clase padre es abstracto. Quería copiar el tipo de datos primitivo del objeto del empleado con este código en lugar de copiar cada tipo de datos primitivos individualmente, pero este código tiene un problema con la línea que llamo método clone(). (Este es el código de clase Employee)¿Qué hay de malo con este clon()?

public Object clone() { 
    Object obj = new Object(); 
    Object object = obj.clone(); //Emphasis here 
    return object; 

} 

el error es: El clon método() desde el tipo de objeto no es visible.

Pero mi clase Employee está en la jerarquía de clases que puede acceder al método protegido clone() en la clase Object.

Ésta es mi sencilla clase Employee:

public class Employee extends Person implements Cloneable { 
private int ID; 

public Employee() { 
    ID = 0; 
} 

public void setID(int ID) { 
    this.ID = ID; 
} 

public int getID() { 
    return ID; 
} 

public Object clone1() throws CloneNotSupportedException { 
    try { 
     Object obj = new Object(); 

     Object object = obj.clone(); 
     return object; 
    } catch (CloneNotSupportedException ex) { 
     return null; 
    } 
} 
+0

1. Porque, según tengo entendido, sé que la situación en realidad es un poco complicada, no solo un simple caso de clonación(). – akarnokd

Respuesta

2

Quizás quiso implementar la interfaz Cloneable en su objeto?

Sin embargo, hay muy pocos casos que usaría clonar para copiar un objeto. Un ejemplo seguro de esto es array.clone(). Prefiero usar la expresión copiar-constructor o copiar/asignar manualmente los valores.

Hay artículo n. ° 11 en Effective Java (2da edición) sobre el problema de fondo. La interfaz clonable es un tipo especial de interfaz ya que modifica el comportamiento de la clase Object con respecto a la clonación. Básicamente es una función que permite clase interfaz en Java.

Editar: En función de su ejemplo, es posible que deba ajustar la llamada de clone() en un try-catch de CloneNotSupportedException en un caso general.

Edit2: reformulado mi respuesta

Edit3: Quizás quiso sustituir los métodos clone() en el contexto public? En la muestra que dio intenta clonar un objeto, que está en el paquete java.lang - apenas el paquete de su código está en

Edit4:. Creo que la respuesta ya está en los demás puestos, sólo quería para reflexionar sobre el problema subyacente.

Edit5: Prueba esto:

public Object clone1() throws CloneNotSupportedException {   
    return super.clone();   
} 

Edit6 A continuación, el nombre de su método public abstract Object copy() por ejemplo, como en la aplicación, utilice el super.clone() - para evitar confusiones.

Edit7 he hecho un poco eclipsado y salió con la siguiente solución:

public class Cloner { 
    public static abstract class Person { 
     protected abstract Object clone1() throws CloneNotSupportedException; 
     public Object copy() throws CloneNotSupportedException { 
      return clone1(); 
     } 
    } 
    public static class Employee extends Person implements Cloneable { 
     @Override 
     protected Object clone1() throws CloneNotSupportedException { 
      return super.clone(); 
     } 

    } 
    public static void main(String[] args) throws Exception { 
     new Employee().copy(); 
    } 
} 

Pero básicamente es el mismo concepto que el cambio de nombre de su método abstracto a algo más que el clon().

Edit8: Se arregló mi muestra, ahora funciona sin excepción.

(Sin embargo, el crédito real va a Gábor Hargitai para super.clone())

+0

Sí, he implementado la interfaz Cloneable. – Johanna

+0

Lo puse en el bloque try catch pero todavía tiene ese error. – Johanna

+0

No puedo usar super.clone(). aquí super es Person and Person tiene un clon abstracto() !!! ¿Cómo puedo llamar a super.clone() ???? – Johanna

0

no estoy muy familiarizado con Java, pero esto puede ayudar: http://en.wikipedia.org/wiki/Clone_(Java_method)

un extracto del mensaje:

Another disadvantage is that one often cannot access the clone() method on an abstract type. Most interfaces and abstract classes in Java do not specify a public clone() method. As a result, often the only way to use the clone() method is if you know the actual class of an object; which is contrary to the abstraction principle of using the most generic type possible. For example, if one has a List reference in Java, one cannot invoke clone() on that reference because List specifies no public clone() method. Actual implementations of List like ArrayList and LinkedList all generally have clone() methods themselves, but it is inconvenient and bad abstraction to carry around the actual class type of an object.

6

El mecanismo de clonación de Java es algo incómodo. Para poder clonarse, la clase debe hacer dos cosas. Primero debe implementar Clonable. En segundo lugar, debe anular el clon() y hacerlo público.

En su ejemplo, reemplaza clone() pero está invocando clone() no en la clase Employee sino en Object.class() donde clone() solo está protegido.

+0

No recibí tu respuesta. ¿Qué quieres decir con la línea 3 y 4 de tu respuesta? – Johanna

+0

Este tipo tiene razón, Object no tiene un método de clonación, solo lo hace ICloneable. Yo diría que necesitas lanzar obj a ICloneable y luego clonar, pero estás construyendo obj con 'new Object', por lo que realmente no tendrá clone(). ¿Qué crees exactamente que debería hacer tu código? – Blindy

+0

Creo que IClonable es C#? Pero sigue siendo un buen punto para clonar Object en lugar de hacerlo a sí mismo. – akarnokd

2

Usted simplemente debe escribir

return super.clone(); 

en su método clone e implementar la interfaz clonable.

+0

+1, según el comentario de Johanna a Italia – akarnokd

+0

No puedo porque la superclase es, por ejemplo, Persona que tiene el método abstracto clone(). – Johanna

+0

Eso no es un problema, porque la clonación real la realiza la clase Object; solo necesita implementar Cloneable, a menos que haya creado un método abstracto clone() en la clase Person. – akarnokd

4

Mister Bloch de Effective Java tiene algunas palabras interesantes para decir sobre el uso de clone.

http://www.artima.com/intv/bloch13.html

En general, el pensamiento actual es evitar el uso de clon, ya que es propenso a errores y muy mal entendido, la aplicación de constructor de copia es una estrategia alternativa o usar un método de fuerza bruta de una copia completa del objeto utilizando la serialización.

+0

+1 que proporciona un artículo legible en lugar de solo una referencia de libro. – akarnokd

-2

Básicamente, para tener un objeto apropiadamente clonable es suficiente tener un método público clone() implementado en esa clase.

La interfaz clonable es una interfaz que se utiliza para indicar a la máquina virtual que es seguro implementar el método clone() protegido por defecto como campo por copia de campo.

Para implementar correctamente el método de clonación para una clase, debe declarar un método público de clonación como este().

public Object clone() { 
    return super.clone(); 
} 

Un buen implementationk de trabajo creará un nuevo objeto y asignar correctamente los campos como los reaquires lógica de negocio:

public Object clone() { 
    CurrentClass newObject = new CurrentClass(); 

    newObject.field1 = this.field1; // for simple types: int, long, etc 
    newObject.referenceField = this.referenceField.clone(); // for agregate objects or references. 
    return newObject; 
} 

La conclusión: declarar un método clon pública. Si desea tener la implementación predeterminada como un campo por campo, copie la llamada super y marque la clase como Clonable Si solo desea la clonación personalizada, puede ignorar la marca Cloneable.

+0

bueno, pero clono el tipo primitivo uno por uno, no quiero esto. Quiero clonar esos tipos de datos primitivos a la vez sin usar "newObject.field1 = this.field1;" – Johanna

+0

así es como funciona el mecanismo de clonación :-). Si quiere algo más, debe implementarlo usted mismo (con generación de código alam y/o reflexión). –

+1

Se considera una mala práctica al nuevo objeto en clon. Debe usar super.clone() para obtener la nueva instancia clonada. –

11

El patrón estándar para la fabricación de un cloneable clase es:

  1. Implementar Cloneable
  2. reemplazar el método clone() y hacerlo público
  3. En clone() llamada super.clone() y luego copiar el estado de cualquier objeto mutable

Debe no crear un nuevo objeto u cantar new. La forma correcta es llamar al super.clone() para una nueva instancia. Objectclone() es especial y creará una nueva copia del objeto y copiará sus campos y referencias primitivos.

Por ejemplo:

public class Person implements Cloneable { 
    protected String name; 
    // Note that overridden clone is public 
    public Object clone() { 
     Person clone = (Person)super.clone(); 
     // No need to copy name as the reference will be 
     // copied by Object's clone and String is immutable 
     return clone; 
    } 
} 

public class Employee extends Person { 
    protected int id; 
    protected java.awt.Point location; 
    public Object clone() { 
     Employee clone = (Employee)super.clone(); 
     // No need to copy id as Object's clone has already copied it 
     // Need to clone location as Point is mutable and could change 
     clone.location = location.clone(); 
     return clone; 
    } 
} 
+0

cierto. ¿Te preguntas cómo expresas la necesidad de que los hijos de una persona sean reproducibles, o en general: copien ellos mismos a pedido? ¿Es suficiente tener una superclase clonable? – akarnokd

+1

Todas las subclases heredan las interfaces principales. Entonces la persona es clonable. –

5

Creo que la respuesta verde actual es mala, ¿por qué usted puede pedir?

  • Se añade una gran cantidad de código
  • Se requiere que enumerar todos los campos que va a copiar y hacer esto
  • Esto no funcionará para las listas al utilizar clone() (Esto es lo clone() pues dice HashMap: Devuelve una copia superficial de esta instancia HashMap:. las llaves y valuesthemselves no se clonan) por lo que terminan haciendo de forma manual (esto me hace llorar)

Ah, y por cierto serialización también es malo , es posible que tenga que agregar Serializable por todas partes (esto también me hace cr y)

Entonces, ¿cuál es la solución:

biblioteca de Java profundas clonación La biblioteca de clonación es una biblioteca de Java fuente pequeña y abierta (licencia Apache) que en el fondo clones de objetos. Los objetos no tienen que implementar la interfaz Cloneable. Efectivamente, esta biblioteca puede clonar CUALQUIER objeto Java. Se puede utilizar, es decir, en implementaciones de caché, si no desea que se modifique el objeto en caché o siempre que desee crear una copia profunda de los objetos.

Cloner cloner=new Cloner(); 
XX clone = cloner.deepClone(someObjectOfTypeXX); 

echarle un vistazo en http://code.google.com/p/cloning/

Cuestiones relacionadas