与嵌套泛型的集合混淆 [英] Confusion with collections of nested generics

查看:155
本文介绍了与嵌套泛型的集合混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请帮助我理解为什么 add1() add4()报告错误以及为什么 add2() add3()具体来说,如果编译器允许每个编译器都编译,请显示不必要的结果。

  class InnerTypeConfusion {
interface Animal {}
class Dog implements Animal {}
class Room< T> {
void add(T t){}
}

void add1(Room< ;? extends Animal> room){
//错误: capture#1-of?extends Animal)in the type
// Room< capture#1-of? extends Animal>不适用于
//参数(Dog)
room.add(new Dog());
}

void add2(Room< Animal> room){
room.add(new Dog());
}

class Cage< T> {}

void add3(Room< Cage< ;? extends Animal>> room){
room.add(new Cage< Dog>
}

void add4(房间< Cage< Animal>房间){
//在房间< Cage< Animal> ;>不是
//适用于参数(Cage< Dog>)
room.add(new Cage< Dog>());
}
}


解决方案

方法 void add1(Room< ;? extends Animal> room),您定义该方法接受 Room Animal 。例如,它可以房间 房间 - 甚至房间<动物> 用于持有所有类型的动物。但是,请记住,房间是在此方法调用之外创建的,您不能对房间类型进行任何假设,除非它拥有特定的动物。

  add1(new Room< Dog>()); //给方法一个狗的房间
add1(new Room< Cat>()); //给方法一个猫的空间
add1(new Room< Animal>()); //给方法一个任何动物的空间

但是一旦你进入方法,不知道已经通过了哪种类型的房间。



只有一个房间才能调用方法 add1 Room << Bird>()),因为 Bird 确实延伸 Animal 。但是在方法体中,您要向其中添加 Dog 。这就是为什么它无效,我们不能把 Dog 对象放入房间< Bird> 。它是某些种动物的房间,而不是 任何种动物。



如果您想写一种方法,将狗添加到适合添加狗的房间(但不仅限于dog-只有房间),您可以使用签名 addDogToRoom(Room< ;? super Dog> room)每个此回答。此方法可接受 Room< Animal> 以及 Room< Dog>



关于 add4 ,它是相同的,但相反。使用 Room< Cage< Animal>> 指定该方法需要特定的房间类型 - 只允许保留任何<种 Animal 。但是,您现在尝试将 Cage< Dog> 插入其中,这个笼子只允许犬。



我们假设有是设计用于容纳猫 Cage< Cat> 和用于容纳狗的笼子 Cage< Dog> 的笼子。还有通用笼,其可以包含任何种类的动物 Cage< Animal> 。这些是三种不同的笼子,它们不能互相替代,因为它们的架构和设计完全不同。




  • void method(Cage< Dog>)意味着该方法需要一个狗笼。

  • void方法(Cage< Animal>)表示该方法需要一个通用网箱。

  • void方法(Cage< ;? extends Animal>)意味着该方法需要任何种类的动物笼。



房间是另一种抽象层次 - 将它们视为一个带有笼子的房间。可以有用于存储猫笼的空间房间,用于存储狗笼的房间房间< Cage< Dog> ; ,用于存储通用网箱房间 >动物笼子房间< Cage< ;? extends Animal>> 。因此,相同的规则适用:




  • 无效的方法(Room< Cage< Dog> c $ c> - 狗笼房间

  • 无效方法(房间< Cage< Cat>>) - 猫笼

  • 无效的方法(房间< Cage< Animal>) - 动物笼子的房间

  • void method(Room< Cage< ;? extends Animal>) - 可以包含多种动物笼子的房间。例如,房间可以同时包含 Cage< Dog> Cage< Animal>


现在,在 add3(Room< Cage< ;? extends Animal> room)你要求最后一种房间,一个可以包含各种动物笼子。因此,传递给方法的房间可以包含或添加新的狗笼子 room.add(new Cage< Dog>())或任何其他类型的笼子。

但是,要调用该方法,您需要先创建一个新的通用房间(它支持所有的笼子):

 房间< Cage< ;? extends Animal>> room = new Room< Cage< ;? extends Animal>>(); 
add3(room);

给它一个狗笼子的房间不起作用:

  //这里我们创建一个只能包含狗笼的房间
房间< Cage< Dog> room = new Room< Cage< Dog>>();

//但是该方法需要一个任何种类的动物笼房间
//因此我们在编译期间遇到错误
add3(room);

如果你想写一个更灵活的方法来接受至少有狗狗笼子的房间,可能如下所示:

  void add(Room< Cage< ;? super Dog> .add(new Cage< Dog>()); 
room.add(new Cage< Animal>());
}


Please help me understand why add1() and add4() report errors and why add2() and add3() don't. Specifically, please show examples of undesired consequences if the compiler allowed each of these to compile.

class InnerTypeConfusion {
   interface Animal {}
   class Dog implements Animal {}
   class Room<T> {
      void add(T t) {}
   }

   void add1(Room<? extends Animal> room) {
      // Error: The method add(capture#1-of ? extends Animal) in the type 
      // Room<capture#1-of ? extends Animal> is not applicable for the 
      // arguments (Dog)
      room.add(new Dog());
   }

   void add2(Room<Animal> room) {
      room.add(new Dog());
   }

   class Cage<T> {}

   void add3(Room<Cage<? extends Animal>> room) {
      room.add(new Cage<Dog>());
   }

   void add4(Room<Cage<Animal>> room) {
      // The method add(Cage<Animal>) in the type Room<Cage<Animal>> is not 
      // applicable for the arguments (Cage<Dog>)
      room.add(new Cage<Dog>());
   }
}

解决方案

In the method void add1(Room<? extends Animal> room), you define that the method accepts a Room that holds an Animal. For example, it can be Room<Cat>, or Room<Dog>--even Room<Animal> for holding all types of animals. However, keep in mind that the room has been created outside this method call and you can't make any assumptions about the room type other than that it holds either a specific animal.

add1(new Room<Dog>()); // give the method a room for dogs
add1(new Room<Cat>()); // give the method a room for cats
add1(new Room<Animal>()); // give the method a room for any animal

But once you're inside the method, you can't know specifically which type of room had been passed.

It would be valid to call the method with a room for only birds add1(new Room<Bird>()), as Bird does indeed extend Animal. However in the method body, you are adding a Dog into it. That's why it's invalid, we can't put Dog objects into Room<Bird>. It is a Room of some kind of animals and not a Room of any kind of animals.

If you wanted to write a method that added a dog to a room appropriate for adding dogs (but not limited to just dog-only rooms), you'd write it with signature addDogToRoom(Room<? super Dog> room) per this answer. This method could accept Room<Animal> as well as Room<Dog> and still within the method add new dogs to the room.

As about add4, it's the same but the opposite. With Room<Cage<Animal>> you specify that the method requires a specific room type--a room that allows only cages that hold any kind of Animal. But then you are trying to put a Cage<Dog> into it, a cage that allows only dogs. Therefore, it's invalid again.

Addition regarding comment:

Let's say there are cages designed for containing cats Cage<Cat> and cages designed for containing dogs Cage<Dog>. There are also universal cages, which can contain any kind of animal Cage<Animal>. Those are three different kinds of cages, they can't be substituted for one another, as they have totally different architecture and design.

  • void method(Cage<Dog>) means that the method needs one dog cage.
  • void method(Cage<Animal>) means that the method needs one universal cage.
  • void method(Cage<? extends Animal>) means that the method needs any kind of animal cage. Either dog cage, cat cage or universal cage.

Rooms are another level of abstraction--visualize them as a rooms with cages inside. There can be a room for storing cat cages Room<Cage<Cat>>, a room for storing dog cages Room<Cage<Dog>>, a room for storing universal cages Room<Cage<Animal>> and a room for storing multiple kinds of animal cages Room<Cage<? extends Animal>>. Therefore, the same rules apply:

  • void method(Room<Cage<Dog>>) - room of dog cages
  • void method(Room<Cage<Cat>>) - room of cat cages
  • void method(Room<Cage<Animal>>) - room of animal cages
  • void method(Room<Cage<? extends Animal>>) - room that can contain multiple kinds of animal cages. E.g., the room could simultaneously contain a Cage<Dog>, and a Cage<Animal>.

Now, in add3(Room<Cage<? extends Animal>> room), you request a last kind of room, the one that can contain "all kinds of animal cages". Therefore the room passed to the method can contain or add new dog cages room.add(new Cage<Dog>()) or any other type of cage.

However, to call that method, you would need to first create a new "universal" room (which supports all cages):

Room<Cage<? extends Animal>> room = new Room<Cage<? extends Animal>>();
add3(room);

Giving it a room of dog cages will not work:

// Here we create a room that can contain only dog cages
Room<Cage<Dog>> room = new Room<Cage<Dog>>(); 

// But the method needs a "any kind of animal cage" room
// Therefore we get error during compilation
add3(room); 

If you wanted to write a more flexible method that accepts rooms capable at minimum of holding dog cages, it could look like this:

void add(Room<Cage<? super Dog>> room) {
   room.add(new Cage<Dog>());
   room.add(new Cage<Animal>());
}

这篇关于与嵌套泛型的集合混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆