🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### [递归计数](https://lingcoder.gitee.io/onjava8/#/book/19-Type-Information?id=%e9%80%92%e5%bd%92%e8%ae%a1%e6%95%b0) `PetCount3.Counter`中的`Map`预先加载了所有不同的`Pet`类。我们可以使用`Class.isAssignableFrom()`而不是预加载`Map`,并创建一个不限于计数`Pet`的通用工具: ~~~ // onjava/TypeCounter.java // 计算类型家族的实例数 package onjava; import java.util.*; import java.util.stream.*; public class TypeCounter extends HashMap<Class<?>, Integer> { private Class<?> baseType; public TypeCounter(Class<?> baseType) { this.baseType = baseType; } public void count(Object obj) { Class<?> type = obj.getClass(); if(!baseType.isAssignableFrom(type)) throw new RuntimeException( obj + " incorrect type: " + type + ", should be type or subtype of " + baseType); countClass(type); } private void countClass(Class<?> type) { Integer quantity = get(type); put(type, quantity == null ? 1 : quantity + 1); Class<?> superClass = type.getSuperclass(); if(superClass != null && baseType.isAssignableFrom(superClass)) countClass(superClass); } @Override public String toString() { String result = entrySet().stream() .map(pair -> String.format("%s=%s", pair.getKey().getSimpleName(), pair.getValue())) .collect(Collectors.joining(", ")); return "{" + result + "}"; } } ~~~ `count()`方法获取其参数的`Class`,并使用`isAssignableFrom()`进行运行时检查,以验证传递的对象实际上属于感兴趣的层次结构。`countClass()`首先计算类的确切类型。然后,如果`baseType`可以从超类赋值,则在超类上递归调用`countClass()`。 ~~~ // typeinfo/PetCount4.java import typeinfo.pets.*; import onjava.*; public class PetCount4 { public static void main(String[] args) { TypeCounter counter = new TypeCounter(Pet.class); Pets.stream() .limit(20) .peek(counter::count) .forEach(p -> System.out.print( p.getClass().getSimpleName() + " ")); System.out.println("n" + counter); } } ~~~ 输出结果: ~~~ Rat Manx Cymric Mutt Pug Cymric Pug Manx Cymric Rat EgyptianMau Hamster EgyptianMau Mutt Mutt Cymric Mouse Pug Mouse Cymric {Dog=6, Manx=7, Cat=9, Rodent=5, Hamster=1, Rat=2, Pug=3, Mutt=3, Cymric=5, EgyptianMau=2, Pet=20, Mouse=2} ~~~ 输出表明两个基类型以及精确类型都被计数了。