I'm trying to make my code more polymorphic. Right now I have a superclass that has four different subclasses. I have a method that accepts the superclass as a type. I want to perform some generic actions before routing it to a different method to handle other actions. Here's what I am envisioning:
public void performSomething(Super object) {
//do some generic action each time to object
object.setSuperProperty();
//now route to appropriate method to perform specific action
doSpecific(object);
}
private void doSpecific(SubA object) { }
private void doSpecific(SubB object) { }
private void doSpecific(SubC object) { }
private void doSpecific(SubD object) { }
This way if I want to add more functionality -- by creating a new subclass or whatever -- then I just need to add another method with the correct subclass type. However, this is not possible since the compiler complains about not having a doSpecific(Super object) method. Instead, in performSomething(Super object) I have to do an ugly:
if(object instanceof SubA)
doSpecific((SubA)object);
else if(object instanceof SubB)
doSpecific((SubB)object);
...
Is there a better way to do this than having to perform all the instanceof checks? Is there a design pattern that I'm not thinking of? I know that I'll lose the compile-time type check safety, but just curious what other solutions could possibly exist.
edit: Forgot to mention this. performSomething and doSpecific are part of an unrelated class I'll call ClassA. I considered creating an abstract method in the Super class so that the subclass could properly implement it. The problem is that performSomething and doSpecific depend on roughly 8 different members of ClassA. So if I wanted to delegate the method to the subclass it would require a ton of parameters like subB.doSpecific(int, int, String, String, Object, int, long, blah, blah); which I'm not sure is better than the original instanceOf check. This would also create a tight coupling between ClassA and the Super/Sub classes I have, when doesn't seem right since I just need to read values from them.
I recommend the Command Pattern.
That means: Every of your subclasses implements a doSpecific() method. Then your initial method looks like this:
public void performSomething(Super object) {
//do some generic action each time to object
object.setSuperProperty();
//now route to appropriate method to perform specific action
object.doSpecific(...);
}
The compiler picks the method of the subclass automatically - no instanceOf check for you.
Related
I am trying to implement a Map<String, Interface> where the interface in question takes in and returns a generic value, so that different functions in the map could have different return types but still using the same interface. I'm not quite sure how it would work but the goal would be to achieve something along these lines below.
// A generic interface of some kind
public interface Action {
Object doAction(Object object);
}
// The class which implements the map
public class MyClass {
public void example() {
HashMap<String, Action> map = new HashMap<>();
// this takes in a boolean and returns the opposing value
map.put("functionOne", (boolean bool) -> !bool);
// this takes in an integer, increments it and returns it.
map.put("functionTwo", (int integer) -> integer++);
...
}
}
Obviously this pseudo code isn't right and I might be way off track but I hope it gives you an understanding of what I'm trying to achieve. Any help would be appreciated.
First of all, your interface should be declared as FunctionalInterface.
Second, since your doAction method takes Object as an argument, I see no point in returning it, unless you want to preserve the original object. You can just modify the object inside the method and make your method void. After invoking the method, your object, which was passed, will be modified. (you want to use objects like Int, Boolean and etc., which wrap up the primitive types)
But overall, this approach seems a little bit old styled and unreliable one. Since this will lead you to creating if statements to ensure you are operating the right type (As some of the colleagues have written in comments).
What I would do is to make Action generic.
#FunctionalInterface
public interface Action<T> {
T doAction(T argument);
}
Then just declare your functions like below and use them without creating a collection for them, because it will result in writing more code to ensure type-safety.
Action<Boolean> booleanFunc = (Boolean bool) -> {...};
I'm very new to Java. This is probably a stupid question--but i can't find the answer anywhere. If you wanted to declare a method that would take in an unknown object and do something with it (copy it, for example), what would be the difference between something like:
<T> T func(Class<T> cls){
//do something
}
Object func(Object o){
//do something
}
Are they comparable? Is there anything you could/would do with one of the above methods and not the other? And where does Class<?> fit in?
The difference in your code is that former func receives a Class<T> (which can be Class<?>) which means the method only receives a Class type . The latter receives any object, regardless if it's a class or another kind of object.
From Class javadoc:
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions.
Note that Class is metadata for your classes.
If your code were like this:
<T> T func(T o){
//do something
}
Object func(Object o){
//do something
}
The main difference is the return type: the former return type should be as the same type of the argument, while the latter is a generic Object. For example:
Object func(Object o){
//do something
return o.toString(); //compiles and works
}
<T> T func(T o){
//do something
return o.toString(); //does not compile
}
Class is a very specialized type of an object. Class<T> is not a replacement for any kind of object, it is rather a class descriptor. In Java, where everything is an object, also classes are objects, so there is this type - Class - which abstracts over the "class" class of objects.
Here's an example:
If you have this:
Class<Object> obj = Object.class;
func(obj);
, this doesn't mean that inside your func method you will have access to an Object instance; you will have access to a Class<Object> instance, which is he descriptor of the Object class.
So, to answer your question, you should use Object for your declared purpose.
Class and Object are 2 different things in Java. If you wanted to take any type of object, which you don't care the type of, the following is more normally seen.
Object func(Object o){
//do something
}
It is more common to declare functions with Object vs Class, since there are a few more steps for passing a class than an object.
lets hava a look at your functions
<T> T func(Class<T> cls){
//do something
}
this one takes class as parameter, and returns instance of the class,
imagine method as black box which do some magic stuff
you enter String.class and you will get "hello world"
second one
Object func(Object o){
//do something
}
takes object as parameter and returns object, so in theory, you can insert class and returns instance, but you can also put date and received String
The first function accepts a java.lang.Class (that is also an instance of an Object class, because Class extends it. You can find more information about the Class class in the javadoc: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html ).
Hence the first method can do something with an instance of Class and it does not accept all objects (note the capital letter, it is a name of a class).
The second method accepts all objects (because every object extends java.lang.Object). (Object's javadoc: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html)
So if you want to create a method that may "take in an unknown object and do something with it" you have to use the second method. You should also know that usually you do not need a method that accepts any object or unknown object and you should not create such methods if you can find another solution (because it causes the code to be harder to read).
A method that accepts Class as an argument is useful when you want to do something with the definition of a class (retrieve a list of fields, methods, constructors etc.). This webpage explains how you can use the Class class: http://docs.oracle.com/javase/tutorial/reflect/index.html
Additionally, if you want to learn more about generics you should read this tutorial: http://docs.oracle.com/javase/tutorial/java/generics/
I'm currently brushing up my Java and reading up on Generics. Since they were not treated extensively in my Java class, I'm still having some trouble wrapping my mind about it, so please keep that in mind when answering.
First of all, I'm pretty sure that what I'm trying to is not possible. However, I'd like to find out where my thinking is wrong and how I should go about achieving what I want.
What I'm trying to do is manipulating an object that implements a generic interface from another class that has no knowledge about the instantiated type. Thus, I have something like the following classes:
public interface CalledInterface<E> {
public E get() { ... }
public set(E e) { ... }
}
public class Called implements CalledInterface<String> {
...
}
Now what I want to do is:
public class Caller {
protected CalledInterface<?> c;
public Caller (CalledInterface<?> arg) {
c = arg;
}
public void run(){
// I can do this:
c.set(c.get());
// But I'd want to be able to do something like:
<?> element = c.get();
c.set(element);
}
}
What is the fundamental flaw in my thinking, if there is one? And what approach should I rather be taking?
First of all, keep in mind that generics is a compile time thing not a runtime.
Now in your Caller you defined Called c. Called is defined to implement CalledInterface<String>, so automatically, Called has the following methods generated at compile time:
String get();
void set(String e); //i assume you wanted to return void
So essentially this doesn't really make sense:
<?> element = c.get();
The Caller class isn't even aware Called is using generics internally, for it, Called just deals with strings.
UPDATE
Based on your comment, since you don't want Caller to use Called directly but use CalledInterface first thing you have to do is change the type of c to that. In this case you should not use generics, because the whole point of generics is that the same class is used in different scenarios with different types (again determined at compile time), enforcing types without having repeated code.
If I understand correctly you don't want to restrict Caller to use String, so what you have to do is change CalledInterface to not use generics, and change the methods to:
Object get();
void set(Object o);
This is how we used to do things before Generics in Java 1.4. You obviously run the risk of not having type safety, so think through whether what you want really makes design sense, because it probably does not because you have to do instanceof anyway to check the type to use the Object in a useful way (i.e. to access its methods).
If on the other hand you just change the c member (and the constructor argument of Caller) to:
CalledInterface<String> c;
Your Caller will be interacting with the CalledInterface rather than the implementation and at the same time still be type safe. So you can still pass an instance of Called and set it to c.
After your edit:
// I can do this:
c.set(c.get());
No you can't. It won't compile with c being CalledInterface<?>. (Have you even tried it?)
To do this, you can use a "capture helper":
private static <T> void helper(CalledInterface<T> c) {
c.set(c.get());
}
public void run(){
helper(c);
}
Which also solves your second problem:
private static <T> void helper(CalledInterface<T> c) {
T element = c.get();
c.set(element);
}
public void run(){
helper(c);
}
There are a few minor mistakes in your code:
protected Called c;
public Caller (CalledInterface arg) {
c = arg;
}
You are not allowed to assign arg here, because the type CalledInterface is not a subtype of Called (it is the other way around)
Also you should give type information when using CalledInterface (it is allowed to leave it out, but only for legacy purposes).
Now to the part you are wondering about. For the type Called, the compiler knows get() returns a String, if you are not interested in that, you can of course always use Object as the type of element. The compiler also knows that set() takes a String as argument, so it requires you to give one. In generics is essentially the same as using Object in a case without generics (even though it isn't allowed on the location you use it, because it doesn't make sense). This means that you would be telling the compiler to forget the type on the first line (calling get()) and to unforget it on the line below.
I have an abstract class UserdataUpdater which extends Updater
Updater has a method declaration
public abstract void processRow (Cluster cluster, IAppendOnlyData row);
Is there anyway to modify this method declaration inside UserdataUpdater to make it more specific, like
public abstract void processRow (Cluster cluster, IUserData row);
IUserData extends IAppendOnlyData, because I want classes that extends UserdataUpdater to only take IUserData
No, you can't. This would break the contract of the superclass, which says: this method accepts a IAppendOnlyData as second argument.
Remember that an instance of a subclass is also an instance of its superclass. So anyone could refer to the subclass instance as its superclass, and call the base method, passing a IAppendOnlyData, without knowing that the instance is actually a subclass instance.
Read more about the Liskov substitution principle.
The only way to do that is to make the superclass generic:
public class Updater<T extends IAppendOnlyData> {
...
public abstract void processRow(Cluster cluster, T row);
}
public class UserdataUpdater extends Updater<IUserData> {
#Override
public void processRow(Cluster cluster, IUserData row) {
...
}
}
You cannot modify a method declaration in a derived class. You can only override a superclass method if the derived class method has the exact same method signature. You must use function overloading and make a new method processRow with the new parameter types you mentioned.
In my experience, you have to use the first declaration, then in the implementation, check to make sure that:
row instanceof IUserData
of course, this is checked at runtime rather than during compile, but I don't know any other way around it. Of course, you can also just cast the row to the type IUserData, whether blindly or after checking its type (above).
Short answer: No.
You can create such a function, but because the signature is different, the compiler will see it as a different function.
If you think about it, what you are trying to do doesn't really make sense. Suppose you wrote a function that takes an Updater as a parameter and calls processRow on it with something that is not IUserData. At compile time, Java has no way to know whether the object passed in an Updater, UserdataUpdater, or some other subclass of Updater. So should it allow the call or not? What should the compiler do?
What you can do is inside UserdataUpdater.processRow, include code that checks the type passed in at runtime and throws an exception or does some other sort of error processing if it is not valid.
Assuming you have no control on the Updater class, you can't do that ... you'll have to implement that method with the exact same signature. However you can check for the type of row, inside your implementation and decide whatever processing is appropriate:
public void processRow (Cluster cluster, IAppendOnlyData row)
{
if( row instanceof IUserData )
{
// your processing here
}
else
{
// Otherwise do whatever is appropriate.
}
}
This code is invalid:
interface Foo
{
public void foo(final String string);
}
public class Bar implements Foo
{
// Error: does not override.
#Override public void foo(final Object object)
{
}
}
Because every String is obviously an Object, I would expect this code to be perfectly fine: any code that depends on giving foo() a String would stil function when foo() actually takes an Object.
It appears, though, that method signatures have to be identical to those of the methods they're overriding. Why?
What if
interface Foo
{
void foo(String string);
void foo(Object string);
}
Then which method is overridden by Bar?
'loosening' as you put it should not impact on someone expecting to use your interface defined method in a particular way, as any methods you call on that object should in theory be callable on the specified object, but Eugene's point stands, becaause there would probably be a little compiler headache to deal with in determining what method you actually intended to override if you just vaguely want to stick to the interfaces specification. Also, why whould this be desireable if you are going to stick to moving up the inheritance heirarchy, because surelely you will be able to do all you want to the thing further down the hierarchy as to 'Object' for example? Possibly casting inside your method would solve your problem? If it is possible to do what you want to do, you will also probably start treading on the polymorphism paradigm.
I think this is a classical contravariance issue. Your interface requires a string to be passed as parameter, you want an implementation that accepts an object (because, after all, strings are also objects).
The problem is that if you allowed that, then you could no longer guarantee that the parameter being required by the interface is a string or any one of its ancestors. You might just as well pass any object to your implementation and you would be breaking the contract of the interface, putting in danger the type safety and type coherence of your design.
You do have options, though:
public class Bar implements Foo
{
#Override public void foo(final String object)
{
}
public void foo(final Object object)
{
foo((String) object);
}
}
By this, you would be ensuring that object is actually a string, making possible to the type system to check that you are actually complying with the interface contract established in the method signature.
Is there a particular scenario in which you would consider your contravariance example to be requirement?
It's just the constructs of the Java programming language. The structure of Java programs will grow on you. So for now just try and adjust.