java - 具有不同泛型的方法参数是否使方法具有不同的签名?

标签 java generics overloading

我有以下工厂类。它有两个方法,它们接受 Class 实例并返回相应的对象。它们具有相同的方法名称,并且两个方法都以 Class 作为参数但具有不同的泛型类,也返回不同的类型。编译器是否认为这两个方法是重复的?当我在 Eclipse 中打开 java 文件时,它报告如下错误:

描述资源路径位置类型 方法 lookupHome(Class) 与类型 EJBHomeFactory EJBHomeFactory.java 中的另一个方法具有相同的删除 lookupHome(Class)

但是,javac 似乎不会报告任何错误。

import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;

public class EJBHomeFactory {
    public <T extends EJBHome> T lookupHome(Class<T> homeClass) throws PayrollException {
        return lookupRemoteHome(homeClass);
    }

    public <T extends EJBLocalHome> T lookupHome(Class<T> homeClass) throws PayrollException {
        return lookupLocalHome(homeClass);
    }

    /* ... define other methods ... */
}

更新 1:这是使代码通过的 ant 脚本,我不确定它是如何工作的,但它不会抛出任何错误。编译器似乎是 Eclipse JDT Compiler,我尝试使用常规 javac,但无法编译。

<target name="compile" depends="init" description="Compile Java classes">
    <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
    <mkdir dir="${build.classes.dir}"/>
    <javac destdir="${build.classes.dir}"
            srcdir="${build.src.dir};${devsrc.dir}"
            deprecation="${build.deprecation}"
            debug="${build.debug}"
            source="${build.source}"
            target="${build.target}"
            nowarn="${suppress.warning}"
            bootclasspath="${bootclasspath}" >
        <classpath>
            <path refid="build.class.path.id"/>
        </classpath> 
    </javac>
</target>

更新 2:我只是创建了另一个示例,有两个基类和两个子类,一个工厂类采用 Class 并根据参数的类型生成实例。代码无法通过 javac 编译,在 Eclipse 中,IDE 会提示同样的删除问题。这是代码: 两个空基类:

public class BaseClassFirst {
}

public class BaseClassSecond {
}

两个子类:

public class SubClassFirst extends BaseClassFirst {
    private int someValue = 0;

    public SubClassFirst() {
        System.out.println(getClass().getName());
    }

    public SubClassFirst(int someValue) {
        this.someValue = someValue;
        System.out.println(getClass().getName() + ": " + this.someValue);
    }
}

public class SubClassSecond extends BaseClassSecond {
    private int someValue = 0;

    public SubClassSecond() {
        System.out.println(getClass().getName());
    }

    public SubClassSecond(int someValue) {
        this.someValue = someValue;
        System.out.println(getClass().getName() + ": " + this.someValue);
    }
}

因素类: 导入 java.lang.reflect.Method;

public class ClassFactory {

    private static ClassFactory instance = null;

    private ClassFactory() {
        System.out.println("Welcome to ClassFactory!");
    }

    public static synchronized ClassFactory getInstance() {
        if (instance == null) {
            instance = new ClassFactory();
        }
        return instance;
    }

    public <T extends BaseClassFirst> T createClass(Class<T> firstClazz) {
        if (firstClazz.equals(SubClassFirst.class)) {
            try {
                return firstClazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public <T extends BaseClassSecond> T createClass(Class<T> secondClazz) {
        if (secondClazz.equals(SubClassSecond.class)) {
            try {
                return secondClazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public static void main(String[] args) {
        ClassFactory factory = ClassFactory.getInstance();
        SubClassFirst first = factory.createClass(SubClassFirst.class);
        SubClassSecond second = factory.createClass(SubClassSecond.class);
        for (Method method : ClassFactory.class.getDeclaredMethods()) {
            System.out.println(method);
        }
    }
}

最佳答案

当方法可以在编译时解析时,这是可行的,因为返回类型是签名的一部分。删除后你有两种方法

public EJBHome lookupHome(Class homeClass) throws PayrollException;
public EJBLocalHome lookupHome(Class homeClass) throws PayrollException;

您不能在没有泛型的情况下定义它们,但由于返回类型是签名的一部分,因此这些是不同的方法。

你可以调用

lookupHome(EJBHome.class);
lookupHome(EJBLocalHome.class);

但不是

Class c= EJBHome.class;
lookupHome(c); // Ambiguous method call.

编辑:尝试以下操作。

for (Method method : EJBHomeFactory.class.getDeclaredMethods()) {
    System.out.println(method);
}

你应该会看到类似的东西

public javax.ejb.EJBHome EJBHomeFactory.lookupHome(java.lang.Class)
public javax.ejb.EJBLocalHome EJBHomeFactorylookupHome(java.lang.Class)

同样,如果您使用 javap -c。

调用虚拟#8;//方法lookupHome:(Ljava/lang/Class;)Ljavax/ejb/EJBHome;

调用虚拟#10;//方法lookupHome:(Ljava/lang/Class;)Ljavax/ejb/EJBLocalHome;

编辑如果你想要一个返回类型是签名一部分的例子..

class A {
   public static Byte getNum() { return 0; }
}

class B {
  public static void main(String ... args) {
     int i = A.getNum();
     System.out.println(i);
  }
}

编译运行,没有报错,现在把A中getNum的签名改成

class A {
   public static Integer getNum() { return 0; }
}

并且只编译类 A。如果返回类型不是签名的一部分,这对 B 没有影响,但是如果你运行 B 而不重新编译它,你会得到

Exception in thread "main" java.lang.NoSuchMethodError: A.getNum()Ljava/lang/Byte;
at B.main(B.java:10)

如您所见,返回类型Ljava/lang/Byte;是返回类型的内部名称和签名的一部分。

关于java - 具有不同泛型的方法参数是否使方法具有不同的签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5109146/

相关文章:

java - 检索泛型类型的类实例而不将泛型作为输入

java - List<List<String>> 泛型问题

arrays - Powershell 如何重载数组索引运算符?

java - 方法参数顺序的改变能叫方法重载吗?

c++ - 如何避免重载指向结构的指针的运算符? C++

Java多数组声明

java - JERSEY 在 Google App Engine 中上传文件

java - 调用泛型类型类中的方法

java - 如何删除 : java. lang.OutOfMemoryError

java - 在单元测试之前初始化数据库时出现 SQL 语法错误