Java 如何使 toString() 方法连同其实例字段一起返回超类私有字段?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27143951/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 03:54:07  来源:igfitidea点击:

How make toString() method return Super Class private fields also along with its instance fields?

javaeclipseinheritancetostringauto-generate

提问by Sainath S.R

Is there a way to make toString()include private fields of the super class? I tried adding a super.toString(), no use however.

有没有办法使toString()包含 super 的私有字段class?我尝试添加一个super.toString(),但是没有用。

Please see the code below

请看下面的代码

Employee.java

雇员.java

package test;

public class Employee {

private  String name;
private int id;
private double salary;

public Employee(String name, int id, double salary) {
    super();
    this.name = name;
    this.id = id;
    this.salary = salary;
}

public double getSalary() {
    return salary;
}

@Override
public String toString() {
    return "Employee [name=" + name + ", id=" + id + ", salary=" + salary
            + "]";
}

public static void main(String[] args) {

    Employee e=new Employee("Joe", 14, 5000);
    System.out.println(e);
    Manager m=new Manager("Bill", 23, 5000, 10);
    System.out.println(m);
    System.out.println("Employee Salary is "+e.getSalary()+"\nManager salary is "+m.getSalary());
}
}

Manager.java

管理器

package test;

public class Manager extends Employee{

private double bonus;
public Manager(String name, int id, double salary,int bonus) {
    super(name, id, salary);
    this.bonus=bonus;
}

public double getSalary()
{
    double baseSalary=super.getSalary();

    return (baseSalary+baseSalary*(bonus/100));

}

@Override
public String toString() {
    return(this.getClass().getName()+" ["+super.toString().substring((this.getClass().getSuperclass().getName().length()-3
            ), (super.toString().length())-1)+", bonus="+bonus+"]");
    //didn't work
    //super.toString();
    //return "Manager [bonus=" + bonus + "]";
}



}

Output

输出

Employee [name=Joe, id=14, salary=5000.0]
test.Manager [name=Bill, id=23, salary=5000.0, bonus=10.0]
Employee Salary is 5000.0
Manager salary is 5500.0

That was the best i could do , to concatenate super.toString()+' a set of Strings', surely this is messy , is there some other way , even if the language spec does not allow it does eclipse have some facility to do that , NOTE: I used eclipseto generate the toStringmethod , any way by which i can tell eclipse to include the super class fields too,

这是我能做的最好的事情,连接super.toString()+'一组字符串',这肯定是乱七八糟的,还有其他方法吗,即使语言规范不允许它 eclipse 有一些工具可以做到这一点,注意:我使用eclipse生成toString方法,我可以通过任何方式告诉 eclipse 也包含超类字段,

In other words can i replace this messy code

换句话说,我可以替换这个凌乱的代码吗

return(this.getClass().getName()+" ["+super.toString().substring((this.getClass().getSuperclass().getName().length()-3
            ), (super.toString().length())-1)+", bonus="+bonus+"]");

by getting eclipseto automate the process and generate a suitable way to do it?

通过让Eclipse自动化该过程并生成合适的方法来做到这一点?

采纳答案by Liam de Haas

If you create getters and setters in your superclass then you can acces the variables through those methods. Other possibility is to change the visibility from private to protected

如果在超类中创建 getter 和 setter,则可以通过这些方法访问变量。另一种可能性是将可见性从私有更改为受保护

first solution looks like this

第一个解决方案看起来像这样

Employee

员工

public class Employee {

    private String name;
    private int id;
    private double salary;

    public Employee(String name, int id, double salary) {
        super();
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public double getSalary() {
        return salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee [name=" + name + ", id=" + id + ", salary=" + salary + "]";
    }
}

Manager

经理

public class Manager extends Employee {

    private double bonus;

    public Manager(String name, int id, double salary, int bonus) {
        super(name, id, salary);
        this.bonus = bonus;
    }

    public double getSalary() {
        double baseSalary = super.getSalary();

        return (baseSalary + baseSalary * (bonus / 100));

    }

    @Override
    public String toString() {
        return "Manager [name=" + getName() + ", id=" + getId() + ", salary=" + getSalary() + ", bonus=" + bonus + "]";
    }

}

Second one (using protected)

第二个(使用受保护的)

Employee

员工

public class Employee {

    protected String name;
    protected int id;
    protected double salary;

    public Employee(String name, int id, double salary) {
        super();
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public double getSalary() {
        return salary;
    }



    @Override
    public String toString() {
        return "Employee [name=" + name + ", id=" + id + ", salary=" + salary + "]";
    }
}

Manager

经理

public class Manager extends Employee {

    protected double bonus;

    public Manager(String name, int id, double salary, int bonus) {
        super(name, id, salary);
        this.bonus = bonus;
    }

    public double getSalary() {
        double baseSalary = super.getSalary();

        return (baseSalary + baseSalary * (bonus / 100));

    }

    @Override
    public String toString() {
        return "Manager [name=" + name + ", id=" + id + ", salary=" + salary + ", bonus=" + bonus + "]";
    }

}

Personally i'd use the getter/setter method but it's up to you.

我个人会使用 getter/setter 方法,但这取决于你。

EDIT: Additonal to eclipse generation of toString()in eclipse. You can't seem to generate it with getters and setter (just had a quick look, you can see some documentation here. What I did figure out is how you can edit the Code Template used when generating the toString()so it includes the toString()from the superclass.

编辑:附加到 eclipse 中的 eclipse 生成toString()。您似乎无法使用 getter 和 setter 生成它(只是快速浏览一下,您可以在此处查看一些文档。我确实想出了如何编辑生成时使用的代码模板,toString()以便它包含toString()来自超类的.

When you enter the generate toString() dialog there is a field 'String Format' with <Default Template>next to it. when you click the edit button you can create a new Code Template. This template automatically holds the <Default Template>and should look something like this:

当您进入生成 toString() 对话框时,<Default Template>旁边有一个字段“字符串格式” 。当您单击编辑按钮时,您可以创建一个新的代码模板。这个模板会自动保存<Default Template>并且应该看起来像这样:

${object.className} [${member.name()}=${member.value}, ${otherMembers}]

only thing you'll have to add is the following at the end

您唯一需要添加的是最后的以下内容

[super: ${object.superToString}]

This way it'll display the toString()form the superclass

这样它就会显示toString()超类的表单

回答by Wayne Huang

No. Because if you could directly access private fields of super class, those fields would not be private.

不。因为如果您可以直接访问超类的私有字段,那么这些字段就不会是私有的。

回答by retroq

The possible solution is to make a protected getters for fields in case you don't want to make fields itself protected.

可能的解决方案是为字段创建受保护的 getter,以防您不想让字段本身受到保护。

回答by FunctionR

Best Solution

最佳解决方案

You can call the getters for the super class instance variablesand put the values on your toString(). You could even be sneaky and make the getters protectedso that only the child classes can view the variable's value.

您可以调用超类实例变量getter并将值放在您的toString(). 您甚至可以偷偷摸摸地制作 getter,protected以便只有子类可以查看变量的值。



Lazy Solution

懒惰的解决方案

Make the fields protectedwhich might be a bad idea depending on how your super class is designed.

protected根据您的超类的设计方式,制作可能是个坏主意的字段。



Bad Idea

馊主意

You could also use reflection, but I wouldn't do that.

你也可以使用反射,但我不会那样做。

Reflection was created for a specific purpose, to discover the functionality of a class that was unknown at compile time, similar to what the dlopen and dlsym functions do in C. Any use outside of that should be heavily scrutinized. (https://softwareengineering.stackexchange.com/questions/193526/is-it-a-bad-habit-to-overuse-reflection)

反射是为特定目的而创建的,以发现在编译时未知的类的功能,类似于 C 中的 dlopen 和 dlsym 函数。除此之外的任何使用都应受到严格。(https://softwareengineering.stackexchange.com/questions/193526/is-it-a-bad-habit-to-overuse-reflection

回答by Udo Klimaschewski

If you can't change the code of the super class (change scope of members or add a getter), then you can use the Java reflection API to access a private field:

如果无法更改超类的代码(更改成员范围或添加 getter),则可以使用 Java 反射 API 访问私有字段:

Manager managerObject = new managerObject():
Employee e = (Employee) managerObject;
Field f = e.getClass().getDeclaredField("salary");
f.setAccessible(true);
double sal = (double) f.get(e);

回答by Timo Türschmann

You can let eclipse generate it, however it would not look like you want it.

您可以让 eclipse 生成它,但是它看起来不像您想要的。

Eclipse generate toString() dialog

Eclipse 生成 toString() 对话框

which creates this code:

创建此代码:

public String toString() {
    return "Manager [bonus=" + bonus + ", toString()=" + super.toString() + "]";
}

which would print this:

这将打印:

Manager [bonus=10.0, toString()=Employee [name=Bill, id=23, salary=5000.0]]

经理 [bonus=10.0, toString()=Employee [name=Bill, id=23,salary=5000.0]]

That's the most you can make eclipse generate for you.

这是您最多可以让 eclipse 为您生成。

You can clean it up a little so it would look like this

你可以稍微清理一下,让它看起来像这样

public String toString() {
    return "Manager [bonus=" + bonus +  "] is a " + super.toString();
}

which would print

哪个会打印

Manager [bonus=10.0] is a Employee [name=Bill, id=23, salary=5000.0]

经理 [bonus=10.0] 是一名员工 [name=Bill,id=23,salary=5000.0]



However, your custom solution works as well. So why not use it?

但是,您的自定义解决方案也适用。那么为什么不使用它呢?

You can clean it up a little like this:

你可以像这样清理它:

@Override
public String toString() {
    return "Manager [" + superFieldsFromToString() + ", bonus=" + bonus + "]";
}

private String superFieldsFromToString() {
    String superToString = super.toString();
    int superClassNameLength = getClass().getSuperclass().getSimpleName().length();
    int fieldStartIdx = superClassNameLength + 2; // + 2 removes " ["
    int fieldEndIdx = superToString.length() - 1; // - 1 removes "]"
    return superToString.substring(fieldStartIdx , fieldEndIdx);
}

which outputs

哪个输出

Manager [name=Bill, id=23, salary=5000.0, bonus=10.0]

经理 [name=Bill,id=23,salary=5000.0,bonus=10.0]

The only other options, as others have mentioned, are to use reflection to access the private fields, make the fields protected or create public getters.

正如其他人所提到的,唯一的其他选择是使用反射来访问私有字段,使字段受到保护或创建公共 getter。

I would not advice to do any of this, as your class design should not be defined by debug output.

我不建议这样做,因为您的类设计不应由调试输出定义。

回答by javaHunter

There is something that doesn't make sense:

有一点说不通:

  1. All your fields are either primitives and immutable thus you can safely publish (For Concurenecy purposes) them using getters.

  2. If you have in mind making salary, id, bonus private because these should not be known(and thus not provide getters), then why provide a toString that shows this secrete information. If the toString is just for visual testing purposes, then consider making them protected and then put them private again when you have successfully tested your class.

  1. 您的所有字段要么是原语,要么是不可变的,因此您可以使用 getter 安全地发布(出于 Concurenecy 目的)它们。

  2. 如果您考虑将工资、身、奖金设为私有,因为这些不应该是已知的(因此不提供 getter),那么为什么要提供一个显示此秘密信息的 toString。如果 toString 仅用于可视化测试目的,请考虑将它们设置为保护状态,然后在成功测试您的类后再次将它们设为私有。

Otherwise, there is something wrong in the structure of your classes and you are just trying to do some hacks in the language.

否则,你的类的结构有问题,你只是想在语言中做一些黑客。