I have the following problem and wonder whether there is an efficient solution to it.
(I am using Java)
Imagine you have multiple different types of classes holding the same data in variables with different name and consider this given.
Here an example:
Imagine there are the three empiric values as member within a container class
short color
int size
String shape
and consider the two classes
class1
class2
class1 has three member variables being the empiric values:
short rgb_color -> corresponds to color
long bigness -> corresponds to bigness
String contour -> corresponds to shape
class2 has three member variables being the empiric values:
int cmyk -> corresponds to color
int greatness -> corresponds to bigness
String shapecountour -> corresponds to shape
As you see the names are different. So if I want to import the values from class one and two into the container class, I would need to
convert every parameter by itself in order to add it to the container class and thus
I need to type as there are member variables (here 6)
e.g. see this pseudo code for the import function:
public void import(class1 class){
this.color = (short) class.rgb_color;
this.size = (int) class.bigness;
this.shape = (String) class.contour;
}
public void import(class2 class){
this.color = (short) class.cmyk;
this.size = (int) class.greatness;
this.shape = (String) class.shapecontour;
}
Now imagine problems, where there are much more parameters.
Is there a generic way to solve the import as to do it one by one for each member?
Thank you for your help.
EDIT: Thanks already for the fast answers.
As I said I cannot modify class1 and class2.
I have checked the reflection, where they have this example for changing the fields.
public class Book {
public long chapters = 0;
public String[] characters = { "Alice", "White Rabbit" };
public Tweedle twin = Tweedle.DEE;
public static void main(String... args) {
Book book = new Book();
String fmt = "%6S: %-12s = %s%n";
try {
Class<?> c = book.getClass();
Field chap = c.getDeclaredField("chapters");
out.format(fmt, "before", "chapters", book.chapters);
chap.setLong(book, 12);
out.format(fmt, "after", "chapters", chap.getLong(book));
Field chars = c.getDeclaredField("characters");
out.format(fmt, "before", "characters",
Arrays.asList(book.characters));
String[] newChars = { "Queen", "King" };
chars.set(book, newChars);
out.format(fmt, "after", "characters",
Arrays.asList(book.characters));
Field t = c.getDeclaredField("twin");
out.format(fmt, "before", "twin", book.twin);
t.set(book, Tweedle.DUM);
out.format(fmt, "after", "twin", t.get(book));
// production code should handle these exceptions more gracefully
} catch (NoSuchFieldException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
But still I need to call each variable by name as e.g. "chapters".
What do I get wrong?
You have two options to resolve the issue:
To change the design, as suggested above. It seems that inheritance of some base class (with these three fields) should work fine.
If you don't have a way to modify these two classes (class1, class2) => You have to specify the mapping between the fields anyway. The straightforward way is your option with converters. Other option is to define the mapping with annotations/xml/etc. and to use some mapping tool. These conversation has a good list of them:
any tool for java object to object mapping?
Dozer seems to be the most promising for me.
You can use java reflection api to obtain list of available fields and than match them by type.
Why don't you do this change your design a bit : Create a parent class and pull those parameters in to parent class, and let your Class1,Class2 extend new Parent class. Now access those parameters.
class BaseClass{
short color;
int size;
String shape;
}
class Class1 extends BaseClass{
-----Other Class Properties----------
}
class Class2 extends BaseClass{
-----Other Class Properties----------
}
Related
The title can easily be misunderstood, but it boils down to that I most likely require a design-pattern to eliminate redundant code. To make my question as clear as possible I made a code example instead of writing a vague explanation.
Basically, I have the following functions:
getValue1(), getValue2(), getValue3(), ... , getValue12()
These functions could look as follows (though all differ slightly from each other and are not editable by means of making them implement an interface for a strategy pattern):
public int getValue1()
{
return 1 + 2;
}
Next we have a secondary class myClass which requires the values returned by the getValue() functions. A function from myClass would then look as follows (each differ in the fact that they make use of a different getValue() function):
public int getMyValues1()
{
int[] values = new int[10];
for (int i = 0; i < 10; i++) {
int[i] = getValue1() // NOTE: getValueX() may output differently each time.
}
}
We have arrived at our problem.
If we would make a getMyValues() function for each respective getValue(), we would have to copy and then paste the same code several times.
This goes against everything OOP languages stand for - that's why I require your help.
Any suggestion is much appreciated!
EDIT:
I reopened the question, because I didn't have Java 8 supported on the IDE I am to use.
Basically I have the following setup:
getValueClass
getValue1()
getValue2()
etc.
myClass
getMyValues1()
getMyValues2()
etc.
implemetingClass
private myClass mc = new MyClass()
main()
getLowestValue(int[] values)
And so main() could look as follows - if i'd wish to output the lowest value:
public static void main(String[] args)
{
...
System.out.print(getLowestValue(mc.getMyValues1()));
...
}
This edit goes to show that a strategy pattern isn't viable, since I have my functions in one class.
Hopefully this clears up any confusion and I really hope you guys can help me solve this issue!
Assuming these methods are public, then in Java 8, you should be able to use a functional interface (in this trivial example it would be a java.util.function.IntSupplier) and pass a reference to these methods as a lambda expression.
Something like (compilation not tested):
public int[] getMyValues(IntSupplier supplier) {
int[] values = new int[10];
for (int i = 0; i < 10; i++) {
int[i] = supplier.getAsInt()
}
return values;
}
Called using:
int[] values = someobject.getMyValues(someobject::getValues1)
This is more or less using those methods as strategies without the need to make an actual interface and multiple implementations: the strategy interface is the functional interface itself and the method references generate the implementation.
EDIT: if you can't use Java 8, then you can just define your own interface with just 1 method that returns the int. The calling just becomes longer because of the lack of support for method references:
int[] values = someobject.getMyValues(new MyIntProducer() {
public int getValue() { return someobject.getValues1(); };
}
Note that the someobject local variable will need to be made final for this to work.
You can use reflection. I don't recommend doing it this way but there is a time place for this type of thing.
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class ReflectiveGetter {
private final Object theObject;
private final String methodPattern;
private final Map<Integer, Method> methodsByIndex = new HashMap<Integer, Method>();
public ReflectiveGetter(Object theObject, String methodPattern) {
this.theObject = theObject;
this.methodPattern = methodPattern;
String patternToMatch = methodPattern + "\\d+";
for(Method m : theObject.getClass().getMethods()) {
String name = m.getName();
if(name.matches(patternToMatch)) {
m.setAccessible(true);
int i = Integer.parseInt(name.substring(methodPattern.length()));
methodsByIndex.put(i, m);
}
}
}
public int getValue(int index)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Method m = methodsByIndex.get(index);
if(m != null) {
return (Integer)m.invoke(theObject);
}
throw new NoSuchMethodException(methodPattern + index);
}
}
Usage is:
ReflectiveGetter rg = new ReflectiveGetter(theValueObject, "getValue");
System.out.println(rg.getValue(1)); // prints as if theValueObject.getValue1()
Reflection is clumsy and you should not use it if you do not know what you are doing or there are more convenient options.
For example, perhaps the value class should be using a Map to begin with.
Have a class including 30+ member variables, need to pass it to a function and then return it from the function after processing. but this function only accept fundamental data types, such as string, int.
I want to convert these member variables into an object array, pass it to the function, then convert back.
have a easy way to do these except converting one bye one?
source code like this:
class A{
int member1;
string member2;
int member3;
//other member variables
A(){
//source code
}
A(Object[] objs){
//assign objects in "objs" array to member variables
}
Object[] asArray(){
//put member variables into a object array
}
};
class B extends SuperB{
//can't modify SuperB, only can inherit it
//only accept fundamental data types, such as string, int
public Object[] run(Object... args){
A a = new A(args);
//processing
return a.asArray();
}
}
public static void main(String[] args){
A a = new A();
//other source code
Processor p = new Processor();
object[] updatedObjs = b.call("B", a.asArray());
a = new A(updatedObjs);
//other source code
};
To do what you are asking you need to do a little bit of java reflection. Loop through all the fields and add them to an array.
If you are not sure what is java reflection:
http://docs.oracle.com/javase/tutorial/reflect/
Otherwise, if you dont want to go through spinning out something on your own, you could use the immensely powerful and popular common beanutils
http://commons.apache.org/proper/commons-beanutils/
If you use the dynabean feature, you could do all this in a few lines of code:
WrapDynaBean wrapDynaBean=new WrapDynaBean(new A());
DynaProperty[] dynaProperties = wrapDynaBean.getDynaClass().getDynaProperties();
List<Object> objects=new ArrayList<>();
for (DynaProperty dynaProperty : dynaProperties) {
System.out.println(dynaProperty.getName()+" = "+wrapDynaBean.get(dynaProperty.getName()));
objects.add(wrapDynaBean.get(dynaProperty.getName()));
}
Object[] theArrayYouWant=objects.toArray(new Object[objects.size()]);
Here is the code:
public class MyClass implements Inreface1, Inreface2 {
public MyClass() {
System.out.println("name is :: " + name);
}
public static void main(String[] args) {
new MyClass();
}
}
//Interface1
public interface Inreface1 {
public String name="Name";
}
//Interface2
public interface Inreface2 {
public String name="Name";
}
Here is the error it causes:
The field name is ambiguous
What is the problem? What is ambiguous?
Your class is implementing two interfaces, and on both of them, the variable name is defined. Thus, when you call name in your class, Java is not able to determine if the variable refers to Interface1.name or Interface.name.
That's the problem in your code...
Class MyClass implements two interfaces, which both have a name variable. In the constructor of MyClass, Java doesn't know which name to pick - the one from Inreface1 or the one from Inreface2. You could tell it explicitly:
public MyClass() {
System.out.println("name is :: " + Inreface1.name);
}
Look at your code:
System.out.println("name is :: " + name);
Which "name" should the compiler use? I's ambiguous, because could be Inreface1.name or Inreface2.name.
If you clear the ambiguity by specifying one "name" the error should disappear. For instance:
System.out.println("name is :: " + Inreface1.name);
what is ambiguous ?
If two fields with the same name are inherited by an interface
because, for example, two of its direct superinterfaces declare fields
with that name, then a single ambiguous member results. Any use of
this ambiguous member will result in a compile-time error. Thus in the
example:
interface BaseColors {
int RED = 1, GREEN = 2, BLUE = 4;
}
interface RainbowColors extends BaseColors {
int YELLOW = 3, ORANGE = 5, INDIGO = 6, VIOLET = 7;
}
interface PrintColors extends BaseColors {
int YELLOW = 8, CYAN = 16, MAGENTA = 32;
}
interface LotsOfColors extends RainbowColors, PrintColors {
int FUCHSIA = 17, VERMILION = 43, CHARTREUSE = RED+90;
}
the interface LotsOfColors inherits two fields named YELLOW. This is
all right as long as the interface does not contain any reference by
simple name to the field YELLOW. (Such a reference could occur within
a variable initializer for a field.)
Even if interface PrintColors
were to give the value 3 to YELLOW rather than the value 8, a
reference to field YELLOW within interface LotsOfColors would still be
considered ambiguous.
Another point is that instance variables are not allowed in interfaces. Your public string turns into a constant : public static String name; - which you get two times. More than one constant with the same name/type is definitely ambiguous.
It looks like you're referring to the same variable.
I think the compiler does not know which value you are trying to pass. Have you tried changing the field variable?
enum icecream {
vanilla(100), strawberry(20);
int price;
icecream(int i) {
price = i;
}
}
I am a little confused as to how the enum objects are created during compilation time
I saw some examples where they mentioned it like this
public enum Flavor
{
COFFEE, VANILLA, CHOCOLATE, STRAWBERRY, RUM_RAISIN, PEACH
}
This gets translated into(during compilation)
public final class Flavor
extends java.lang.Enum
{
public static final Flavor COFFEE = new Flavor("COFFEE", 0);
public static final Flavor VANILLA = new Flavor("VANILLA", 1);
// ...
}
Link: http://www.kdgregory.com/index.php?page=java.enum
But how are the objects created when I pass a value along with the name cause to me they just look like method calls. E.x. vanilla(100) here for vanilla the price is 100 but how does it actually gets created? I am not getting it at all. Please help :(
the vanilla(100), strawberry(20) is just a java5+ notation. It gets translated during the compilation to proper object creation code:
public static final icecream vanilla = new icecream(100);
public static final icecream strawberry = new icecream(20);
BTW, java type should be CamelCased, so, icecream should be named IceCream.
Enums are read by the java compiler as constants, but ultimately, they are implemented like any other objects (that is, they are not special types, like ints/floats/arrays, but rather, a syntactic wrapper over a pure object-oriented language feature). Thus, enums have constructors which you can override, so that your static enums have more than just a name. This can be very useful, for example, if you want your enumerated values to have multiple fields.
For example, I may have an Animal enum, where each animal has a name, as well as a number of legs :
public enum Animal{
Dog(4), Baboon(2);
public int legs;
private Animal(int legs) {
legs=legs;
}
}
However, in the absence of such overriding, the compiler generate default enumeration objects, which is essentially what you have pasted.
I am doing astrophysical research. I wrote a package containing the classes Star, Band, and Datfile. I also have the enumerated type of BandName. Each star contains several Bands, each Band contains several Datfiles.
I have observational data for several galaxies. For each of these, I make a StarDatabase class (a HashMap of Stars) and a Main class.
The problem I'm having is with the enumerated type of BandName. So far, all of the data I have used has been in the I and V bands. Now I have data in J, H, and K bands. If I simply add J, H, and K to BandName, all of my loops that iterate over all of the items in BandName and do something are now broken.
Any ideas?
Edit: To sum up my problem, I want every package to have its own BandName enum that it can iterate through. But this doesn't work, because the methods in the Star package are expecting objects of type Star.BandName and I am providing objects of type IndividualPackage.BandName.
You can't inherit an enum from another enum, although you can have your enum implement an interface. The technical problem (that all enums implicitly extend java.lang.Enum, thus they can't extend another class, only implement additional interfaces) is no accident:
For the most part, extensibility of enums turns out to
be a bad idea. It is confusing that elements of an extension type are instances of
the base type and not vice versa. There is no good way to enumerate over all of the
elements of a base type and its extension. Finally, extensibility would complicate
many aspects of the design and implementation.
From Effective Java 2nd Edition, Item 34.
However, I don't fully understand your problem: haven't you used values() for iterating through your enum? Then you shouldn't worry about extending your enum with new values.
Please specify more clearly what "broken" is supposed to mean.
Update: so you need to have distinct sets of bands for different types of stars - this can be implemented using distinct enums extending a common interface, e.g.:
interface Band {
String getName();
void doStuff();
...
}
enum BandsVI implements Band {
V, I;
public String getName() { return toString(); }
public void doStuff() { /* do stuff as appropriate for these bands */ }
...
}
enum BandsJHK implements Band {
J, H, K;
public String getName() { return toString(); }
public void doStuff() { /* do stuff as appropriate for these bands */ }
...
}
And you can use these by making your Star class generic:
class Star<T extends Enum<T> & Band> {
private Class<T> bandType;
public Star(Class<T> bandType) { this.bandType = bandType; }
public void printBandNames() {
for (Band b : bandType.getEnumConstants())
System.out.println(b.getName());
}
public void doStuffOnAllBands() {
for (Band b : bandType.getEnumConstants())
b.doStuff();
}
}
...
Star<BandsVI> star1 = new Star<BandsVI>(BandsVI.class);
Star<BandsJHK> star2 = new Star<BandsJHK>(BandsJHK.class);
star1.printBandNames(); // prints V I
star2.printBandNames(); // prints J H K
This works nicely if the bands are organized into distinct groups. If there are stars with mixed band groups, however, you might prefer an alternative approach:
class Star {
private List<? extends Band> bandTypes;
public Star(List<? extends Band> bandTypes) { this.bandTypes = bandTypes; }
public void printBandNames() {
for (Band b : bandTypes)
System.out.println(b.getName());
}
...
}
...
Star star1 = new Star(Arrays.asList(BandsVI.values()));
Star star3 = new Star(Arrays.asList(new Band[]{BandsVI.V, BandsVI.I, BandsJHK.K}));
...
This allows you to set up stars with an arbitrary mix of bands. However, this way you can't use EnumSet or EnumMap on the bands.
All enums implicitly extend java.lang.Enum. Since Java does not support multiple inheritance an enum cannot extend anything else. - http://download.oracle.com/javase/tutorial/java/javaOO/enum.html
This is what I'd do (pseudo-code):
class Band
{
String name;
};
static Band J("J");
static Band K("K");
static ArrayList<Band> JK;
static ArrayList<Band> IHL;
class Star
{
Star(ArrayList<Band> bands)
}
This way you can add bands by just creating more Band objects. Each start has the list of bands it uses so it can iterate over all them.