3

I have a superclass that I would like to forward a static method called getInstance() to all subclasses.

When creating an instance of a subclass, I then register the instance in the superclass (perhaps using a hashtable, where the key is based on getClass()). Then, I wish to use the aforementioned static method ( getInstance ) where the superclass method will return the instance of the correct type.

For example, I have a superclass A, and a subclass B extends A. I want to write a static method A.getInstance(); when called from B (B.getInstance()), I would like it to return the instance of B that I stored earlier.

Its kinda hard to explain, but I am going to be using this superclass a lot, and I would rather not code a getInstance method into every single subclass.

How would I go about doing something like this?

edit: I just realized that my question may be misconstrued as creating a NEW instance of the object. I have already created the instance, and i wish to get the existing instance of the class

CorrieKay
  • 181
  • 1
  • 4
  • 15

6 Answers6

3

As many others have noted in the comments, what you are trying to do is not possible with static methods. Also, you should try to avoid static methods whenever possible because they can result in a testing and maintanance nightmare (*).

You named your method "getInstance", so I guess what you want to do is a mix of Factory- and Singleton patterns. Here is some information to get you started about these patterns:

Singleton: http://en.wikipedia.org/wiki/Singleton_pattern
Factory Method: http://en.wikipedia.org/wiki/Factory_method_pattern
Abstract Factory: http://en.wikipedia.org/wiki/Abstract_factory

Both should not be coded by hand in these days (*) - Have a look at a good "Dependency Injection" (DI) container like Google Guice or Spring. I am not 100% sure what exactly you want to achieve, but it looks like a DI container will do it for you.

Edit: This is a response to an edit of the question. You want to receive a cached instance of the sub classes. In this case, I would still advise against static methods. You could create a singleton instance of a "BCache" class (using a DI container or programming it by hand), and then use this cache object to look up your registered objects. Using Guice as a DI container, it could look like this (warning, untested):

@Singleton
public class BCache {
    private Map<Class<? extends B>, B> cache = ...;

    public <T> T getInstance(Class<? extends T> type) {
        return (T) cache.get(type);
    }
}

I still think it would be possible to get rid of the cache class completely using a DI container, though. Again, this is untested code, using Guice, but it could look like this:

@Singleton
public class A extends B {
    public A() {
        //I am not sure if you need to register in this case, because your
        //DI container keeps track of the singleton instances.
        super.register(this);
    }
}

public class SomeClassUsingA {
    @Inject private A a;
}

(*) Note that "all generalizations are wrong", that is, in some projects it might make sense, but in most it will not.

David Tanzer
  • 2,732
  • 18
  • 30
  • 2
    Using a DI Framework will not improve the fact, that the OP is not aware of the "Factory" pattern. He should learn about that and patterns in general and then deside if a DI Framework is overkill. Just my humble opinion. – Fildor Jan 16 '13 at 08:08
  • @Fildor you are right, I have added links to the pattern descriptions at wikipedia as a starting point. – David Tanzer Jan 16 '13 at 08:19
  • Even with the edit above, (that i am not trying to CREATE an instance) are the factory links relevant? – CorrieKay Jan 16 '13 at 08:42
  • @CoralineKay What you describe in you comments above is a singleton pattern for your classes B and C, which happen to inherit A. That is not a factory and a factory is probably not what you want. – Fildor Jan 16 '13 at 09:04
  • Thank you. Then im assuming the best/only way to solve this issue is to write a getInstance method for each class then? – CorrieKay Jan 16 '13 at 09:06
  • @DavidTanzer why are static methods a maintenance nightmare? – Eloff Apr 05 '14 at 19:19
  • 1
    @Eloff Most of the time, they are really hard to test. With static methods, you create a dependency that you cannot easily replace (for testing or other purposes). So you are tightly coupling the caller and callee. This will often bite you when you want to re-use the caller. An exception would be pure utility methods: For something like "Strings.notEmpty(str)" or "Arguments.notNull(argumentValue, argumentName)", a static method is probably OK. – David Tanzer Apr 08 '14 at 04:01
  • @Eloff if you want a more elaborate answer, feel free to ask a stack overflow question and tell me about it (for example on twitter: @dtanzer), then I will try to provide a more detailed answer and also show you some alternatives. – David Tanzer Apr 08 '14 at 04:05
1

You can't do exactly what you want with the static methods, in good OOP way. You can can do something with the reflection or bunch of if .. else if.

You however, should use some well defined design patterns like Abstract fectory or Factory method. This is the way you should go, like someone said "Don't invent warm water".

partlov
  • 13,789
  • 6
  • 63
  • 82
1

You can always assign a subClass instance to a superClass reference. Therefore your superClass's static methods can set or get a subClass instance. But make sure to cast the returned instance before using.

public class A {
    private static A a;

    /**
     * @param a the a to set
     */
    public static void setA(A a) {
        A.a = a;
    }

    /**
     * @return the a
     */
    public static A getA() {
        return a;
    }


public class B extends A {
    private int index = 0;

    /**
     * @param index the index to set
     */
    public void setIndex(int index) {
        this.index = index;
    }

    /**
     * @return the index
     */
    public int getIndex() {
        return index;
    }

Usage:

public static void main(String[] args) throws Exception {
        B b = new B();
        A.setA(b);

    B c = (B) A.getA();
    System.out.println(c.getIndex());
}
spathirana
  • 155
  • 10
0

Change form getInstance() to getInstance(String class) in the superclass:

public static A getInstance(String class){
if(class.equals("A")){
RegisterObject(...);//User defined method
return new A(...);
}
else if(class.equals("B")){
RegisterObject(...);//User defined method
return  new B(...);
}
else if(class.equals("C")){
RegisterObject(...);//User defined method
return  new C(...);
}
//... and so on

}
Govind Balaji
  • 639
  • 6
  • 17
0

Static methods are cannot know which class is used to invoke them. If for example you have class A and B that extends A and static getInstance() implemented in A there is no difference whether you invoke getInstance() using A or B. Moreover attempt to call B.getIntance() will produce compilation warning (at least in Eclipse).

However you can pass the class as a parameter of getInstance():

public class A {
    public static <T extends A> T getInstance(Class<T> clazz) {
        return clazz.newInstance(); // I do not catch exceptions here: do it yourself
    }
}

public class B extends A {
}

...............
B b = A.getInstance(B.class);
AlexR
  • 114,158
  • 16
  • 130
  • 208
0

You can do like this way,

 class A{
     public static A getInstance(){
     return new A();
   }

  @Override
  public String toString() {
   return "inside A";
   }
 }

 class B extends A{
public static A getInstance(){
  return new B();
 }

   @Override
   public String toString() {
      return "inside B";
   }
 }

inside main :

   public static void main(String[] args) {
  A a1 = A.getInstance();
  A a2 = B.getInstance();
      System.out.println(a1.toString());
  System.out.println(a2.toString());
   }
Amol Fasale
  • 942
  • 1
  • 10
  • 32