Skip to content

Commit eb6c5be

Browse files
committed
update
1 parent dcff5d4 commit eb6c5be

File tree

1 file changed

+178
-0
lines changed

1 file changed

+178
-0
lines changed

docs/book/19-Type-Information.md

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)