+3  A: 

There is no way in Java to declare the variable the way you would like to do it.

You could use SelectableChannel for the type of the variable (since this is a supertype of both SocketChannel and DatagramChannel), and cast it to a ByteChannel whenever you need to call methods from that interface. Simple example:

class MyClass {
    private SelectableChannel channel; // either a SocketChannel or a DatagramChannel

    public int readStuff(ByteBuffer buffer) {
        // Cast it to a ByteChannel when necessary
        return ((ByteChannel) channel).read(buffer);
    }
}

(Or the other way around: declare the variable as a ByteChannel and cast to a SelectableChannel when necessary - whichever is more convenient in your case).

Jesper
I suppose I could test in the constructor and throw an `InvalidArgumentException` if the `SelectableChannel` isn't an instance of `ByteChannel`. Then I could store the object in two properties and use each one as appropriate to access the method I want.
Erick Robertson
If you get the channel from "outside" (i.e. the class doesn't have direct control over the creation of the channel), then checking it in the constructor would indeed be a good idea.
Jesper
A: 

I don't think there's a direct way to do what you want. You could define an interface and two proxy classes to expose the methods you want to use:

interface GenericChannel {
  // ... methods you want to use ...
}

class SocketWrapper implements GenericChannel {
  private final SocketChannel channel;
  public SocketWrapper(SocketChannel channel) {
    this.channel = channel;
  }
  // ... pass through calls to this.channel ...
}

class DatagramWrapper implements GenericChannel {
  private final DatagramChannel channel;
  public DatagramWrapper(DatagramChannel channel) {
    this.channel = channel;
  }
  // ... pass through calls to this.channel ...
}

or

class GenericWrapper<C extends SelectableChannel & ByteChannel> implements GenericChannel {
  private final C channel;
  public DatagramWrapper(C channel) {
    this.channel = channel;
  }
}
jacobm
+2  A: 

Fields can't be of a disjunction type, you can only use that syntax as part of a type bound in a type parameter list. You could make your class generic:

class Foo<C extends SelectableChannel & ByteChannel> {
    private C selectableByteChannel;
}

That puts a bit of extra strain on the client code, though, so you could hide this stuff behind a factory method and a private implementation class which is generic:

abstract class Foo {
    private Foo(){}
    public abstract void doSomethingWithASelectableByteChannel();
    public static <C extends SelectableChannel & ByteChannel> 
            Foo createFoo(C channel) {
        return new FooImpl<C>(channel);
    }
    private static final class FooImpl<C extends SelectableChannel & ByteChannel> 
            extends Foo 
    {
        private final C selectableByteChannel;
        private FooImpl(C channel){
            selectableByteChannel = channel;
        }
        public void doSomethingWithASelectableByteChannel(){
            // Do stuff with your selectableByteChannel
        }
    }
}
gustafc
+1  A: 

The type of a variable in a Java variable declaration must either be a definite type or the name of a type parameter. So what you are trying to express is not expressible in Java.

I'm afraid your only choices are:

  • use two variables with the respective interface types containing the same reference, or
  • use one variable with a common supertype and use typecasts.

The latter is not as bad as all that. Typecasts aren't that expensive, and the JIT compiler may be able to optimize some or all of them away.

(Incidentally, your "syntax" looks rather like the syntax for declaring a TypeParameter or TypeArgument in Java. But it is not real.)

Stephen C
Yes, I borrowed the syntax from generics, although I realize it's not real.
Erick Robertson
A: 

Doesn't casting take care of this?

public void doWhatever(SelectableChannel foo) {
    // Call a SocketChannelMethod
    ((SocketChannel)foo).someSocketChannelMethod();

    // Call a DatagramChannel method
    ((DatagramChannel)foo).someByteChannelMethod();
}

Unfortunately, calling this function with a non-SocketChannel-non-DatagramChannel SelectableChannel would be a runtime exception instead of a compile-time error. But you could make it private and have two public methods, one that accepts a SocketChannel and one that accepts a DatagramChannel. Even if your interface is more complex than that, you could have your setters setup in a similar way:

public void setChannel(SelectableChannel foo) {
    this.channel = foo;    
}
public void setChannel(SocketChannel foo) {
    setChannel((SelectableChannel) foo);
}
public void setChannel(DatagramChannel foo) {
    setChannel((SelectableChannel) foo);
}
Plutor