【问题标题】:Override a method of another class using Java Reflections使用 Java 反射覆盖另一个类的方法
【发布时间】:2023-04-10 21:25:01
【问题描述】:

我有一个 Java 项目,其中有 2 个类。我需要使用 Java 反射首先从 mywork.java 类打印由构造函数在 ProjectAccount.java 中设置的默认值,然后我需要重写 toString() 方法以从 mywork.java 类传递值并打印它们。

我能够使用 java 反射来打印默认的构造函数集值。但是在尝试使用参数覆盖和打印toString() 方法时出现错误。

ProjectAccount.java

package relive;

public class ProjectAccount {
    private String projectAccountID;
    private double budget;
    public int noOfProjects;

    public ProjectAccount(){
        this.projectAccountID = "MARTINDAWS-BillAnalyzer-001";
        this.budget = 120000.00;
        this.noOfProjects = 10;
    }

    @Override
    public String toString(){
        return "Project Accoutn ID = " + projectAccountID + " , Project Budget = "+budget + " , No of Projects = "+ noOfProjects;
    }
}

mywork.java

package relive;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class mywork {

    public static void main(String[] args) {
        try{
            Class<?> clazz = Class.forName("relive.ProjectAccount");
            Constructor<?> constr = clazz.getDeclaredConstructor(null);
            Method mets = clazz.getDeclaredMethod("toString", null);
            Object obj = constr.newInstance(new Object[] {});

            //Print Default values
            System.out.println(mets.invoke(obj, null));

            String mod_projectAccountID="ORPT-BT-EMP-DEV";
            double mod_budget = 2200000.0;
            int mod_noOfProjects = 20;

            //Print new passed values using the overridden method
            System.out.println(mets.invoke(obj, mod_projectAccountID,mod_budget, mod_noOfProjects));        
        }

        catch(ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e){
            e.printStackTrace();
        }
    }
    public static String toString(String mod_projectAccountID, double mod_budget, int mod_noOfProjects){
        return "Project Accoutn ID = " + mod_projectAccountID + " , Project Budget = "+mod_budget + " , No of Projects = "+ mod_noOfProjects; 
    }

}

输出和错误

我猜我遇到了这个错误,因为我还没有覆盖toString() 方法。任何关于我如何覆盖和打印它的建议都将受到高度赞赏。

【问题讨论】:

  • 目前尚不清楚为什么您要故意尝试调用具有比它所能接受的更多元素的方法。 mets 完全定义为 ProjectAccount toString 方法,它不带参数。 myWork 类没有扩展 ProjectAccount,那么它的 toString 方法如何以任何方式覆盖 ProjectAccount 实现?
  • 因此,与其尝试覆盖和传递修改后的参数,我可以访问变量并修改它们的值并直接调用相同的toString() 方法吗?
  • 当像你一样使用反射时,你不能改变任何方法的签名——你只能在它们被定义时调用它们。因此 ProjectAccount 方法 toString() 将始终不带任何参数。如果您希望它接受更多参数,您的选择是: 1)在项目帐户中编写另一个 toString 方法,该方法接受参数(您可以保留以前的 toString() 方法,只需添加另一个新方法); 2) 使 ProjectAccount 扩展 myWork - 这将允许您使用带有参数的 toString 的 myWork 版本。
  • 我为第二个选项添加了一个解决方案 - 见下文。

标签: java class reflection annotations overriding


【解决方案1】:

我刚刚修改了mywork.java类,直接访问ProjectAccount.java类变量并进行设置。

我访问了声明的字段并根据变量的名称或类型修改了声明的变量并调用了相同的toString() 方法,而没有覆盖toString() 方法。

mywork.java

package relive;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class answer_a {

    public static void main(String[] args) {
        try{
            Class<?> clazz = Class.forName("relive.ProjectAccount");
            Constructor<?> constr = clazz.getDeclaredConstructor(null);
            Method mets = clazz.getDeclaredMethod("toString", null);
            Object obj = constr.newInstance(new Object[] {});

            //Print Default values
            System.out.println(mets.invoke(obj, null));

            String mod_projectAccountID= "ORPT-BT-EMP-DEV";
            double mod_budget = 2200000.0;
            int mod_noOfProjects = 20;

            //Method that accesses the Fields and modifies them with the new variables

            Field [] fields = clazz.getDeclaredFields();
            for(int y=0; y<fields.length; y++){
                fields[y].setAccessible(true);

                if(fields[y].getName() == "projectAccountID"){
                    fields[y].set(obj, mod_projectAccountID);
                }
                else if(fields[y].getType().getSimpleName() == "double"){
                    fields[y].set(obj, mod_budget);
                }
                else if (fields[y].getType().getSimpleName() == "int"){
                    fields[y].set(obj, mod_noOfProjects);
                }
            }

            System.out.println(mets.invoke(obj, null));

        }
        catch(ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e){
            e.printStackTrace();
        }
    }

}

输出

【讨论】:

    【解决方案2】:

    里面有一些问题。

    1. 重写 toString 是通过定义一个实例方法(你的是静态的)
    2. 您的反射访问是 mets ,它引用了 ProjectAccount
    3. mywork 不是 ProjectAccount 的子类
    4. 你不能添加参数,

    子类重写方法的能力允许类从行为“足够接近”的超类继承,然后根据需要修改行为。覆盖方法与它覆盖的方法具有相同的名称、参数数量和类型以及返回类型。覆盖方法还可以返回被覆盖方法返回的类型的子类型。这种子类型称为协变返回类型。

    Oracle Docs

    package de.me.example;
    
    public class SuperType {
    
        @Override
        public String toString() {
    
            return "SuperType";
        }
    
    }
    
    
    package de.me.example;
    
    public class SubType extends SuperType {
    
        // this annatotion is syntactic sugar nothing more,
        //it behaves the same without it
        @Override
        public String toString() {
            return "SubType";
        }
    
    }
    

    【讨论】:

    • 在这种情况下,我是否要在同一个 try{} 块中声明该方法并添加一个@Override?您能否基于此举个例子。谢谢
    • 你能澄清一下,你真正想要得到什么?我明白,你想覆盖一个 toString 附加方法参数?
    猜你喜欢
    • 2013-02-22
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    相关资源
    最近更新 更多