public LeNo generate (PrintStream stream) {
prepareOperands(stream);
LeNo l = (LeNo)left;
LeNo r = (LeNo)right;
if (l instanceof NumNo && r instanceof NumNo) {
return new NumNo((Integer.getInteger(l.name()).intValue()*Integer.getInteger(r.name())));
}
if ((l instanceof NumNo && l.name().equals("0"))||(r instanceof NumNo && r.name().equals("0"))) {
return new NumNo(0); // cut of rest of code here....
Is there a way I can create a new NumNo method without having to create it when I return?
The thing is I still want to return NumNo, but without creating a new NumNo doing it.
It is just return new NumNo(0); that you don't want to create right? Because it is the same every time? If so, you can create a static instance of that object. For example,
private static final NewNo ZERO = new NewNo(0);
This is called the flyweight pattern, where you create commonly used instances once.
return NumNo.getClass();
To return a class instead of an instance.
Create an instance with java.lang.Class.newInstance()
for example:
klass = generate(stream);
object = klass.newInstance();
Related
I am trying to create a utility method that should be able to deep-clone any object.
(Object.clone() only works on Object implementing Cloneable and I heard it's flawed anyways.)
I am using Objenesis to create new instances of objects without the use of constructors.
However, when trying to clone a JFrame I get the following Exception:
(using this class because I think it should be a good and complex test)
java.lang.InstantiationError: [Ljava.util.concurrent.ConcurrentHashMap$Node;
at sun.reflect.GeneratedSerializationConstructorAccessor12.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
I am open to any solution, not necessarily limited to Objenesis.
My Code:
private static ObjenesisStd OBJENESIS = new ObjenesisStd();
#SuppressWarnings("unchecked")
public static <T> T clone(T object, boolean deep){
if(object == null){
return null;
}else{
try {
T clone = (T) OBJENESIS.newInstance(object.getClass());
List<Field> fields = ReflectionUtil.getAllFieldsInHierarchy(object.getClass());
for(Field field : fields){
boolean isAccessible = field.isAccessible();
boolean isFinal = ReflectionUtil.isFinal(field);
field.setAccessible(true);
ReflectionUtil.setFinal(field, false);
Class<?> type = field.getType();
if(!deep || type.isPrimitive() || type == String.class){
field.set(clone, field.get(object));
}else{
field.set(clone, clone(field.get(object), true));
}
field.setAccessible(isAccessible);
ReflectionUtil.setFinal(field, isFinal);
}
return clone;
} catch (Throwable e) {
e.printStackTrace();
//throw new RuntimeException("Failed to clone object of type " + object.getClass(), e);
return null;
}
}
}
public static void main(String[] args) {
GetterSetterAccess access = new GetterSetterAccess(JFrame.class);
JFrame frame = new JFrame("Test Frame");
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
System.out.println("----------------------------------------------");
frame = clone(frame, true);
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
}
EDIT: Got it to work with the accepted answer and a few more fixes:
Avoided cloning Wrappers of Primitive Types (Integer.class etc.)
Avoided cloning Classes (Objects of the class Class.class)
Stored the cloned objects in a Map and reused them, so if Object A has a reference to Object B and Object B one to Object A it doesn't get stuck in an infinite loop. I also used a Map that checks for exact equality (==) instead of using equals().
Created a custom exception class which would just be passed on instead of throwing a new exception on every level (causing a huge caused-by-depth).
I finally figured it out. Your code doesn't handle arrays. So it fails with instantiating "[Ljava.util.concurrent.ConcurrentHashMap$Node;" which is an array of Nodes.
However, I will advocate that indeed, you should not do that. You will end up with fairly complicated code. Depending on what you want to do, you could use Jackson or XStream to do a marshall / unmarshall to perform the copy.
If you really want to continue that path, you will need something like this after the null check of your clone method.
if(object.getClass().isArray()) {
int length = Array.getLength(object);
Object array = Array.newInstance(object.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(array, i, clone(Array.get(object, i), true));
}
return (T) array;
}
Hello everyone I'm writing a Java program where I need to copy the values of an old object into a new one (the two must be separated, if I chance one, the other must not be affected);
Once the copy is done the data should be displayed on Jtable, however the 2 object created seems to be linked(if I try to change one the other get modified too)
I suspect the problem is this method :
public void CopiatoreDiArea(Area nuova, Area daCopiare){
nuova.setNome(daCopiare.getNome());
nuova.setInter(daCopiare.getInter());
nuova.setRischioInerente(daCopiare.getRischioInerente());
nuova.setRischioResiduo(daCopiare.getRischioResiduo());
nuova.setControlli(daCopiare.getChecklists());
nuova.setStrategicita(daCopiare.getStrategicita());
nuova.setRischiosita(daCopiare.getRischiosita());
nuova.setMediaHpReato(daCopiare.getMediaHpReato());
nuova.setProbabilitaInerente(daCopiare.getProbabilitaInerente());
nuova.setEsposta(daCopiare.isEsposta());
nuova.setStrumentale(daCopiare.isStrumentale());
nuova.setCommento(daCopiare.getCommento());
nuova.setCondivisa(daCopiare.isCondivisa());
if (daCopiare.getNomeCompleto() != null){
nuova.setNomeCompleto(daCopiare.getNomeCompleto());
}
else{
nuova.setNomeCompleto(daCopiare.getNome());
}
if (daCopiare.getInterCompany() != null){
nuova.setInterCompany(daCopiare.getInterCompany());
}
if (daCopiare.getArticoli() != null || daCopiare.getArticoli().size() != 0){
nuova.setArticoli(daCopiare.getArticoli());
}
}
If this is the wrong way, how can I accomplish that?
How do you create the new instance of nuova object?
You have to make a new instance of it, if you created the new object with the reference of the oldest they will be linked and every change in the one will be reflected in other.
If you call the method as following:
CopiatoreDiArea(new Area(), oldArea)
Your code should work as the new 'Area' has all the attributes the other object has without any references being made to the new Area.
Try this:
public Area CopiatoreDiArea(Area daCopiare){
Area nuova = new Area();
nuova.setNome(daCopiare.getNome());
nuova.setInter(daCopiare.getInter());
nuova.setRischioInerente(daCopiare.getRischioInerente());
nuova.setRischioResiduo(daCopiare.getRischioResiduo());
nuova.setControlli(daCopiare.getChecklists());
nuova.setStrategicita(daCopiare.getStrategicita());
nuova.setRischiosita(daCopiare.getRischiosita());
nuova.setMediaHpReato(daCopiare.getMediaHpReato());
nuova.setProbabilitaInerente(daCopiare.getProbabilitaInerente());
nuova.setEsposta(daCopiare.isEsposta());
nuova.setStrumentale(daCopiare.isStrumentale());
nuova.setCommento(daCopiare.getCommento());
nuova.setCondivisa(daCopiare.isCondivisa());
if (daCopiare.getNomeCompleto() != null){
nuova.setNomeCompleto(daCopiare.getNomeCompleto());
}
else{
nuova.setNomeCompleto(daCopiare.getNome());
}
if (daCopiare.getInterCompany() != null){
nuova.setInterCompany(daCopiare.getInterCompany());
}
if (daCopiare.getArticoli() != null || daCopiare.getArticoli().size() != 0){
nuova.setArticoli(daCopiare.getArticoli());
}
}
And then in your call:
Area nuova = CopiatoreDiArea(daCopiare);
If you copy primitives (or the special primitive wrapper classes) in Java, the runtime will always do a deep copy of the values. To illustrate this, I show a few examples.
See http://jdoodle.com/a/3TL for an online runnable version of the code below:
public class MyClass {
public static void main(String[] args) {
int a = 10;
int b = a;
b = 20;
System.out.println(a + " != " + b);
// We did not change a when changing b.
Integer c = 10;
Integer d = c;
d = 20;
System.out.println(c + " != " + d);
// We did not change c when we changed d, even though they are class instances.
// This shows that primitive wrappers are handled differently due to
// autoboxing.
// See https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
MyInteger e = new MyInteger(10);
MyInteger f = e;
f.value = 20;
System.out.println(e + " == " + f);
// Changing the data contained within f also affected e. The two variables now point to the same instance.
MyInteger g = new MyInteger(10);
MyInteger h = new MyInteger(g);
h.value = 20;
System.out.println(g + " != " + h);
// We prove that we have two instances, initially containing
// the same value but changing their internal values does not
// affect each other.
}
private static class MyInteger {
public int value;
public MyInteger(int value) {
this.value = value;
}
public MyInteger(MyInteger other) {
this.value = other.value;
}
public String toString() {
return Integer.toString(this.value);
}
}
}
From your example, it seems you might be trying to copy complex classes, even lists maybe, and these will always copy a reference only when you use simple assignment.
There are a few options that you could take, for instance the copy constructor that I use above, or alternatively rely on some form of reflection or serialization that does the hard work for you.
Apache Commons Lang has a SerializationUtils class that will run through all internal data in your classes, serialize them into byte format and then try to re-instantiate new versions of the same classes with the serialized data.
The Cloner library makes use of reflection and some special performance cases for known types such as collections and calendars, with some great debugging options.
Declare a copy constructor for deep cloning your object
public class Area {
public Area() { // constructor }
public Area(Area objectToCopy) {
setNome(objectToCopy.getNome());
setInter(objectToCopy.getInter());
setRischioInerente(objectToCopy.getRischioInerente());
setRischioResiduo(objectToCopy.getRischioResiduo());
setControlli(objectToCopy.getChecklists());
setStrategicita(objectToCopy.getStrategicita());
setRischiosita(objectToCopy.getRischiosita());
setMediaHpReato(objectToCopy.getMediaHpReato());
setProbabilitaInerente(objectToCopy.getProbabilitaInerente());
setEsposta(objectToCopy.isEsposta());
setStrumentale(objectToCopy.isStrumentale());
setCommento(objectToCopy.getCommento());
setCondivisa(objectToCopy.isCondivisa());
if (objectToCopy.getNomeCompleto() != null)
setNomeCompleto(objectToCopy.getNomeCompleto());
else
setNomeCompleto(objectToCopy.getNome());
if (objectToCopy.getInterCompany() != null)
setInterCompany(objectToCopy.getInterCompany());
if (objectToCopy.getArticoli() != null || objectToCopy.getArticoli().size() != 0)
setArticoli(objectToCopy.getArticoli());
}
}
and then do it calling
Area newArea = new Area(oldArea);
I am unable to create an object using singleton design pattern, here is what I did:
class Test {
public static Test objTest = null;
public static int count = 0;
public static Test CreateObject() {
if (objTest != null)
objTest = new Test();
return objTest;
}
private Test() {
Test.count++;
}
}
Have I created zeroton pattern ?
Check your if condition inside createObject method once. it should be if(objTest == null) .
Besides the fact, that your count would always be either '0' or '1' (ignoring potential multi-threading issues) - why do you have that parameter?
You are checking for objTest != null instead of objTest == null.
That's why you are always returning null and never create a new instance.
The objTest variable should also be private, you'll not want to reference to a null instance. Access to the instance should only be possible through your CreateObject() method.
I wonder if there is a method that checks whether my new instance has been already created and added to my instances in Java...
Like ;
Instance instance = new Instance(i, vals);
if(instances.contains(instance) == false) { //or hasInstance maybe
instances.add(instance);
}
I understand, that you want for two objects x1 and x2 with x1.equals(x2) that x1 is the same instance (x1 == x2).
One needs to do something like this:
private Map<Instance, Instance> identityMap = new HashMap<>();
public Instance unique(Instance instance) {
Instance first = identityMap.get(instance);
if (first == null) {
first = instance;
identityMap.put(instance, instance);
}
return first;
}
Instance instance = new Instance(i, vals);
instance = unique(instance);
The reason is, that you want to maintain the first instance, to be used by all.
By the way - for other purposes:
Set<Instance> instances = ...;
Instead of
if (!instances.contains(instance)) { // if not instances contains
one could use code like
if (instances.add(instance)) {
// Added, hence new...
} else {
// Not added, hence already existing...
}
im trying to copy the contents of one array to another without pointing to the same memory, but i cant.
My Code:
class cPrueba {
private float fvalor;
public float getFvalor() {
return fvalor;
}
public void setFvalor(float fvalor) {
this.fvalor = fvalor;
}
}
List<cPrueba> tListaPrueba = new ArrayList<cPrueba>();
List<cPrueba> tListaPrueba2 = new ArrayList<cPrueba>();
cPrueba tPrueba = new cPrueba();
tPrueba.setFvalor(50);
tListaPrueba.add(tPrueba);
tListaPrueba2.addAll(tListaPrueba);
tListaPrueba2.get(0).setFvalor(100);
System.out.println(tListaPrueba.get(0).getFvalor());
The result is "100.0" ....
Still pointing to the same object... Any short way to copy ? (without for(..){})
EDIT:
class cPrueba implements Cloneable {
private float fvalor;
public float getFvalor() {
return fvalor;
}
public void setFvalor(float fvalor) {
this.fvalor = fvalor;
}
public cPrueba clone() {
return this.clone();
}
}
List<cPrueba> tListaPrueba = new ArrayList<cPrueba>();
List<cPrueba> tListaPrueba2 = new ArrayList<cPrueba>();
cPrueba tPrueba = new cPrueba();
tPrueba.setFvalor(50);
tListaPrueba.add(tPrueba);
for ( cPrueba cp : tListaPrueba )
tListaPrueba2.add(cp);
tListaPrueba2.get(0).setFvalor(100);
System.out.println(tListaPrueba.get(0).getFvalor());
Still get 100...
There is no way to "deepcopy" an array, or any kind of Collection (which includes List) or even Map if your object itself does not have deep copy support (for instance, via a copy constructor).
So, to your question:
Any short way to copy ? (without for(..){})
the answer is no.
Of course, if your objects are immutable, this is not a concern.
Like dystroy said, you'll need to pass through the loop and clone all of the objects, like this:
List<cPrueba> newList = new ArrayList<cPrueba>();
for ( cPrueba cp : oldList )
newList.add(cp.clone());
And that's assuming your object implements Cloneable, or at least has a method called clone.
So no, there is no short way (unless you write your own static method), but it is possible.
EDIT
You need your clone method to return a new cPrueba:
public cPrueba clone() {
cPrueba c = new cPrueba();
c.setFvalor(this.getFvalor());
return c;
}
Also, make sure you call cp.clone() in your for loop; don't just pass cp to the add method. e.g., change
tListaPrueba2.add(cp);
to
tListaPrueba2.add(cp.clone());
vanilla Java can't do this for you.
but by adding some spice you can get it done with the Dozer framework:
http://dozer.sourceforge.net/