Javadoc for Object.toString() says:
Returns a string representation of the object. In general, the
toString method returns a string that "textually represents" this
object. The result should be a concise but informative representation
that is easy for a person to read. It is recommended that all
subclasses override this method. The toString method for class Object
returns a string consisting of the name of the class of which the
object is an instance, the at-sign character '#', and the unsigned
hexadecimal representation of the hash code of the object. In other
words, this method returns a string equal to the value of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
Therefore, I am questioning myself if I'm abusing this when I am overriding toString() of a class Foo just so that a ComboBox control (doesn't matter it's JavaFX or Swing control) can render a list of Foo correctly without me doing anything explicit in the ComboBox.
class Foo {
private String name;
public final String getName() { return name; }
public final void setName(String n) { name = n; }
#Override
public String toString() {
return name;
}
}
List<Foo> foos = getFoos(); // Get list of Foos from somewhere
ComboBox comboBox = ....; // Some ComboBox control
comboBox.addItems(foos); // Add the list to the ComboBox
The default implementation of toString() that most IDE generates are JSON representation of the class. I am suspecting this allows easy serialization/deserialization of class objects. Although I do not need to serialize or deserialize through this method, but I am definitely breaking this possibility by overriding like this.
Edit
I've read the comments of many people, as well as the answer given by VGR. I can see that the general consensus is that there is no hard and fast rule on this. I see that it is generally agreed that toString() is better left for debugging purposes.
The biggest reason why I am doing this "hack" is because I have ComboBox in quite a number of different places. Of course the indisputably correct and clean way is to use a "renderer" to do this job, but it is causing a significant amount of code duplication.
I will mull over this for a few days before I decide which is the best way to do it. Thanks a lot for the bunch of comments and answer.
For Swing, you definitely need to override the toString method of some class. That’s how Swing model objects work. (Do not use cell renderers to convert a value to String; that will break accessibility, keyboard navigation, and built-in sorting of JTables.)
Usually you’d want to separate your display logic from your data, such as by creating a wrapper class, but since you are just returning the raw value of a property (as opposed to formatting it or concatenating it with other information), what you’re doing is fine.
JavaFX is another matter: Controls use cell factory callback objects to determine what text appears in a cell, so a data class probably should not override toString with a display value in a JavaFX application.
I’m not familiar with IDEs’ auto-generated toString methods, but converting an object to JSON in a toString method is a horrible idea in my opinion. Swing model objects should have a toString method that returns a human-readable form of the object; most other classes should return a one-line string with a summary of the object’s state (which does not have to be every property in the object), like getClass().getName() + "[" + getName() + "]".
In summary, you are not abusing toString. For Swing, you’re doing the right thing. For JavaFX, it’s better to return a string useful for debugging.
Related
I need to compare huge, multiple time nested, complex java object. There are no circular references (ufff). Adding "equal" method to each class takes weeks. I got the idea that maybe serializing these objects to array of bytes, and then comparing these arrays can be easier.
Very simplified example:
public class Car implements Serializable{
String name;
String brand;
public Car(String name, String brand) {
this.name = name;
this.brand = brand;
}
}
public class App {
public static void main(String[] args) {
Car carA = new Car("Ka", "Ford");
Car carB = new Car("P85D", "Tesla");
Car carC = new Car("Ka", "Ford");
byte[] carAr = SerializationUtils.serialize(carA);
byte[] carBr = SerializationUtils.serialize(carB);
byte[] carCr = SerializationUtils.serialize(carC);
boolean res = Arrays.equals(carAr, carBr);
System.out.println(res);
res = Arrays.equals(carAr, carAr);
System.out.println(res);
res = Arrays.equals(carAr, carCr);
System.out.println(res);
}
}
My initial tests (for much smaller and simpler structures) show that it works. Unfortunately I cannot find any proof that object properties are always serialized in the same order.
UPDATE
These classes are generated by a maven plugin and I do not know yet, how to intercept that process to add equals and hashCode methods.
If you're looking to compare objects for equality, serializing them and then comparing is pointless when you can simply override the class' equals method and compare them by their fields (there will undoubtedly be cases where certain fields of the class should not be taken into account, and your method of serialization may not offer that).
Adding "equal" method to each class takes weeks.
I'm sure this isn't the case. Modern IDEs are able to generate these methods for you, and libraries (such as Guava) offer methods that can compare objects by their fields in a single line of code.
You might want to give Apache's EqualsBuilder a try, most specifically this method (and variances of it); I think in the latest versions (3.7) it is fully recursive, but I think they also have a bug with Strings only solved in the yet-to-be-released v3.8, checking transient fields is also an option of some of the methods.
No, it isn't a good idea.
First, it ignores the content of all non-serializable base classes.
Second, it ignores any transient fields that may be present.
Third, it takes into account differences in referenced objects that you may wish to ignore.
Fourth, it requires that all classes concerned are serializable.
Fifth, it wastes time and space.
It isn't a good idea to post-modify generated code, but you could look into building a set of custom Comparators, which exist outside the class, such that you can use Comparatar.compare(T object1, T object2) to compare them.
I have a Map which represents Json object (so Map might have nested maps), and I want to log this Map in some places but I don't want to write to the console long strings. I'm looking for some way to get something like toString() but with ability of configuring max length of returned string.
Overriding toString() with implementation like
#Override
public String toString() {
return super.toString().substring(0, 100);
}
is not an option, because super.toString() might return really long (with >1000 length) string, which undesirable will fall into heap.
So can anybody tell if there is another way exists to get limited string of the object?
I see a lot of the following line in projects I took over:
log.debug(submitObject(" + object + ")");
log.debug(registerUser(" + user + ")");
and so on.
In the logs this prints out something like:
SubmitObject(java.lang.Object#13a317a)
Is it useful to log just the object type and its hashcode? Say I want to know the name of the user object but I only have the hashcode, would it be possible for me to reconstruct the object based on the hashcode?
From the javadoc for object.toString()
Returns a string representation of the object. In general, the
toString method returns a string that "textually represents" this
object. The result should be a concise but informative representation
that is easy for a person to read. It is recommended that all
subclasses override this method. The toString method for class Object
returns a string consisting of the name of the class of which the
object is an instance, the at-sign character `#', and the unsigned
hexadecimal representation of the hash code of the object. In other
words, this method returns a string equal to the value of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
Returns: a string representation of the object.
I myself always override the toString() of a custom object so it prints out all the fields of the object. Should I start printing the object code instead?
You could use ReflectionToStringBuilder from org.apache.commons, if you do not have access to source code, or if you do not want implement toString for change existing code.
For Example:
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("User : "
+ reflectionToStringBuilder.toString(user ,
ToStringStyle.MULTI_LINE_STYLE))
}
"LOGGER.isDebugEnabled() is very important as toString Operation, or reflectionToStringBuilder, will be executed before calling log.debug, so you do not want such expensive operations.
ReflectionToStringBuilderJavaDoc: http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/builder/ReflectionToStringBuilder.html
No, keep overriding toString() which is much more useful. The default toString() is practically useless except that it at least shows what the class instance is.
That hash code is a randomly assigned value. It is only useful if you want to check you had the same object in a previous log, or a different one (i.e. very rarely)
I'm designing a public interface (API) for a package. I wonder, should I use CharSequence generally instead of String. (I'm mainly talking about the public interfaces).
Are there any drawbacks of doing so? Is it considered a good practice?
What about using it for identifier-like purposes (when the value is matched against a set in a hash-based container)?
CharSequence is rarely used in general purpose libraries. It should usually be used when your main use case is string handling (manipulation, parsing, ...).
Generally speaking you can do anything with a CharSequence that you could do with a String (trivially, since you can convert every CharSequence into a String). But there's one important difference: A CharSequence is not guaranteed to be immutable! Whenever you handle a String and inspect it at two different points in time, you can be sure that it will have the same value every time.
But for a CharSequence that's not necessarily true. For example someone could pass a StringBuilder into your method and modify it while you do something with it, which can break a lot of sane code.
Consider this pseudo-code:
public Object frobnicate(CharSequence something) {
Object o = getFromCache(something);
if (o == null) {
o = computeValue(something);
putIntoCache(o, something);
}
return o;
}
This looks harmless enough and if you'd had used String here it would mostly work (except maybe that the value might be calculated twice). But if something is a CharSequence then its content could change between the getFromCache call and the computeValue call. Or worse: between the computeValue call and the putIntoCache call!
Therefore: only accept CharSequence if there are big advantages and you know the drawbacks.
If you accept CharSequence you should document how your API handles mutable CharSequence objects. For example: "Modifying an argument while the method executes results in undefined behaviour."
This does depend on what you need, I'd like to state two advantages of String, however.
From CharSequence's documentation:
Each object may be implemented by a different class, and there is no
guarantee that each class will be capable of testing its instances for
equality with those of the other. It is therefore inappropriate to use
arbitrary CharSequence instances as elements in a set or as keys in a
map.
Thus, whenever you need a Map or reliable equals/hashCode, you need to copy instances into a String (or whatever).
Moreover, I think CharSequence does not explicitly mention that implementations must be immutable. You may need to do defensive copying which may slow down your implementations.
Java CharSequence is an interface. As the API says, CharSequence has been implemented in CharBuffer, Segment, String, StringBuffer, StringBuilder classes. So if you want to access or accept your API from all these classes thenCharSequence is your choice. If not then String is very good for a public API because it is very easy & everybody knows about it. Remember CharSequence only gives you 4 method, so if you are accepting a CharSequence object through a method, then your input manipulation ability will be limited.
If a parameter is conceptually a sequence of chars, use CharSequence.
A string is technically a sequence of chars, but most often we don't think of it like that; a string is more atomic / holistic, we don't usually care about individual chars.
Think about int - though an int is technically a sequence of bits, we don't usually care about individual bits. We manipulate ints as atomic things.
So if the main work you are going to do on a parameter is to iterate through its chars, use CharSequence. If you are going to manipulate the parameter as an atomic thing, use String.
You can implement CharSequenceto hold your passwords, because the usage of String is discouraged for that purpose. The implementation should have a dispose method that wipes out the plain text data.
I appear to have a fundamental gap in my understanding of an EditText object. I have an Activity+Layout with a single EditText object. After I type a few characters into the EditText object and hit the Enter key, I retrieve the text in my onKey() listener. When I use the toString() method to retrieve the text I get back a weird string like:
android.widget.EditText#43749ff0
Despite the fact the EditText.mText property does show the string I entered, "123" during my tests. Why is toString() returning a different result and what appears to be some kind of "uninitalize" value? How do I get the desired string currently in the mText property and what is that strange value?
-- roschler
Passing glance at the API suggests you should use the getText() method. toString() is a general method that applies to Object and all its subclasses (i.e., everything that isn't a primitive, to my knowledge). It's often overridden to supply more useful strings, but by default, it reports something just like what you posted - a sparse description and the object's hashcode. To be clear, the API defines toString() as:
getClass().getName() + '#' + Integer.toHexString(hashCode())
You can't use the 'toString'-method on this, use 'getText().toString()' in stead.
You are calling toString() on a View Object, which probably does not have a toString() defined.
I believe you want to call this:
editText.getText().toString()
Try EditText.getText().toString()
Take a moment to read the java API: http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#toString%28%29
toString
public String toString() Returns a string representation of the object.
In general, the toString method
returns a string that "textually
represents" this object. The result
should be a concise but informative
representation that is easy for a
person to read. It is recommended that
all subclasses override this method.
The toString method for class Object
returns a string consisting of the
name of the class of which the object
is an instance, the at-sign character
`#', and the unsigned hexadecimal
representation of the hash code of the
object. In other words, this method
returns a string equal to the value
of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
Returns: a string representation of
the object.