简体   繁体   中英

Paramterized class, how to reference the paramterized type of something passsed as a paramterized type

Sorry if the title sucks, not sure how to ask this question...

Lets say I have some interface Foo that takes a parameter

  public interface IFoo<Bar extends IBar>{

      public Bar generateBar();
  }

and I have another class that takes a foo object and will generate a bar object. I can define it like this.

 public class FooBar<Bar extends IBar, Foo extends IFoo<Bar>>{

      private Foo foo;

      public FooBar(Foo foo){
          this.foo = foo;
      }

      public Bar getBar(){
           this.foo.generateBar();
      }

This all works fine. However, it seems silly for me to be defining Bar as a parameter of my FooBar class. The IFoo object is going to be parametrized to take the Bar value, so I would assume I could infer the type of Bar from whatever parameter the Foo object has; thus avoiding someone having to provide two parameters every time they define a FooBar object.

Is there a way I can do this? Instead of making Bar part of the FooBar parametrized type just infer it from Foo's parameter?

edit: The answer appears to be this can't be done, as already answered. However, I'm going to leave this open for another day because I'm hoping someone may post an answer that not only if it can be done, but why it is not possible. Specifically, is this simply a use case java developers never chose to support, or is there a reason that it's not possible for the same compile time type checking that supports other parametrization checks to infer Bar type by looking at the specific IFoo type parameter. isn't IFoo parameter able to be determined as well as any parametrized type by the compiler?

If you care about the actual type parameter to IFoo , then what you have is correct -- declaring the type parameter Bar so it can be the type argument to IFoo when declaring Foo .

However, if you don't care in the code what the type parameter to IFoo is, then you can eliminate the Bar type argument and replace the type argument to IFoo with a wildcard bound.

class FooBar<Foo extends IFoo<? extends IBar>>{

Your getBar method will need to return an IBar .

public IBar getBar(){
    return this.foo.generateBar();
}

In order to have a method that creates a Bar object, you need an object of type Class<Bar> . Then you can use:

class FooBar ...{
    Class<Bar> barClass = ...;

    public Bar getBar(){
         return barClass.newInstance();
    }
}

There a various ways to get barClass. I'm not sure what design to recommend since you have given us arbitrary types Foo, Bar, etc.

A more general solution would be:

class FooBar<T> ...{
        Class<T> someClass = ...;

        public T getInstance(){
             return someClass.newInstance();
        }
    }

You would need to pass Class<Bar> as a parameter somehow.

Presumably your getBar method will return a Bar. You can't infer the type due to type erasure. You could return a bare Object for casting, but that rather defeats the purpose of generics.

Answering my own question, just to mention the approach I used in my specific situation, a work around since what I want can't be done. Honestly, it's pretty simple so I should have tried it first, but I got caught up in wondering what can be done with parametrization.

My FooBar equivalent now looks like this:

public class FooBar<Bar extends IBar>{

  private IFoo<Bar> foo;

  public FooBar(IFoo<Bar> foo){
      this.foo = foo;
  }

  public Bar getBar(){
       this.foo.generateBar();
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM