@@ -850,6 +850,184 @@ Manx=7, Rodent=5, Mutt=3, Dog=6, Pet=20, Hamster=1}
850850
851851` instanceof ` 有一个严格的限制:只可以将它与命名类型进行比较,而不能与 ` Class ` 对象作比较。在前面的例子中,你可能会觉得写出一大堆 ` instanceof ` 表达式很乏味,事实也是如此。但是,也没有办法让 ` instanceof ` 聪明起来,让它能够自动地创建一个 ` Class ` 对象的数组,然后将目标与这个数组中的对象逐一进行比较(稍后会看到一种替代方案)。其实这并不是那么大的限制,如果你在程序中写了大量的 ` instanceof ` ,那就说明你的设计可能存在瑕疵。
852852
853+ ## 使用类字面量
854+
855+ 如果我们使用类字面量重新实现 ` PetCreator ` 类的话,其结果在很多方面都会更清晰:
856+
857+
858+ ``` java
859+ // typeinfo/pets/LiteralPetCreator.java
860+ // 使用类字面量
861+ // {java typeinfo.pets.LiteralPetCreator}
862+ package typeinfo.pets ;
863+ import java.util.* ;
864+
865+ public class LiteralPetCreator extends PetCreator {
866+ // try 代码块不再需要
867+ @SuppressWarnings (" unchecked" )
868+ public static
869+ final List<Class<? extends Pet > > ALL_TYPES =
870+ Collections . unmodifiableList(Arrays . asList(
871+ Pet . class, Dog . class, Cat . class, Rodent . class,
872+ Mutt . class, Pug . class, EgyptianMau . class,
873+ Manx . class, Cymric . class, Rat . class,
874+ Mouse . class, Hamster . class));
875+ // 用于随机创建的类型:
876+ private static final
877+ List<Class<? extends Pet > > TYPES =
878+ ALL_TYPES.subList (ALL_TYPES .indexOf (Mutt .class ),
879+ ALL_TYPES.size ());
880+ @Override
881+ public List<Class<? extends Pet > > types () {
882+ return TYPES ;
883+ }
884+ public static void main (String [] args ) {
885+ System . out. println(TYPES );
886+ }
887+ }
888+ /* 输出:
889+ [class typeinfo.pets.Mutt, class typeinfo.pets.Pug,
890+ class typeinfo.pets.EgyptianMau, class
891+ typeinfo.pets.Manx, class typeinfo.pets.Cymric, class
892+ typeinfo.pets.Rat, class typeinfo.pets.Mouse, class
893+ typeinfo.pets.Hamster]
894+ */
895+ ```
896+
897+ 在即将到来的 ` PetCount3.java ` 示例中,我们用所有 ` Pet ` 类型预先加载一个 ` Map ` (不仅仅是随机生成的),因此 ` ALL_TYPES ` 类型的列表是必要的。` types ` 列表是 ` ALL_TYPES ` 类型(使用 ` List.subList() ` 创建)的一部分,它包含精确的宠物类型,因此用于随机生成 ` Pet ` 。
898+
899+ 这次,` types ` 的创建没有被 ` try ` 块包围,因为它是在编译时计算的,因此不会引发任何异常,不像 ` Class.forName() ` 。
900+
901+ 我们现在在 ` typeinfo.pets ` 库中有两个 ` PetCreator ` 的实现。为了提供第二个作为默认实现,我们可以创建一个使用 ` LiteralPetCreator ` 的 * 外观模式* :
902+
903+ We now have two implementations of ` PetCreator ` in the ` typeinfo.pets ` library. To provide the second one as a default implementation, we can create a * Façade* that utilizes ` LiteralPetCreator ` :
904+
905+ ``` java
906+ // typeinfo/pets/Pets.java
907+ // Facade to produce a default PetCreator
908+ package typeinfo.pets ;
909+ import java.util.* ;
910+ import java.util.stream.* ;
911+
912+ public class Pets {
913+ public static final PetCreator CREATOR =
914+ new LiteralPetCreator ();
915+
916+ public static Pet get () {
917+ return CREATOR . get();
918+ }
919+
920+ public static Pet [] array (int size ) {
921+ Pet [] result = new Pet [size];
922+ for (int i = 0 ; i < size; i++ )
923+ result[i] = CREATOR . get();
924+ return result;
925+ }
926+
927+ public static List<Pet > list (int size ) {
928+ List<Pet > result = new ArrayList<> ();
929+ Collections . addAll(result, array(size));
930+ return result;
931+ }
932+
933+ public static Stream<Pet > stream () {
934+ return Stream . generate(CREATOR );
935+ }
936+ }
937+ ```
938+
939+ 这还提供了对 ` get() ` 、` array() ` 和 ` list() ` 的间接调用,以及生成 ` Stream<Pet> ` 的新方法。
940+
941+ 因为 ` PetCount.countPets() ` 采用了 ` PetCreator ` 参数,所以我们可以很容易地测试 ` LiteralPetCreator ` (通过上面的外观模式):
942+
943+ ``` java
944+ // typeinfo/PetCount2.java
945+ import typeinfo.pets.* ;
946+
947+ public class PetCount2 {
948+ public static void main (String [] args ) {
949+ PetCount . countPets(Pets . CREATOR );
950+ }
951+ }
952+ /* 输出:
953+ Rat Manx Cymric Mutt Pug Cymric Pug Manx Cymric Rat
954+ EgyptianMau Hamster EgyptianMau Mutt Mutt Cymric Mouse
955+ Pug Mouse Cymric
956+ {EgyptianMau=2, Pug=3, Rat=2, Cymric=5, Mouse=2, Cat=9,
957+ Manx=7, Rodent=5, Mutt=3, Dog=6, Pet=20, Hamster=1}
958+ */
959+ ```
960+
961+ 输出与 ` PetCount.java ` 的输出相同。
962+
963+ ## 一个动态 ` instanceof ` 函数
964+
965+ ` Class.isInstance() ` 方法提供了一种动态测试对象类型的方法。因此,所有这些繁琐的 ` instanceof ` 语句都可以从 ` PetCount.java ` 中删除:
966+
967+ ``` java
968+ // typeinfo/PetCount3.java
969+ // 使用 isInstance() 方法
970+ import java.util.* ;
971+ import java.util.stream.* ;
972+ import onjava.* ;
973+ import typeinfo.pets.* ;
974+
975+ public class PetCount3 {
976+ static class Counter extends
977+ LinkedHashMap<Class<? extends Pet > , Integer > {
978+
979+ Counter () {
980+ super (LiteralPetCreator . ALL_TYPES. stream()
981+ .map(lpc - > Pair . make(lpc, 0 ))
982+ .collect(
983+ Collectors . toMap(Pair :: key, Pair :: value)));
984+ }
985+
986+ public void count (Pet pet ) {
987+ // Class.isInstance() 替换 instanceof:
988+ entrySet(). stream()
989+ .filter(pair - > pair. getKey(). isInstance(pet))
990+ .forEach(pair - >
991+ put(pair. getKey(), pair. getValue() + 1 ));
992+ }
993+
994+ @Override
995+ public String toString () {
996+ String result = entrySet(). stream()
997+ .map(pair - > String . format(" %s=%s" ,
998+ pair. getKey(). getSimpleName(),
999+ pair. getValue()))
1000+ .collect(Collectors . joining(" , " ));
1001+ return " {" + result + " }" ;
1002+ }
1003+ }
1004+
1005+ public static void main (String [] args ) {
1006+ Counter petCount = new Counter ();
1007+ Pets . stream()
1008+ .limit(20 )
1009+ .peek(petCount:: count)
1010+ .forEach(p - > System . out. print(
1011+ p. getClass(). getSimpleName() + " " ));
1012+ System . out. println(" \n " + petCount);
1013+ }
1014+ }
1015+ /* 输出:
1016+ Rat Manx Cymric Mutt Pug Cymric Pug Manx Cymric Rat
1017+ EgyptianMau Hamster EgyptianMau Mutt Mutt Cymric Mouse
1018+ Pug Mouse Cymric
1019+ {Rat=2, Pug=3, Mutt=3, Mouse=2, Cat=9, Dog=6, Cymric=5,
1020+ EgyptianMau=2, Rodent=5, Hamster=1, Manx=7, Pet=20}
1021+ */
1022+ ```
1023+
1024+ 为了计算所有不同类型的 ` Pet ` ,` Counter Map ` 预先加载了来自 ` LiteralPetCreator.ALL_TYPES ` 的类型。如果不预先加载 ` Map ` ,将只计数随机生成的类型,而不是像 ` Pet ` 和 ` Cat ` 这样的基本类型。
1025+
1026+ ` isInstance() ` 方法消除了对 ` instanceof ` 表达式的需要。此外,这意味着你可以通过更改 ` LiteralPetCreator.types ` 数组来添加新类型的 ` Pet ` ;程序的其余部分不需要修改(就像使用 ` instanceof ` 表达式时那样)。
1027+
1028+ ` toString() ` 方法被重载,以便更容易读取输出,该输出仍与打印 ` Map ` 时看到的典型输出匹配。
1029+
1030+ ### Counting Recursively
8531031
8541032## 类型转换检测
8551033
0 commit comments