简体   繁体   English

如何声明包含实现接口的类的子类的变量?

[英]How do I declare a variable that contains a subclass of a class which implements an interface?

I want to declare a variable which holds a class which implements a specific interface. 我想声明一个包含实现特定接口的类的变量。 Specifically, I'm trying to store a SocketChannel and a DatagramChannel in the same property so I can use them interchangeably. 具体来说,我正在尝试将SocketChannelDatagramChannel存储在同一属性中,以便我可以互换使用它们。 Both of these classes extend SelectableChannel and also implement ByteChannel , and I wish to call methods from both. 这两个类都扩展了SelectableChannel并实现了ByteChannel ,我希望从两者中调用方法。 I do not want to store this in two separate variables, because I they need to be the same object. 我不想将它存储在两个单独的变量中,因为我需要将它们作为同一个对象。 I want to pass this object in one variable to the constructor. 我想在一个变量中将此对象传递给构造函数。

Is it even possible to do this? 甚至可以这样做吗? If not, what are the common workarounds which still support this type of model? 如果没有,那么仍然支持这种模型的常见解决方法是什么? For clarity, here are the (incorrect) declarations which could describe what I'm trying to do, were they valid: 为清楚起见,这里是(不正确的)声明可以描述我正在尝试做什么,如果它们有效:

private SelectableChannel & ByteChannel byteChannel;
private SelectableChannel implements ByteChannel byteChannel;
private ? extends SelectableChannel implements ByteChannel byteChannel;

Please Note: 请注意:

I am not looking for other ways to handle networking which avoids this problem, or other ways to implement networking. 我不是在寻找其他方法来处理避免此问题的网络,或其他实现网络的方法。 This question is about declaring a variable to hold a subclass of a class which also implements a specific interface. 这个问题是关于声明一个变量来保存一个类的子类,该类也实现了一个特定的接口。 I only gave the specifics so that you would know that I cannot create a new interface or subclass because in this case all of the classes involved are part of the java.nio package. 我只给出了详细信息,以便您知道我无法创建新的接口或子类,因为在这种情况下,所涉及的所有类都是java.nio包的一部分。

There is no way in Java to declare the variable the way you would like to do it. Java中没有办法按照您希望的方式声明变量。

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. 您可以使用SelectableChannel作为变量的类型(因为这是SocketChannelDatagramChannel的超类型),并在需要从该接口调用方法时将其ByteChannel转换为ByteChannel 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). (或者ByteChannel :将变量声明为ByteChannel并在必要时ByteChannel转换为SelectableChannel - 在您的情况下更方便)。

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
        }
    }
}

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;
  }
}

The type of a variable in a Java variable declaration must either be a definite type or the name of a type parameter. Java变量声明中的变量类型必须是明确类型或类型参数的名称。 So what you are trying to express is not expressible in Java. 所以你想表达的东西在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. 类型转换并不昂贵,JIT编译器可能能够优化其中的部分或全部。

(Incidentally, your "syntax" looks rather like the syntax for declaring a TypeParameter or TypeArgument in Java. But it is not real.) (顺便说一句,你的“语法”看起来很像在Java中声明TypeParameter或TypeArgument的语法。但它并不真实。)

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. 不幸的是,使用非SocketChannel-non-DatagramChannel SelectableChannel调用此函数将是运行时异常而不是编译时错误。 But you could make it private and have two public methods, one that accepts a SocketChannel and one that accepts a DatagramChannel. 但是你可以将它设为私有,并有两个公共方法,一个接受SocketChannel,另一个接受DatagramChannel。 Even if your interface is more complex than that, you could have your setters setup in a similar way: 即使您的界面比这更复杂,您也可以以类似的方式设置您的setter:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我如何声明一个实现了可限制类类型的接口的类? - How do I declare a class that implements an interface that constrains the type of a class? Java:如何声明一个变量实现了一个接口? - Java: How to declare that a variable implements an interface? 如何声明接口类型的变量,然后将实现接口的 Class 的 object 分配给该变量,以及如何测试? - How to declare a variable of type Interface and then assign to the variable an object of a Class that implements the Interface, and how to test this? 如何从使用反射实现接口的类的字段中获取值? - How do i get a values from fields of a class which implements interface using reflection? 如何使用实现接口的抽象 class 内部的 return 语句创建一个方法,该接口被子类继承? - How to make a method with a return statement that is inside an abstract class which implements an interface get inherited by a subclass? 如何在该接口类型的对象上调用实现接口的类中的方法? - How can I call a method which is in a class which implements an Interface, on an object of that interface's type? 用 asm 如何声明一个非泛型 class 实现泛型接口 - With asm how to declare a non-generic class implements generic interface 为什么我不能从Scala访问实现Java接口的类中声明的变量? - Why can't I access a variable declared in a class, which implements a Java interface, from Scala? 检查子类是否在父类中实现接口? - Check if subclass implements an interface in parent class? 如何通过接口从实现接口的类调用方法? - How to call a method from a class which implements an interface, through the interface?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM