java编译器错误中的动态强制转换

java编译器错误中的动态强制转换,java,casting,Java,Casting,我有3个类A、B和C。它们唯一的共同点是一个getName()函数,其他什么都没有 我有一个Class类型的数组,它存储上述类 Class[] classes = {A.class,B.class,C.class}; 然后我有一个包含类型a、B和C的对象的列表 List<?> list = new ArrayList<?>(); list.add(new A()); list.add(new B()); list.add(new C()); List List=new

我有3个类A、B和C。它们唯一的共同点是一个getName()函数,其他什么都没有

我有一个Class类型的数组,它存储上述类

Class[] classes = {A.class,B.class,C.class};
然后我有一个包含类型a、B和C的对象的列表

List<?> list = new ArrayList<?>();
list.add(new A());
list.add(new B());
list.add(new C());
List List=new ArrayList();
添加(新的A());
添加(新的B());
添加(新的C());
我想通过循环访问列表中的对象。我还想访问对象A、B和C的方法。因此,我尝试使用类数组强制转换它们

for(int i = 0; i < classes.length;i++)
{
    classes[i].cast(list.get(i)).getName(); //A,B,and C have method getName() in common
}
for(int i=0;i
这给了我一个编译器错误:“没有为类型对象定义getName()方法


编译器是否有办法在运行时之前忽略这种类型的强制转换(我确信它在运行时会起作用)?或者是否有另一种解决方案可以满足我的期望(我正在寻找一种不涉及更改类a、B和C的代码的解决方案)

您应该使用方法
getName()实现一个接口
,我们称之为可命名的

public interface Nameable {

    public String getName();
}
然后让这三个类
A
B
C
实现
Nameable
。这将允许您将列表声明为
列表
,并且在访问其元素时无需强制转换来调用此方法

编辑:好的,因为你不能修改这些类,你可以做一些类似于@JB niset建议的事情。但是,不要在循环中动态查找方法,因为这是昂贵的。静态地为每个类查找这些方法一次,并将它们保存在一个
映射中,其中键是

private static final Map<Class<?>, Method> getNameMap = new HashMap<Class<?>, Method>();
static {
    try {
        getNameMap.put(A.class, A.class.getMethod("getName"));
        getNameMap.put(B.class, B.class.getMethod("getName"));
        getNameMap.put(C.class, B.class.getMethod("getName"));
    }
    catch (NoSuchMethodException nsme) {
        //handle method not being found
    }
}
私有静态最终映射,方法>();
静止的{
试一试{
getNameMap.put(A.class,A.class.getMethod(“getName”));
getNameMap.put(B.class,B.class.getMethod(“getName”);
getNameMap.put(C.class,B.class.getMethod(“getName”);
}
捕获(NoSuchMethodException nsme){
//找不到句柄方法
}
}
然后从循环中查找方法:

for (Object obj : list) {
    try {
        Class<?> objClass = obj.getClass();
        Object returned = getNameMap.get(objClass).invoke(obj);
        String name = (String)returned; //I'm just assuming these methods return a String that you want to use for something
    }
    catch (IllegalAccessException iae) {
        //handle method not being accessable
    }
    catch (InvocationTargetException ite) {
        Throwable cause = ite.getCause();
        //handle cause exception
    }
}
用于(对象对象对象:列表){
试一试{
类objClass=obj.getClass();
返回的对象=getNameMap.get(objClass.invoke)(obj);
String name=(String)returned;//我只是假设这些方法返回一个您想要用于某些内容的字符串
}
捕获(IllegalacessException iae){
//句柄方法不可访问
}
捕获(调用targetException ite){
可丢弃原因=ite.getCause();
//处理原因异常
}
}

您应该使用方法
getName()
实现一个接口,我们称之为
Nameable

public interface Nameable {

    public String getName();
}
然后让这三个类
A
B
C
实现
Nameable
。这将允许您将列表声明为
列表
,并且在访问其元素时无需强制转换来调用此方法

编辑:好的,因为你不能修改这些类,你可以做一些类似于@JB niset建议的事情。但是,不要在循环中动态查找方法,因为这是昂贵的。静态地为每个类查找这些方法一次,并将它们保存在一个
映射中,其中键是

private static final Map<Class<?>, Method> getNameMap = new HashMap<Class<?>, Method>();
static {
    try {
        getNameMap.put(A.class, A.class.getMethod("getName"));
        getNameMap.put(B.class, B.class.getMethod("getName"));
        getNameMap.put(C.class, B.class.getMethod("getName"));
    }
    catch (NoSuchMethodException nsme) {
        //handle method not being found
    }
}
私有静态最终映射,方法>();
静止的{
试一试{
getNameMap.put(A.class,A.class.getMethod(“getName”));
getNameMap.put(B.class,B.class.getMethod(“getName”);
getNameMap.put(C.class,B.class.getMethod(“getName”);
}
捕获(NoSuchMethodException nsme){
//找不到句柄方法
}
}
然后从循环中查找方法:

for (Object obj : list) {
    try {
        Class<?> objClass = obj.getClass();
        Object returned = getNameMap.get(objClass).invoke(obj);
        String name = (String)returned; //I'm just assuming these methods return a String that you want to use for something
    }
    catch (IllegalAccessException iae) {
        //handle method not being accessable
    }
    catch (InvocationTargetException ite) {
        Throwable cause = ite.getCause();
        //handle cause exception
    }
}
用于(对象对象对象:列表){
试一试{
类objClass=obj.getClass();
返回的对象=getNameMap.get(objClass.invoke)(obj);
String name=(String)returned;//我只是假设这些方法返回一个您想要用于某些内容的字符串
}
捕获(IllegalacessException iae){
//句柄方法不可访问
}
捕获(调用targetException ite){
可丢弃原因=ite.getCause();
//处理原因异常
}
}

您不需要强制转换:一个
A
实例就是一个
A
实例,强制转换不会改变它的类型。因为您在编译时不知道元素的类型是什么,所以强制转换对您没有帮助

您必须做的是通过反射调用
getName
方法:

Class<?> clazz = list.get(i).getClass();
Method m = clazz.getMethod("getName");
m.invoke(list.get(i));
Class clazz=list.get(i).getClass();
方法m=clazz.getMethod(“getName”);
m、 调用(list.get(i));

您不需要强制转换:一个
A
实例就是一个
A
实例,强制转换不会改变它的类型。因为您在编译时不知道元素的类型是什么,所以强制转换对您没有帮助

您必须做的是通过反射调用
getName
方法:

Class<?> clazz = list.get(i).getClass();
Method m = clazz.getMethod("getName");
m.invoke(list.get(i));
Class clazz=list.get(i).getClass();
方法m=clazz.getMethod(“getName”);
m、 调用(list.get(i));

因为编译器无法检查该列表中的对象是否有相应的
getName()
方法。如果该列表中有一个类为D的对象,该怎么办?解决方案是使用方法定义一个接口
getName()

import java.util.ArrayList;
导入java.util.List;
公共类接口示例{
接口I{
字符串getName();
}
静态类A实现了I{
...
}
静态类B实现了I{
...
}
静态类C实现了I{
...
}
公共静态void main(字符串[]args){
列表=新的ArrayList();
添加(新的A());
添加(新的B());
添加(新的C());
(I:列表){
i、 getName();
}
}
}

因为编译器无法检查该列表中的对象是否具有相应的
ge
for(int i = 0; i < list.length;i++)
{
    final Object obj = list.get(i);
    final Method m = obj.getClass.getMethod("getName"); //A,B,and C have method getName() in common
    m.invoke(obj);

    // Exception-handling code omitted
}
public static void main(String[] args) { A aObject; B bObject; C cObject; List list = new ArrayList(); list.add(new A()); list.add(new B()); list.add(new C()); list.add(new String()); for (Object current : list) { if (current instanceof A) { aObject = (A)current; System.out.println(aObject.getName()); } else if (current instanceof B) { bObject = (B)current; System.out.println(bObject.getName()); } else if (current instanceof C) { cObject = (C)current; System.out.println(cObject.getName()); } else { System.out.print("Unexpected class: "); System.out.println(current.getClass()); } } } public static void main(String[] args) { List list = new ArrayList(); Method getNameMethod; list.add(new A()); list.add(new B()); list.add(new C()); list.add(new String()); for (Object current : list) { // getNameMethod = MethodUtils.getAccessibleMethod(current.getClass(), "getName", (Class[])null); try { getNameMethod = current.getClass().getMethod("getName"); } catch (SecurityException exception1) { getNameMethod = null; } catch (NoSuchMethodException exception1) { getNameMethod = null; } if (getNameMethod != null) { try { System.out.println(getNameMethod.invoke(current, (Object[])null)); } catch (IllegalArgumentException exception) { // TODO Implement this catch block. } catch (IllegalAccessException exception) { // TODO Implement this catch block. } catch (InvocationTargetException exception) { // TODO Implement this catch block. } } else { System.out.print("Unexpected class: "); System.out.println(current.getClass()); } } }
static String executeGetName(Object o) throws SecurityException,
        NoSuchMethodException, IllegalArgumentException,
        IllegalAccessException, InvocationTargetException {
    Method method = o.getClass().getMethod("getName");
    return (String) method.invoke(o);
}