Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 安全地强制类型之间的关系_Java_Oop_Generics_Type Safety - Fatal编程技术网

Java 安全地强制类型之间的关系

Java 安全地强制类型之间的关系,java,oop,generics,type-safety,Java,Oop,Generics,Type Safety,我正在构建一个系统,用于编写关于拍摄鸟类照片的人的代码(真正的系统实际上并不是关于这一点,我在这里使用鸟类来替代我无法发布的业务逻辑)。我很难保证代码类型的安全,同时还要强制执行我想要的所有关系,避免代码变得超级混乱。这是我的 有三种鸟 public interface BirdType {} public class BlueJay implements BirdType {} public class Cardinal implements BirdType {} public class

我正在构建一个系统,用于编写关于拍摄鸟类照片的人的代码(真正的系统实际上并不是关于这一点,我在这里使用鸟类来替代我无法发布的业务逻辑)。我很难保证代码类型的安全,同时还要强制执行我想要的所有关系,避免代码变得超级混乱。这是我的

有三种鸟

public interface BirdType {}
public class BlueJay implements BirdType {}
public class Cardinal implements BirdType {}
public class Canary implements BirdType {}
对于每种类型的鸟,都有一种专门拍摄这种鸟的相机,还有一种特殊的鸟叫声吸引着这种鸟

public interface BirdCamera<BT extends BirdType> {}
public interface BirdCall<BT extends BirdType> {}
public class BlueJayCamera implements BirdCamera<BlueJay> {}
public class CardinalCamera implements BirdCamera<Cardinal> {}
public class CanaryCamera implements BirdCamera<Canary> {}
public class BlueJayCall implements BirdCall<BlueJay> {}
public class CardinalCall implements BirdCall<Cardinal> {}
public class CanaryCall implements BirdCall<Canary> {}
其中一个需要在许多方法中使用摄影师的类是NationalPark,它是我应用程序的核心类之一。下面是一个国家公园方法示例:

  public void importantMethod(PhotographerProvider photographerProvider) {
    // blah blah logic goes here
    int mostCommonBirdType = 1;
    Photographer typicalTourist = photographerProvider.get(mostCommonBirdType);
    BirdCamera cam = typicalTourist.getPhotographersCamera();
    typicalTourist.examineCamera(cam);
    // blah blah more logic here
  }
编译器不喜欢该方法的最后一行,并生成警告: 作为原始类型“birdexample.photograph”的成员,未经检查地调用“ExamiceCamera(CAM)”


我不想要这个警告,但我找不到一种方法来修复它,而不会在其他地方导致错误。。。我还想避免造成一个巨大的混乱,因为我整个程序中的每一个类都必须通过鸟类类型、摄像头和呼叫进行参数化。我如何才能做到这一点(不只是抑制/忽略警告)?

您的具体示例可以在没有警告的情况下完成,如下所示:

Photographer<?, ?, ?> typicalTourist = photographerProvider.get(mostCommonBirdType);
foo(typicalTourist);

<BT extends BirdType,
 CAM extends BirdCamera<BT>> void foo(Photographer<BT, CAM, ?> typicalTourist) {
    CAM cam = typicalTourist.getPhotographersCamera();
    typicalTourist.examineCamera(cam);
}
摄影师典型游客=摄影师提供者.get(最常见的类型);
foo(典型游客);
void foo(摄影师,典型游客){
CAM=TypicalTourism.getPicturersCamera();
典型旅游考官(cam);
}
但我要提醒你的设计。老实说,任何超过1个类型变量的操作都非常笨拙。2对于像maps这样的情况是可以接受的,但是3只是有点疯狂了——最终用类型声明填充了一半行。6(你在真实代码中所说的数字)完全进入了憎恨你自己、憎恨你的同事或两者兼而有之的领域

如果您真的需要这些泛型,请仔细考虑-如果您可以消除它们,您可能会节省大量的精力。

此外,您的
摄影师提供程序#get
方法会因其原始返回类型
摄影师
而发出编译器警告。要解决此问题,可以使用以下方法:

public class PhotographerProvider {
    public Photographer<?, ?, ?> get(int birdCode) {
        if (birdCode == 0) {
            return new BlueJayPhotographer();
        } else if (birdCode == 1) {
            return new CardinalPhotographer();
        } else if (birdCode == 2) {
            return new CanaryPhotographer();
        } else {
            throw new IllegalArgumentException("Unsupported bird code: " + birdCode);
        }
    }
}
公共类摄影师提供者{
公共摄影师获取(int birdCode){
如果(birdCode==0){
返回新的BlueJayPhotographer();
}else if(birdCode==1){
返回新的参数();
}else if(birdCode==2){
返回新的金丝雀摄影师();
}否则{
抛出新的IllegalArgumentException(“不支持的鸟代码:”+birdCode);
}
}
}

您的方法摄影师Provider.get返回一个未知类型相机和鸟类的原始摄影师:

public Photographer get(int birdCode) {
[...]
}
你可以写一些类似的东西

public   <BT extends BirdType, CAM extends BirdCamera<BT>, CAL extends BirdCall<BT>> Photographer<BT, CAM, CALL> get(int birdCode) {
[...]
}
公共摄影师获取(int-birdCode){
[...]
}
所以你得到了类型安全。问题是,至少在最新版本的java中,在调用get方法时,您可以选择任何BT类型,而编译器也可以这样做

事实上,所有这些系统并没有给你带来太多的类型安全。例如,将正确的类型实际实例化为整数。当一个人使用摄影师时,他不知道鸟的类型或相机,所以他不能真正从中受益

它提供附加值的唯一地方是给定BT类型的摄影师必须使用相机和所有给定类型的相机。。。但您也可以只使用BT作为参数化类型:

public interface Photographer<BT extends BirdType> 
{
  BirdCamera<BT> getPhotographersCamera();
  BirdCall<BT> getPhotographersBirdCall();
  void examineCamera(BirdCamera<BT> camera);
}
公共界面摄影师
{
BirdCamera GetPhotosersCamera();
BirdCall获取摄影师BirdCall();
空检摄像机(鸟瞰摄像机);
}
你得到的方法会直接得到一个BirdType:

public <BT extends BirdType> Photographer<BT> get(BT birdType) {
[...]
}
公共摄影师获取(BT birdType){
[...]
}

为什么你认为照相机和摄影师应该为不同的鸟类配备不同的类型?为什么一个蓝鸟的摄影师不能决定他有足够的蓝鸟照片,然后开始拍摄金丝雀的照片呢?相机、摄影师和鸟类都是商业逻辑的替代品,这些商业逻辑需要不同的类型,因为它们做不同的事情。如果我的比喻不完美,我很抱歉。但是他们做不同的事情这一事实需要成为这种类型的一部分吗?就像在电影中一样,鸟类都会鸣叫,相机会拍照,摄影师都有相机和最喜欢的鸟类。。。但是你可以在没有泛型的情况下完成所有这些。你在用常规多态性做不到的泛型做什么?我在这里试图获得的好处是未来的开发人员不能创建我在问题中描述的“混乱摄影师”。如果有一种不用泛型就可以完成所有这些的方法,我会很激动。那么,你如何称呼
examicecamera
方法呢?你只会用你自己的相机打电话吗?如果是这样的话,为什么要拿着相机,只是为了把它传回去——只要让它
examicecamera()
。有一个类型变量消失了,我同意你的看法。我实际上从另一个工程师那里继承了这个系统的所有权,在实际系统中,有6个类型变量,而不仅仅是3个。使用这些泛型的每个类都对整个类进行了参数化,其中许多类都有这些警告。我努力想知道是否有一种方法可以提高周围类的可读性(比如不使用这些参数),同时保持我的类型强制。但也许我应该检查一下强制执行与可读性之间的关系到底有多重要。
public Photographer get(int birdCode) {
[...]
}
public   <BT extends BirdType, CAM extends BirdCamera<BT>, CAL extends BirdCall<BT>> Photographer<BT, CAM, CALL> get(int birdCode) {
[...]
}
public interface Photographer<BT extends BirdType> 
{
  BirdCamera<BT> getPhotographersCamera();
  BirdCall<BT> getPhotographersBirdCall();
  void examineCamera(BirdCamera<BT> camera);
}
public <BT extends BirdType> Photographer<BT> get(BT birdType) {
[...]
}