简体   繁体   中英

Passing generic types as generic method parameters in Java

First let me apologize for the terrible title, but I had no idea how to summarize this in a single sentence.

public class GenericFun {
    public class TypedStream<I extends OutputStream> {
        I input;

        public I getInput() { return input; }
        public void setInput(I input) { this.input = input; }
    }

    public abstract class GarbageWriter<I extends OutputStream> {
        public void writeGarbage(I output) throws Exception {
            output.write("Garbage".getBytes());
        }
    }

    public class GarbageWriterExecutor<I extends OutputStream> extends GarbageWriter<I> {
        public void writeTrash(TypedStream stream) throws Exception{
            this.writeGarbage(stream.getInput());       // Error
            this.writeGarbage((I)stream.getInput());    // OK
        }
    }
}

In the above code (the OutputStream is just an example) in class GarbageWriterExecutor class in the method first line causes compilation error, while the second one don't. I have two questions regarding this.

  1. Why stream.getInput() causes error, even though TypedStream.I is known to extend OutputStream ?
  2. How can I solve this issue without the ugly casting?

Because your method

public void writeTrash(TypedStream stream)

should also make sure TypedStream type is defined, like this :

 public void writeTrash(TypedStream<I> stream)

Edit : Thomas answer actually explain why

TypedStream stream will disable generic type checking and thus the compiler only knows that getInput() will return an object, hence the error.

TypedStream stream will disable generic type checking and thus the compiler only knows that getInput() will return an object, hence the error.

Try writeTrash(TypedStream<I> stream) instead.

Maybe you event want to use writeTrash(TypedStream<? extends I> stream) in order to be able to pass any TypedStream which is parameterized for I or subclasses of I .

Yet another alternative would be

public class GarbageWriterExecutor extends GarbageWriter<OutputStream> {
  public void writeTrash(TypedStream<?> stream) throws Exception{
    this.writeGarbage(stream.getInput());     
  }
}

or

public class GarbageWriterExecutor extends GarbageWriter<OutputStream> {
  public void writeTrash(TypedStream<? extends OutputStream> stream) throws Exception{
    this.writeGarbage(stream.getInput());     
  }
}

Simply use:

public class GarbageWriterExecutor<I extends OutputStream> extends GarbageWriter<I> {
    public void writeTrash(TypedStream<I> stream) throws Exception {
        this.writeGarbage(stream.getInput());
    }
}

Ie parameterize your TypedStream parameter with I .

1.Resolve this by using this code.

 public void writeTrash(TypedStream<I> stream) throws Exception{
            this.writeGarbage(stream.getInput());       
            this.writeGarbage(stream.getInput());   
        }
2.  In Generic class class name is followed by a type parameter section. If you are not    doing this then you have to do casting.

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