10 Replies Latest reply: Apr 1, 2011 8:32 PM by 848862 RSS

    How to declare class variable with generic parameters?

    848862
      I've got a class that declares a type parameter T. I know how to declare a static method, but this doesn't work for a static variable:
      public class Test< T >
      {
         /**
          * Map of String to instances of T.
          * error: '(' expected (pointing to =)
          * <identifier> expected (pointing to () )
          */
         private final static < T > Map< String, T > MAP = new HashMap< String, T >();
      
      
      
         /**
          * Get instance of type T associated with the given key.
          */
         public final static < T > T getType( String key )
         {
            return MAP.get( key );
         }
      }
      Edited by: 845859 on Mar 20, 2011 11:46 AM
        • 1. Re: How to declare class variable with generic parameters?
          796440
             private final static Map< String, T > MAP = new HashMap< String, T >();
          The < T > is already declared for the class. No need to re-declare it for the member variable.


          Nor for the method:
          public final static T getType( String key )
             {
                return MAP.get( key );
             }
          The < T > that you included there means that the method is declaring its own, independent type parameter that has nothing to do with the < T > that parameterizes the class, but just happens to have the same name.
          • 2. Re: How to declare class variable with generic parameters?
            848862
            There is no instance. It is a class variable and method.

            If I follow your example, I get the error: non-static class T cannot be referenced from a static context* for the class variable and method.

            Edited by: 845859 on Mar 20, 2011 3:00 PM

            Edited by: 845859 on Mar 20, 2011 3:09 PM

            Edited by: 845859 on Mar 20, 2011 3:21 PM
            • 3. Re: How to declare class variable with generic parameters?
              796440
              Oops. My bad.

              Variables cannot be parameterized. Only classes and methods.
              • 4. Re: How to declare class variable with generic parameters?
                848862
                OK. Then is the T in the class declaration the same same type as the T in the static method? This is what I am assuming.
                Secondly, if I remove static keyword from the MAP declaration, no problem. But I need it to be static so I can use it in the static method and have all the Ts be the same type. Looks like I have some studying ahead of me.
                • 5. Re: How to declare class variable with generic parameters?
                  EJP
                  OK. Then is the T in the class declaration the same same type as the T in the static method? This is what I am assuming.
                  If you have class Test<T> ... the T is visible inside the class scope. If you introduce another <T> it becomes different. It's just scoping.
                  Secondly, if I remove static keyword from the MAP declaration, no problem. But I need it to be static so I can use it in the static method and have all the Ts be the same type.
                  Just remove the <T> from the map declaration and the methods, unless you have a need to define another type parameter, in which case it would make more sense to use a different letter so it's clear, including to yourself.
                  • 6. Re: How to declare class variable with generic parameters?
                    796440
                    jveritas wrote:
                    OK. Then is the T in the class declaration the same same type as the T in the static method? This is what I am assuming.
                    No. If it were
                     public final static T T getType( String key )
                    instead of
                     public final static < T > T getType( String key )
                    it would be. As I stated, putting the < T > there for the method means it has its own T parameter that's completely independent of that for the class, but just happens to have the same name. Of course, you're not allowed to do
                     public final static T T getType( String key )
                    and it doesn't make any sense to do it. To wit:
                    Test<String> t1 = new Test<String>();
                    Test<Platypus> t2 = new Test<Platypus>();
                    Test.getType(); // which T is it? String or Platypus? And what if we never instantiated any Test objects at all?
                    But I need it to be static so I can use it in the static method and have all the Ts be the same type.
                    Not sure what you're saying here. What are you trying to accomplish by this?
                    • 7. Re: How to declare class variable with generic parameters?
                      848862
                      Ok. That makes sense. So let me make sure I've got it right.

                      The <T> at the class level only applies to instances of that class.

                      Since static methods have no instance, then I have to declare the generic identifier for that method (on the method signature). The identifiers for the static method and at the class level have different scope.

                      There is no mechanism to declare a generic identifier for class variables.
                      • 8. Re: How to declare class variable with generic parameters?
                        848862
                        >
                        Not sure what you're saying here. What are you trying to accomplish by this?
                        >
                        I'm trying to create a generic polymorphic Factory class that contains boilerplate code. The class declaration might look something like this.
                        public abstract class GenericFactory< T, P >
                        {
                           private final static Map< String, GenericFactory< T, P > > FACTORY_MAP =
                              new HashMap< String, GenericFactory< T, P > >();
                        
                           protected abstract T create( P param ); // template method
                        
                           public static void addFactory( String id, GenericFactory< T, P > factory )
                           {
                              FACTORY_MAP.put( id, factory ); // register the factory
                           }
                        
                           public static final T newInstance( String id, P param )
                           {
                              GenericFactory< T, P > factory = FACTORY_MAP.get( id );
                              return factory.create( param );
                           }
                        }
                        Now all I have to do is declare an abstract class that extends the GenericFactory, but with specific types

                        Classes have Factory inner classes that extend the SpecificFactory.
                        Classes register their Factory instances in a static block (when the class is loaded).
                        Finally, classes can be created by calling the SpecificFactory.newInstance( id, param )

                        I don't want to have to rewrite the registration code every time I have a different return type and parameter.

                        Edited by: jveritas on Mar 21, 2011 8:07 AM
                        • 9. Re: How to declare class variable with generic parameters?
                          jschellSomeoneStoleMyAlias
                          jveritas wrote:
                          I'm trying to create a generic polymorphic Factory class that contains boilerplate code.
                          ...
                          I don't want to have to rewrite the registration code every time I have a different return type and parameter.
                          I haven't seen a case yet where that is reasonable.

                          If you have hundreds of factories then something is wrong with your code, design and architecture.

                          If you have a factory which requires large number of a varying input types (producing different types) then something is probably wrong with your code and design.

                          A reasonable factory usage is one where you have say 20 classes to be created and you need to add a new class every 3 months. Along with additional functionality represented by the class itself and perhaps variances in usage. Thus adding about 3 lines of code to one class is trivial. Conversely if you have hundreds of classes to be created by the factory and you are adding them daily then it is likely that
                          1. Something is wrong with the architecture which requires a new class every day.
                          2. You should be using a dynamic mechanism for creation rather than static because you can't roll out a static update that often.

                          More than that the idiom that leads to factory creation is different for each factory. A factory that creates a database connection is substantially different than the one used in dynamic rules logic processing. A generic version will not be suitable for both.

                          Actualy the only case I know of where such a factory might be seem to be a 'good' idea is where someone has gotten it into their head that every class should be represented by an interface and every class created by a factory (its own factory.) And of course that is flawed.
                          • 10. Re: How to declare class variable with generic parameters?
                            848862
                            EJP pointed me the right direction. Thanks!