質問

I'm not sure what the author means when he writes that a singleton static factory method can guarantee that no two equal instances exist. Well actually I do kind of understand that but I'm confused by the following text when he demonstrates the equals method vs the literal comparison operator: "a.equals(b) if and only if a==b."

I understand that the equals() method actually compares the contents of an object while the literal == compares to see if they are the same object in memory. This is confusing because he goes on to say that the client can use the == instead of the .equals(object) method. How so? Why would the client use the == comparator if they're guaranteed to only one object?

Could someone write me a short coded example to explain this more concretely?

The authors text is below:

The ability of static factory methods to return the same object from repeated invocations allows classes to maintain strict control over what instances exist at any time. Classes that do this are said to be instance-controlled. There are several reasons to write instance-controlled classes. Instance control allows a class to guarantee that it is a singleton (Item 3) or noninstantiable (Item 4). Also, it allows an immutable class (Item 15) to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its clients can use the == operator instead of the equals(Object) method, which may result in improved performance. Enum types (Item 30) provide this guarantee.

役に立ちましたか?

解決 2

I think you've almost got it. The static method makes the following promise, "if you request a new object that would compare .equals() to an existing object, I'll return the existing object instead". Given that guarantee, you know that a.equals(b) means that a == b, and you know that a == b means that a.equals(b). As a result, if you want to see if a and b are equal, you can use the == operator instead of the .equals method. That's useful because == is very fast and, depending on the object types, .equals could be slow.

Here's a concrete example. Suppose we have a person class. A person is defined by their first and last name (pretend that there are no two people in the world with the same name). My class might look like this (didn't try to compile, so no guarantee of correctness):

class Person {
  private final String fname;
  private final String lname;

  // Private constructor - must use the static method
  private Person(String first, String last) {fname = first; lname = last;}

  // Note that this is slow - the time it takes is proportional to the length of the
  // two names
  public boolean equals(Object o) {
    // Should check types here, etc.
    Person other = (Person) o;
    if (!person.fname.equals(other.fname)) {return false;}
    if (!person.lname.equals(other.lname)) {return false;}
    return true;
  }

  // Registry of all existing people
  private static Map<String, Person> registry = new TreeMap<String, Person>();

  public static getPerson(String fname, String lname) {
    String fullName = fname + "-" + lname;
    // If we already have this person, return that object, don't construct a new one.
    // This ensures that p1.equals(p2) means that p1 == p2
    if (registry.containsKey(fullName)) {return registry.get(fullName);}
    Person p = new Person(fname, lname);
    registry.put(fullName, p);
    return p;
  }
}

And then you can use it like this:

public boolean isSamePerson(Person p1, Person p2) {
  // Guaranteed to have the same result as "return p1.equals(p2)" but will be faster
  return p1 == p2;
}

他のヒント

In the particular snippet you quote at the top he's talking about enforcing one instance for each possible set of values in instances of an immutable class:

Also, it allows an immutable class (Item 15) to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b

That is, you might want your static factory to guarantee that if a and b represent the same values, then they are the same instance in memory (i.e. duplicates cannot exist). When this is true, then == works the same as equals(Object), which means that you are free to use == where you think it might help with performance.

As Jon says in the comments, static factories are not restricted to singletons.

If you can guarantee (perhaps with a Flyweight pattern) that equal objects will have the same referent, then callers may use == (and get a performance benefit); as an example consider an enum type... you can use == to determine if any two enum instances are the same.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top