如何使toString()方法返回Super Class私有字段及其实例字段?

时间:2014-11-26 08:03:02

标签: java eclipse inheritance tostring auto-generate

有没有办法让toString()包含超级class的私有字段?我尝试添加super.toString(),但没有用。

请参阅以下代码

Employee.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 + "]";
}



}

输出

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

这是我能做的最好的,连接super.toString() +'一组字符串',当然这很麻烦,还有其他一些方法,即使语言规范不允许eclipse有一些这样做的设施,注意:我使用 eclipse 来生成 toString 方法,我可以用任何方式告诉eclipse包含超类字段也是,

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

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

通过 eclipse 来自动化流程并生成合适的方法来实现它?

7 个答案:

答案 0 :(得分:5)

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

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

员工

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 + "]";
    }
}

管理器

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 + "]";
    }

}

第二个(使用受保护的)

员工

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 + "]";
    }
}

管理器

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 + "]";
    }

}

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

编辑:在日食中添加toString()的eclipse生成。 您似乎无法使用getter和setter生成它(只需快速查看,您可以看到一些文档here。 我所知道的是如何编辑生成toString()时使用的代码模板,因此它包含来自超类的toString()

当你进入generate toString()对话框时,旁边有一个字符串'String Format',<Default Template>。单击编辑按钮时,您可以创建新的代码模板。 此模板会自动保留<Default Template>,看起来像这样:

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

你必须添加的内容最后是

[super: ${object.superToString}]

这样它会显示超级类的toString()

答案 1 :(得分:5)

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

Eclipse generate toString() dialog

创建此代码:

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

会打印出来:

  

经理[奖金= 10.0,toString()=员工[name = Bill,id = 23,salary = 5000.0]]

你可以为你生成最多的东西。

你可以将它清理一下,看起来像这样

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

会打印

  

经理[奖金= 10.0]是员工[name = Bill,id = 23,salary = 5000.0]


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

你可以像这样清理它:

@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);
}

输出

  

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

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

有些事情没有意义:

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

  2. 如果你想到工资,身份,奖金私有因为这些不应该被知道(因此不提供吸气剂),那么为什么要提供一个显示这种秘密信息的toString。如果toString仅用于可视化测试目的,那么考虑使它们受到保护,然后在成功测试类后再将它们设置为私有。

  3. 否则,你的课程结构有问题,你只是想用语言做一些黑客攻击。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

最佳解决方案

您可以为超类实例变量调用 getters,并将值放在toString()上。你甚至可以偷偷摸摸地制作getter protected,这样只有子类才能查看变量的值。


懒人解决方案

制作字段protected,这可能是一个坏主意,具体取决于您的超类的设计方式。


坏主意

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

  

为特定目的创建反思,以发现反射   编译时未知的类的功能,类似于   dlopen和dlsym函数在C中做了什么。除此之外的任何用途   应该仔细审查。 (https://softwareengineering.stackexchange.com/questions/193526/is-it-a-bad-habit-to-overuse-reflection

答案 6 :(得分:0)

如果您无法更改超类的代码(更改成员范围或添加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);