Java - How to deal with Abstract Static functions

Started by
8 comments, last by Starfarer42 9 years, 6 months ago
I'm coming from C++, trying to learn Java.
The issue is that Java doesn't allow overriding of static functions.
In this case, I would like each class that inherits from a parent (let's call it the Item class) to have an identifier that get by calling getId().

class Item
{
  abstract String getId();
}

class ItemA extends Item
{
  String getId()
  {
    return "ITEM_A";
  }
}
The thing is that I want to be able to call getId without having to instantiate the class, so that I can do something like this:

void foo(Item i)
{
  if(i.getId() == ItemA.getId())
  {
    //Do Something
  }
}
Java doesn't allow abstract static functions, so I'm left with defining non-abstract static functions. As a result, the above function doesn't work, because i.getId() returns the Parent object's id, not that of the child object.
Are there any ways around this, or what would be a better way of dealing with it?
Advertisement

C++ does not allow abstract static functions either. My Java is a bit rusty but adding a static function to ItemA should work (you haven't done that though). You don't really need a declaration in Item. I'm currently unsure how static functions work in Java when there is a similar named function in a superclass but my gut says it works fine.

That said, are you sure you need something like that? Java already comes with type information built in (in the form of a static variable of type java.lang.Class inside each class, including significant reflection capabilities). A lot of the reasons why you would handroll such a system in C++ can be dealt with in Java without actual extra work on your part.

Edit: come to think of it, there is no point to even make that a function. Just add a 'static final String myId = "blabliblub";' static data member to the individual classes.

If you just want to know if Item "i" is an instance of a certain derived class you can use "instanceof": http://www.java2s.com/Tutorial/Java/0060__Operators/TheinstanceofKeyword.htm

EDIT: "abstract static" doesn't make sense, if it's static it means you can access it from the class object, so Item.some_static_field should be always valid, but abstract means it's not defined there.

If you really want to stick to static functions and string ids you can do something like this I think:


class Item {
    abstract string getId();
}

class ItemA extends Item {
  static string getId() {
    return "ITEM_A";
  }

  string getId() {
    return ItemA.getId();
  }
}

void foo(Item i) {
  if (i.getId() == ItemA.getId()) {
    ...
  }
}

EDIT2: If you wan't to do different things for different Item derived classes you can do something better using function overloading.

If you have ItemA, ItemB and ItemC extending Item you add 3 "foo" functions that receive a concrete implementetion of Item as a parameter, instead of "Item", and the JRE resolves the type automatically.


class Item { ... }
class ItemA extends Item { ... }
class ItemB extends Item { ... }
class ItemC extends Item { ... }

void foo(ItemA item) { ... }
void foo(ItemB item) { ... }
void foo(ItemC item) { ... }

This also has some advantages on mantaining the code and adding more Item classes if needed, just add another "foo" function. You can even have a more complex inheritance (ItemD extends ItemA, for example) and you still only require one extra foo function.


Are there any ways around this, or what would be a better way of dealing with it?

As mentioned above, there are no abstract but static methods. Static methods are tied to a class, not an object, so they must be defined. They can't be part of a class but defined in some other child class.

However, I would skip all this, and figure out what you are trying to do. I learned C++ first, and when I first tried Java everyone said it would be so easy, but it turns out that being forced to use objects and never break the rules is hard for us C++ fans. We like to break the rules and have globals and friend functions and function pointers.

You of course can use the instanceof keyword to solve this, but usually if you're checking the concrete class type there is probably a better way to solve the problem.



void foo(Item i) {
   if( i instanceof ItemA ) {
     ...
   }
} 

I think, therefore I am. I think? - "George Carlin"
My Website: Indie Game Programming

My Twitter: https://twitter.com/indieprogram

My Book: http://amzn.com/1305076532


void foo(Item i) {
 if(i.getId() == ItemA.getId()) {
       //Do Something
 }
}

First. That wouldn't even work. You're comparing if the two strings are the same, not if they're equal.

This would work (actually I'm lying since you have static method and regular method with the same signature, but talking about string comparison here...).


void foo(Item i) {
if(i.getId().equals(ItemA.getId())) {
    //Do Something
    }
}

Also. Say that you dislike using 'instanceof' for some reason, whats preventing you from defining two methods, one static, other not static and final, that return the "id" of the class/object?


class Item {
private static final String ID = "ID_01";
static final String classId() { return ID };
final String id() { return ID };
}
 
void foo(Item i) {
  if(i.id().equals(ItemA.classId()) {
    //Do Something
  }

}

Now, thats kinda ugly. Say that you want to get away from 'instanceof' AND don't like defining two methods per class.


enum TypeID {
ID01, ID02, ID03;
}
 
class Item {
final TypeID id() { return TypeID.ID01 };
}
 
void foo(Item i) {

  switch ( i.id() ) {
  case ID01 : // Do stuff.
                      break;
  case ID02 : // Do stuff.
                      break;
  default :  System.out.println("Something be wrong yo!");
                break;
  }
}

That's beautiful switch on enum that is nicer and faster (the JIT will decide if if/else chains or jump tables are better for each particular use case!), since comparing for string equality isn't the most efficient thing in the planet precisely.

EDIT: You can even put that "id()" method in an interface and make all classes that will use such IDs implement it. You could also return plain ints as ID if that's enough for your use case, then again, enums tend to be easier to handle for restricted values (and unlike ints, you can have methods in enums).

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

Hi guys,

I think the DiegoSLTS is the 'best' solution... You must approach your problem in a more 'object oriented' way... Trying to verify if "object A is the same type of object B" looks like a 'procedural way of thinking'....

ex:

If its just a decision making based on object types so you may stick with method overload ( each object implements its own logic ) and get a 'facade' to collect the result and do the high level stuff...

If you want to decide which object you must instantiate, so try to use some kind of "Factory" pattern...

methinks : Its hard to know how to help you in this case because you just show the 'implementation part' of the problem... if you expand your explanation and tell us why are you trying to do that ( compare the object types ) maybe we could help you to come with a better approach to your problem... :D

KrinosX


methinks : Its hard to know how to help you in this case because you just show the 'implementation part' of the problem... if you expand your explanation and tell us why are you trying to do that ( compare the object types ) maybe we could help you to come with a better approach to your problem...

^^^ This.

I think, therefore I am. I think? - "George Carlin"
My Website: Indie Game Programming

My Twitter: https://twitter.com/indieprogram

My Book: http://amzn.com/1305076532

Java has build-in support for classes. Something along


Item i = new Item();
if( i.getClass() == Item.class ) {
    ...
}

would do the trick. However, whether this is a meaningful way to solve OP's problem is another question as posters have already mentioned above...

Thanks for the feedback. I'll look into instanceof, it looks like it will do what I need for the type, though I'll still face the same problem for other pieces of data (Such as UUID).


... if you expand your explanation and tell us why are you trying to do that ( compare the object types ) maybe we could help you to come with a better approach to your problem...

To be honest, I don't know quite yet, the id will probably be used as keys in a HashMap, but I haven't gotten that far yet. Partly I'm just trying to understand the language itself.



class Item {
abstract string getId();
}

class ItemA extends Item {
static string getId() {
return "ITEM_A";
}

string getId() {
return ItemA.getId();
}
}

Tried this, but I got the error "Duplicate Function"

For now I'll go with this; not as clean as I'd like, but functional


class ItemA extends Item
{
  public static final String id = "ITEM_A";
  
  @Override
  public String getId()
  {
    return id;
  }
}

then call ItemA.id or i.getId()


To be honest, I don't know quite yet, the id will probably be used as keys in a HashMap, but I haven't gotten that far yet. Partly I'm just trying to understand the language itself.

If you don't know what you'll use the ID for then why do you care about it now? Do the agile thing and don't design something you're not going to use.

Also, Class objects work just fine as keys in a HashMap so there's no need to create IDs for them. If you need an identifier that can be stored in a file then the class name is the usual approach. A simple Class.forName(..) will convert that String back into a Class object which you can then use as a key.

This topic is closed to new replies.

Advertisement