我们需要知道,编译器在编译的时候是会将泛型擦除的,譬如原来的<Person> ---> <Object>
Person和Child1都有setValue方法
public class Person<T> {
public AtomicInteger updateCount = new AtomicInteger(0);
private T value;
//重写toString,输出值和值更新次数
@Override
public String toString() {
return String.format("value: %s updateCount: %d", value, updateCount.get());
}
//设置值
public void setValue(T value) {
System.out.println("Person.setValue called");
this.value = value;
updateCount.incrementAndGet();
}
}
public class Child1 extends Person{
//@Override
public void setValue(String value) {
System.out.println("Child1.setValue called");
super.setValue(value);
}
}
public class Application {
@Test
public void test() {
Child1 child1 = new Child1();
Arrays.stream(child1.getClass().getMethods())
.filter(method -> "setValue".equals(method.getName()))
.forEach(method -> {
try {
method.invoke(child1, "123");
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
});
System.out.println(child1.toString());
}
}
这里使用的是getMethods方法去获取类方法,但是要清楚这个方法获取的方法是子类和父类的所有方法;
可以很显然看出来这个父类的setValue方法被调用了两次,但是我们的期望是调用一次,那就证明或者debug发现调用了父类的
setValue(Object)方法,那这事为啥呢?前面提及到这个getMethods()方法可以获取父类和子类的所有方法,但是这个getDeclaredMethods只能获取当前类的方法,换一下看看。可以看到换了后就可以了;
但是这并不是最后的解决方式,因为我们需要考虑到泛型是jdk1.5出现的,那么jdk1.5之前的怎么办呢?这个时候就会出现了桥接。
修改Person的子类:给子类继承的父类加上泛型,
public class Child2 extends Person<String>{
//@Override
public void setValue(String value) {
System.out.println("Child1.setValue called");
super.setValue(value);
}
}
emmm,又出了两次调用,但是这次的调用跟上面的不一样,这个很显然是调用了两次子类的setValue方法这是为什么呢,提到过一个桥接,我也没弄明白这个东西,大致知道这个东西在子类中又创建了一个方法public void setValue(Object obj)
这里有个博客可以稍微看:blog.csdn.net/mhmyqn/arti…,
因此在做过滤的时候需要过滤那个桥接方法,增加这个!method.isBridge()这个过滤条件。
@Test
public void test() {
Child2 child2 = new Child2();
Arrays.stream(child2.getClass().getDeclaredMethods())
.filter(method -> "setValue".equals(method.getName()) && !method.isBridge())
.forEach(method -> {
try {
method.invoke(child2, "123");
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
});
System.out.println(child2.toString());
}