有没有办法让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 来自动化流程并生成合适的方法来实现它?
答案 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生成它,但它看起来不像你想要它。
创建此代码:
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)
有些事情没有意义:
您的所有字段都是原始字段和不可变字段,因此您可以使用getter安全地发布(出于Concurenecy目的)。
如果你想到工资,身份,奖金私有因为这些不应该被知道(因此不提供吸气剂),那么为什么要提供一个显示这种秘密信息的toString。如果toString仅用于可视化测试目的,那么考虑使它们受到保护,然后在成功测试类后再将它们设置为私有。
否则,你的课程结构有问题,你只是想用语言做一些黑客攻击。
答案 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);