web-dev-qa-db-ja.com

toString()メソッドがインスタンスフィールドとともにスーパークラスのプライベートフィールドを返すようにするにはどうすればよいですか?

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にはいくつかの機能がありますそれを行うには、[〜#〜] note [〜#〜]Eclipseを使用してtoStringメソッド、スーパークラスフィールドも含めるようにEclipseに指示できる方法、

言い換えれば、この厄介なコードを置き換えることができますか

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

Eclipseを取得してプロセスを自動化し、それを行うための適切な方法を生成しますか?

6
Sainath S.R

スーパークラスでゲッターとセッターを作成する場合は、これらのメソッドを使用して変数にアクセスできます。他の可能性は、可視性をプライベートから保護に変更することです

最初の解決策は次のようになります

社員

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

}
_

2番目(保護されたものを使用)

社員

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

}
_

個人的にはゲッター/セッターメソッドを使用しますが、それはあなた次第です。

編集:EclipseでのtoString()のEclipse生成に追加。ゲッターとセッターでそれを生成することはできないようです(ちょっと見てみると、いくつかのドキュメントを見ることができます ここ 。私が理解したのは、生成時に使用されるコードテンプレートを編集する方法です。 toString()なので、スーパークラスのtoString()が含まれます。

Generate toString()ダイアログに入ると、フィールド「String Format」があり、その横に_<Default Template>_があります。編集ボタンをクリックすると、新しいコードテンプレートを作成できます。このテンプレートは自動的に_<Default Template>_を保持し、次のようになります。

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

追加する必要があるのは、最後に次のことだけです。

_[super: ${object.superToString}]
_

このようにして、スーパークラスからtoString()を表示します

5
Liam de Haas

Eclipseにそれを生成させることができますが、それはあなたが望むようには見えません。

Eclipse generate toString() dialog

このコードを作成します:

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

これを印刷します:

マネージャー[ボーナス= 10.0、toString()=従業員[名前=請求書、ID = 23、給与= 5000.0]]

これが、Eclipseに生成させることができる最大のものです。

あなたはそれを少しきれいにすることができるのでそれはこのようになります

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

印刷されます

マネージャー[ボーナス= 10.0]は従業員です[名前=請求書、ID = 23、給与= 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);
}

どの出力

マネージャー[名前=請求書、ID = 23、給与= 5000.0、ボーナス= 10.0]

他の人が述べているように、他の唯一のオプションは、リフレクションを使用してプライベートフィールドにアクセスするか、フィールドを保護するか、パブリックゲッターを作成することです。

クラスの設計はデバッグ出力で定義されるべきではないため、これを行うことはお勧めしません。

5

意味をなさないことがあります:

  1. すべてのフィールドはプリミティブで不変であるため、ゲッターを使用して(Concurenecyの目的で)安全に公開できます。

  2. 給与、ID、ボーナスを知られてはならない(したがってゲッターを提供しない)ために非公開にすることを考えている場合は、この秘密情報を表示するtoStringを提供するのはなぜですか。 toStringが視覚的なテストのみを目的としている場合は、それらを保護することを検討し、クラスのテストに成功したら、それらを再びプライベートにします。

それ以外の場合は、クラスの構造に問題があり、言語でいくつかのハックを実行しようとしています。

1
javaHunter

いいえ。スーパークラスのプライベートフィールドに直接アクセスできる場合、それらのフィールドはプライベートではないためです。

1
Wayne Huang

考えられる解決策は、フィールド自体を保護したくない場合に備えて、フィールドの保護されたゲッターを作成することです。

0
retroq

最良の解決策

スーパークラスインスタンス変数のゲッターを呼び出して、toString()に値を設定できます。卑劣でゲッターをprotectedにして、子クラスだけが変数の値を表示できるようにすることもできます。


怠惰な解決策

フィールドをprotectedにします。これは、スーパークラスの設計方法によっては悪い考えかもしれません。


悪いアイデア

リフレクションを使用することもできますが、私はそうしません。

リフレクションは、コンパイル時に未知であったクラスの機能を発見するために、特定の目的で作成されました。これは、Cでのdlopen関数とdlsym関数の機能と同様です。それ以外の使用については、十分に精査する必要があります。 ( https://softwareengineering.stackexchange.com/questions/193526/is-it-a-bad-habit-to-overuse-reflection

0
FunctionR

スーパークラスのコードを変更できない場合(メンバーのスコープを変更するか、ゲッターを追加する)、Java Reflection APIを使用してプライベートフィールドにアクセスできます:

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