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

有没有办法让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自动化流程并生成一个合适的方法来实现它?

如果在超类中创建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方法,但这取决于你。

编辑:在eclipse中添加到eclipse生成的toString() 。 你似乎无法使用getter和setter生成它(只是快速查看,你可以在这里看到一些文档。我弄清楚你是如何编辑生成toString()时使用的代码模板所以它包括来自超类的toString()

当您进入generate toString()对话框时,旁边有一个“String Format”字段,其中包含 。 单击编辑按钮时,可以创建新的代码模板。 此模板自动保存 ,看起来像这样:

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

你必须添加的东西最后是以下内容

 [super: ${object.superToString}] 

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

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

Eclipse生成toString()对话框

创建此代码:

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

哪打印出来:

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

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

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

 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]

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

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

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

有些事情没有意义:

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

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

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

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

最佳方案

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


懒惰的解决方案

根据超类的设计方式,使字段protected ,这可能是一个坏主意。


馊主意

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

为特定目的创建了reflection,以发现在编译时未知的类的function,类似于dlopen和dlsym函数在C中执行的操作。除此之外的任何使用都应该经过严格审查。 ( https://softwareengineering.stackexchange.com/questions/193526/is-it-a-bad-habit-to-overuse-reflection

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

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