I'm pretty new to java and not particularly sure how to initialize a generic type / child class from the 'base' class.
Essentially I have a bunch of classes that extend the abstract class BaseClass that need to be initialized and added to the instance Map if a key is not present.
The child class is re-used multiple times but is dynamically created based on the key parameter.
I would like to avoid reflection and don't mind changing the template if it's not 'the Java way'.
What I currently have:
public abstract class BaseClass<T> {
protected Map<String, T> instance = new HashMap<String, T>();
public T Get(String key) {
if (this.instance.containsKey(key)) {
return this.instance.get(key);
}
T item = new T(key); // Obviously this line errors but you get the idea
instance.put(key, item);
return item;
}
}
// Example top class which extends my base class
public class TopClass extends BaseClass<TopClass> {
public TopClass(String key) {
// Do unique initialization stuff
}
}
Since generic types are erased at runtime, you cannot do this. You can instead use a Class variable as follows:
public T Get(Class<T> clazz, String key) throws Exception {
if (this.instance.containsKey(key)) {
return this.instance.get(key);
}
T item = clazz.getDeclaredConstructor(String.class).newInstance(key);
instance.put(key, item);
return item;
}
I have another approach to this.
Have an interface MyInterface.
public interface MyIinterface{
public void doSomething();
}
Create an many implementations of this interface.
#Component
public class MyImplementation1 implements MyInterface{
#Override
public void doSomething(){
}
}
Use spring core jars in the dependency.
Annotate all the implementations with #Component.
#Component
public class MyImplementation1 implements MyInterface{
.
.
Have a method in some Util class that will get you the implementation based on a string key.
public static MyInterface getImplementation(String name){
ApplicationContext context;
return context.getBeanByName(name);
}
Related
Item is an abstract class with subclasses Potion, Weapon. Shield.
The useItem() method is an abstract method defined in each of Item's subclasses
get_item return object of class Item
The getItem method returns an object of class subclass of Item
case "use":
if (hero.get_item() instanceof Potion) {
hero.<Potion>getItem(Potion.class).useItem();
} else if (hero.get_item() instanceof Weapon) {
hero.<Weapon>getItem(Weapon.class).useItem();
} else if (hero.get_item() instanceof Shield) {
hero.<Shield>getItem(Shield.class).useItem();
}
break;
is there a way I can condense this code into something like...
Class itemclass = hero.getItem().getClass();
hero.<itemclass>getItem(itemclass.class).useItem();
The code above does not compile but I am looking for something like it. I am trying to avoid if else statements because there are many more items.
Edit:
The reason i did not initially use hero.get_item().useItem() was because
i was trying to do
Weapon sword = hero.get_item();
so i could access methods such as sword.getDamage()
However, I would get the error error: incompatible types: Item cannot be converted to a Weapon
so that is why I created (help from #marsouf) hero.<Weapon>getItem(Weapon.class)
Today i created the method abstract public void useItem();
and since it is a method of the Item class I am able to use hero.getItem().useItem()
It would make more sense to haven an Interface for Item with the method useItem().
Then have an implementation for Potion, Shield etc.
This way you avoid having to cast and make it more complex than it is.
useItem() does not belong in the abstract class if its not giving any functionality, and less needed now Interfaces can have default methods.
My idea is to use the magic of generics without not cast
public class Character<T extends Item> {
private T item;
public Character (T item){
this.item = item;
}
public T getItem(){
return item;
}
}
When you create a hero:
Character hero = new Character<Weapon>(new Weapon("sword"));
after this you can use it like:
hero.getItem().useItem(); // abstract method from Item class
hero.getItem().getPower(); //where power is a Weapon method
Character class you can extend like:
public class Hero<T> extend Character<T>{
//add there your custom methods or override Character methods
}
Difficult to answer without seeing the contracts being involved (hero.get_item(), hero.getItem()).
But have you tried:
Class<?> itemClass = hero.get_item().getClass();
hero.getItem(itemClass).useIt();
?
Assuming you are set on using generics the way you're using them... here's how.
First, I've created some extremely simple classes to mimic your structure from this and your other question: a class which uses instances of a particular abstract class.
public class ACOne extends AbstractClass
{
#Override
public void use(){System.out.println("Used item ACOne!");}
}
public class ACTwo extends AbstractClass
{
#Override
public void use(){System.out.println("Used item ACTwo!");}
}
public abstract class AbstractClass
{
public abstract void use();
}
public class UserClass
{
private AbstractClass item;
public UserClass (AbstractClass item)
{
this.item = item;
}
public Class<? extends AbstractClass> getItemClass()
{
return item.getClass();
}
public <T extends AbstractClass> T getItem (Class <? extends T> targetType)
{
return targetType.cast(this.item);
}
public void setItem (AbstractClass item)
{
this.item = item;
}
}
public class CastingSubclasses
{
public void testCastingSubclasses()
{
UserClass user = new UserClass(new ACOne());
user.setItem(new ACTwo());
user.getItem(user.getItemClass()).use();
}
}
This program, when run, prints out "Used item ACTwo!"
The crux here is in the getItemClass method on the UserClass (your Character class).
Also, it's common to call these methods which get the Class object 'getClazz', since there is a default method 'getClass' that you don't want to override.
Here it made sense to just keep the spelling.
Is there a way to setup the following construct in JAVA:
having a common interface or base class
having a static public field declared by the common interface
each model implementing the common interface should have its own static field (not one shared instance for all models)
Detailed explanation:
I'm working with ORMLite and I need to refresh the ForeignCollections of my models after deserialization. For doing this I need to have a reference to my DAO from the models, which I don't want to.
So, I came up with the following concept:
keep a static field in each of the models of the following Interface:
public interface SerializableObserver {
void onAfterDeserialization(Object object);
}
in my implementation of private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException after reading in all ivars i'am calling the onAfterDeserialization-Method of the static field i'am holding in the model.
In the Dao, I'm setting the static field of the model. So when the deserialization is finished, a method in my Dao is called. Where i can finally refresh the ForeignCollection so it's still valid after deserialization.
So what I'm looking for is some sort of way to make this whole approach a bit more generic so, I don't have to implement this behavior for all of my 20 Models.
And finally, this is going to be an Android-App. so no fancy Java-8 things.
I would use another class that maps Model classes to SerializableObserver implementations.
For example,
DeserializerMap:
public enum DeserializerMap {
INSTANCE;
private Map<Class<? extends Model>, SerializableObserver> modelObserverMap = new HashMap<>();
public void registerSerializableObserver(Class<? extends Model> modelClass, SerializableObserver serializableObserver) {
modelObserverMap.put( modelClass, serializableObserver );
}
public void deregisterSerializableObserver(Class<? extends Model> modelClass) {
modelObserverMap.remove( modelClass );
}
public SerializableObserver getSerializableObserver(Class<? extends Model> modelClass){
return modelObserverMap.get( modelClass );
}
}
Model class:
public class ModelClass implements Model{
private int id;
public ModelClass(int id) {
this.id = id;
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
ois.defaultReadObject();
DeserializerMap.INSTANCE.getSerializableObserver( this.getClass() ).
onAfterDeserialization( this );
}
}
The "Model" interface just extends Serializable and is used in DeserializerMap, but you can just get rid of the interface and use Class<? extends Object> instead of Class<? extends Model> in DeserializerMap,
Model:
public interface Model extends Serializable{
}
DAO Class:
public class DAOClass {
public DAOClass(){
SerializableObserver serializableObserver = new SerializableObserver() {
#Override
public void onAfterDeserialization(Object object) {
System.out.println("After deserialization");
anotherMethod();
}
};
DeserializerMap.INSTANCE.registerSerializableObserver( ModelClass.class, serializableObserver );
}
public void anotherMethod(){
System.out.println("another method");
}
}
if you don't want to do anything additional than just call DAOClass method then you can map ModelClass with DAOClass classes, but I would recommend using DAO just for communicating with your persistence system and register mappings in your main class and not in DAOClass constructor.
Without understanding the details I can offer the following:
Use an Interface to define commonly required behaviour and then a generic abstract base class to define a common structure is something you should consider.
I have an abstract class (Candy) with a generic collection (Flavors). Candy has a factory method to produce concrete instances of itself. It also has methods to get an instance of the generic flavor appropriate to the concrete candy and to add the flavor to its collection.
I know the getter is working, because if I cast the flavor from the CandyStore, the methods unique to the concrete flavor work fine. But the very last line, the addFlavor(flavor), errs (Eclipse) on me. The error is: "The method addFlavor(capture#5-of ? extends IFlavor) in the type ICandy is not applicable for the arguments (IFlavor)." Can anyone explain what is going on?
Interface:
public interface ICandy <Flavor extends IFlavor> {
public Flavor getFlavorForCandy();
public void addFlavor(Flavor flavor);
}
Abstract Class:
public abstract class AbstractCandy<Flavor extends IFlavor> implements ICandy<Flavor> {
public static ICandy<? extends IFlavor> buildCandy(String flavor){
if(flavor.equals("Jolly Rancher")
return new JolRanchCandy();
}
public Flavor getFlavorForCandy() {
return (Flavor) new CandyFlavor();
}
public void addFlavor(Flavor flavor) {
... //implemented
}
}
Concrete Class:
public class JolRanchCandy extends AbstractCandy<JolRanchFlavor> {
... //implemented
}
Used By:
public class CandyStore {
private ICandy<? extends IFlavor> candy;
private IFlavor flavor;
public void createCandy() {
candy = AbstractCandy.buildCandy("Jolly Rancher");
flavor = candy.getFlavorForCandy(); //returns a JolRanchFlavor
flavor.setName("Apple"); //etc for creating flavor
candy.addFlavor(flavor); //no luck
}
}
Edit: For clarity, JolRanchFlavor extends CandyFlavor implements IJolRanchFlavor and CandyFlavor implements IFlavor.
Try this...
public <T extends IFlavor> void createCandy() {
ICandy<T> candy= (ICandy<T>) AbstractCandy.buildCandy("Jolly Rancher");
T flavor= candy.getFlavorForCandy();
flavor.setName("Apple");
candy.addFlavor(flavor);
}
The problem is the declaration of private ICandy<? extends IFlavor> candy. Since the type of the candy is unknown and therefore ? the compiler doesn't know exactly what kind of IFlavor addFlavor should take. You just need to define a generic holder for the IFlavor type so that it is preserved.
It looks like this is impossible to do, but does anyone have a clever way around this problem?
public class SomeClassIterableWrapper<S, T extends SomeClass & S> implements Iterable<S>
Where S is supposed to be an interface of some unknown type and SomeClass is a 2D array with a row index, similar in functionality to a bidirectional JDBC resultset. Subclasses of SomeClass have custom getters and setters for each column. I want to be able to iterate through this structure like I would a List. I want to implement a common interface between my SomeClass and Bean to have access to the getters and setters. As such S needs to be that interface. However the declaration I provided does not work. Is there a way to work around this?
edit to show my desired implementation:
public class SomeClassIterableWrapper<S, T extends SomeClass & S> implements Iterable<S>{
T object;
public SomeClassWrapper(T object){
this.object = object;
}
#Override
public Iterator<S> iterator() {
object.setIndex(-1);
return new SomeClassIterator<S>();
}
private class SomeClassIterator<S> implements Iterator<S> {
#Override
public boolean hasNext() {
return object.index() < object.rowSize() - 1;
}
#Override
public S next() {
object.next();
//safe because only interface methods allowed, can't further manipulate index
return object;
}
#Override
public void remove() {
object.deleteRow();
}
}
Can't you parameterize SomeClass with S? Then you could have
public class SomeClassIterableWrapper<S, T extends SomeClass<S>>
implements Iterable<S>{
I think the S in extends SomeClass & S
public class SomeClassIterableWrapper
has to be a definite class because in this context,
S has to be a class that is extending something.
Is there a way you can narrow down what the
potential classes that are used in place of S are?
You could use multiple ampersands if you have multiple
classes that T should extend
I confess that I don't fully comprehend the problem but this is what I suggest:
Create an interface of S. It contains one method ad it returns the S object.
public interface SWrapper<S> {
S getS();
}
Then create an implementation:
public class SImpl implements SWrapper<SImpl> {
#Override
public SImpl getS() {
return this;
}
}
You can now create:
public class SomeClass<T extends SomeClass & SWrapper<T>> {
private final T object;
public SomeClass(T object) {
this.object = object;
}
}
You will have to modify your usage a bit but perhaps it works.
I have the concept of NodeTypes and Nodes. A NodeType is a bunch of meta-data which you can create Node instances from (a lot like the whole Class / Object relationship).
I have various NodeType implementations and various Node implementations.
In my AbstractNodeType (top level for NodeTypes) I have ab abstract createInstance() method that will, once implemented by the subclass, creates the correct Node instance:
public abstract class AbstractNodeType {
// ..
public abstract <T extends AbstractNode> T createInstance();
}
In my NodeType implementations I implement the method like this:
public class ThingType {
// ..
public Thing createInstance() {
return new Thing(/* .. */);
}
}
// FYI
public class Thing extends AbstractNode { /* .. */ }
This is all well and good, but public Thing createInstance() creates a warning about type safety. Specifically:
Type safety: The return type Thing for
createInstance() from the type
ThingType needs unchecked conversion
to conform to T from the type
AbstractNodeType
What am I doing wrong to cause such a warning?
How can I re-factor my code to fix this?
#SuppressWarnings("unchecked") is not good, I wish to fix this by coding it correctly, not ignoring the problem!
You can just replace <T extends AbstractNode> T with AbstractNode thanks to the magic of covariant returns. Java 5 added support, but it didn't receive the pub it deserved.
Two ways:
(a) Don't use generics. It's probably not necessary in this case. (Although that depends on the code you havn't shown.)
(b) Generify AbstractNodeType as follows:
public abstract class AbstractNodeType<T extends AbstractNode> {
public abstract T createInstance();
}
public class ThingType<Thing> {
public Thing createInstance() {
return new Thing(...);
}
}
Something like that should work:
interface Node{
}
interface NodeType<T extends Node>{
T createInstance();
}
class Thing implements Node{}
class ThingType implements NodeType<Thing>{
public Thing createInstance() {
return new Thing();
}
}
class UberThing extends Thing{}
class UberThingType extends ThingType{
#Override
public UberThing createInstance() {
return new UberThing();
}
}