Serialize an object into a string [duplicate] - java

This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed 3 years ago.
Can someone help me to serialze an object into a string? The result of my code is a bit weird, I need to get a toString(); methode or something with which i can serialze an object into a string but I dont know any.
Thanks for the help
results with getString -> only "null"
result without getString(); -> Fruit#4dd8dc3, Fruit#6d03e736, Fruit#568db2f2, Fruit#378bf509, Fruit#5fd0d5ae,
Fruit#2d98a335, Fruit#16b98e56, Fruit#7ef20235"
import java.io.Serializable;
public class Fruit implements Comparable<Fruit>,Serializable{
String getString;
String name;
int gewicht;
public String getString() {
return this.getString;
}
public Fruit(String name, int gewicht) {
this.name=name;
this.gewicht=gewicht;
}
public int compareTo(Fruit otherFruit) {
if(this.gewicht < otherFruit.gewicht)
return -1;
if(this.gewicht>otherFruit.gewicht)
return 1;
return 0;
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.TreeSet;
public class FruitTree {
public static void main(String[] args) {
TreeSet<Fruit> fruitTree = new TreeSet<Fruit>();
fruitTree.add(new Fruit("Kiwi",5));
fruitTree.add(new Fruit("Kirsche",1));
fruitTree.add(new Fruit("Ananas",75));
fruitTree.add(new Fruit("Zitrone",15));
fruitTree.add(new Fruit("Grapefruit",44));
fruitTree.add(new Fruit("Banane",55));
fruitTree.add(new Fruit("Kirsche",2));
fruitTree.add(new Fruit("Kiwi",8));
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("IO.txt"));
Iterator<Fruit> it = fruitTree.iterator();
while(it.hasNext()) {
oos.writeObject(it.next());
}
oos.writeObject(null);
ObjectInputStream ois = new ObjectInputStream (new FileInputStream("IO.txt"));
Object readObject=null;
TreeSet<Fruit> deserializedFruits= new TreeSet<Fruit>();
do {
readObject=ois.readObject();
if(readObject !=null)
deserializedFruits.add((Fruit) readObject);
}
while (readObject!=null);
it=deserializedFruits.iterator();
while(it.hasNext()) {
System.out.println(it.next().getString());
ois.close();
oos.close();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Can someone help me to serialze an object into a string? The result of my code is a bit weird, I need to get a toString(); methode or something with which i can serialze an object into a string but I dont know any.
Thanks for the help

Adding implements Serializable to your class will not override default Object.toString implementation - that's not how Java works (btw this default implementation will actually provide you what you got - for example Fruit#5fd0d5ae - that's how it works)
what you need to do is to override toString by yourself - for example
public class Fruit implements Comparable<Fruit>,Serializable {
// ...
#Override
public String toString() {
return "name: " + this.name + ", gewicht: " + String.valueOf(this.gewicht);
}
}
or to use some existing tool that will generate this method for you (like lombok), or even better that will allow you to serialize your class object to some common format like JSON or XML (for this take a look at gson or Jackson)

Related

Why is my TreeSet in Java giving me a null pointer exception when I try to add a String? [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 11 months ago.
I'm working on a project for a Java class, and I can't seem to get past this NullPointerException. The project is a command-line LinkedIn program. One of the aspects I'm implementing is the ability to add a skillset to a user's profile.
I have a LinkedInUser class in which I define a TreeSet to hold these skillsets in the form of Strings entered by the user. I'm using TreeSet, because the assignment requires them to be sorted.
I define the TreeSet in the LinkedInUser class here:
private Set<String> skillsets = new TreeSet<>();
The action the user takes is defined in the AddSkillsetAction class:
String skillset;
System.out.println("Enter a skillset to add to your list:");
skillset = scanner.nextLine();
loggedInUser.addSkillset(skillset);
System.out.println(skillset + " has been added to your skillsets.");
And the String they enter is passed to the addSkillSet function in the LinkedInUser class:
public void addSkillset(String skillset) {
skillsets.add(skillset);
}
I keep getting a NullPointerException on the line:
skillsets.add(skillset);
What am I doing wrong? I've tested every level up to that line. I even tested the TreeSet inside the addSkillset function with this code:
if(skillsets == null) {
System.out.println("The TreeSet is null.")
}
It's telling me the TreeSet is null. I thought instantiating the Set with:
private Set<String> skillsets = new TreeSet<>();
would actually create an empty TreeSet, instead of it pointing to a null location. Why is my set "skillsets" still pointing to null? What am I doing wrong here?
EDIT:
Here are the full classes:
package edu.institution.asn2;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class LinkedInUser extends UserAccount implements Comparable<LinkedInUser>, Serializable {
private static final long serialVersionUID = 75648957489235739L;
private String type;
private List<LinkedInUser> connections = new ArrayList<>();
private Set<String> skillsets = new TreeSet<>();
public LinkedInUser(String username, String password) {
super(username, password);
}
#Override
public void setType(String type) {
this.type = type;
}
public String getType() {
return this.type;
}
// Add a connection to user's list
public void addConnection(LinkedInUser user) throws LinkedInException {
int index = connections.indexOf(user);
if (index >= 0) {
throw new LinkedInException("You are already connected with this user.");
}
else {
connections.add(user);
}
}
// Remove a connection from the user's connection list
public void removeConnection(LinkedInUser user) throws LinkedInException {
int index = connections.indexOf(user);
if (index < 0) {
throw new LinkedInException("You are NOT connected to this user.");
}
else {
connections.remove(index);
}
}
// Return a copy of the ArrayList of connections
public List<LinkedInUser> getConnections() {
ArrayList<LinkedInUser> copy = new ArrayList<>(connections);
return copy;
}
// Return the number of connections
public int getNumberOfConnections() {
return connections.size();
}
// Return the skillsets
public Set<String> getSkillsets(){
return skillsets;
}
// Add a skillset
public void addSkillset(String skillset) {
skillsets.add(skillset);
}
// Remove a skillset
public void removeSkillset (String skillset) {
if(skillsets.contains(skillset)){
skillsets.remove(skillset);
} else {
System.out.println(skillset + " is not in your skills list.");
}
}
// Override the compareTo function
#Override
public int compareTo(LinkedInUser user) {
int i = this.getUsername().compareToIgnoreCase(user.getUsername());
return i;
}
}
And the class to add a skillset:
package edu.institution.actions.asn7;
import java.util.Scanner;
import edu.institution.ApplicationHelper;
import edu.institution.UserRepository;
import edu.institution.actions.MenuAction;
import edu.institution.asn2.LinkedInUser;
public class AddSkillsetAction implements MenuAction {
#Override
public boolean process(Scanner scanner, UserRepository userRepository, LinkedInUser loggedInUser) {
String skillset;
System.out.println("Enter a skillset to add to your list:");
skillset = scanner.nextLine();
loggedInUser.addSkillset(skillset);
System.out.println(skillset + " has been added to your skillsets.");
ApplicationHelper.incrementSkillsetCount(skillset);
return true;
}
}
After I run and try to add a skillset, I get this error:
Exception in thread "main" java.lang.NullPointerException
at edu.institution.asn2.LinkedInUser.addSkillset(LinkedInUser.java:69)
at edu.institution.actions.asn7.AddSkillsetAction.process(AddSkillsetAction.java:19)
at edu.institution.ApplicationController.process(ApplicationController.java:61)
at edu.institution.LinkedInCLI.main(LinkedInCLI.java:39)
LinkedInUser.java:69 is:
skillsets.add(skillset);
By the way… Your naming is confusing. String skillset; should be String skill, and .addSkill not .addSkillset, because you are adding individual skills rather than adding a set.
Clarifying your naming may clarify your code. Notice the singular skill and plural skills naming used in code below.
You did not provide enough details to diagnose the problem. But I can show you some example code based on your descriptions.
Your problem may be related to your not properly instantiating the TreeSet. Notice in this code that you have a choice of at least two places in which to instantiate:
On the declaration line of skills.
In the constructor. (Code currently commented-out.)
The LinkedInUser class.
package work.basil.linkedin;
import java.util.NavigableSet;
import java.util.Set;
import java.util.TreeSet;
public class LinkedInUser
{
private String name;
private NavigableSet < String > skills = new TreeSet <>();
// Constructor
public LinkedInUser ( final String name )
{
this.name = name;
// this.skills = new TreeSet <>() ;
}
// Modifiers
public void setName ( String name ) { this.name = name; }
public void addSkill ( String skill ) { this.skills.add( skill ); }
// Getters
public String getName ( ) { return name; }
public Set < String > getSkills ( ) { return Set.copyOf( this.skills ); } // Return a unmodifiable copy of the set. (defensive programming)
}
For defensive programming, we return a copy of the set. This unmodifiable copy returned by Set.copyOf has no order. In some implementations, the order may even change arbitrarily for each iterator. If you want to return an ordered NavigableSet instead, do this:
Change the return type of the method to NavigableSet.
Change the code to pass the instance’s set to the constructor of another set.
public NavigableSet < String > getSkills ( ) { return new TreeSet <>(this.skills ); }
Usage.
LinkedInUser alice = new LinkedInUser( "Alice" );
LinkedInUser bob = new LinkedInUser( "Bob" );
alice.addSkill( "Yodeling" );
alice.addSkill( "Tap Dancing" );
bob.addSkill( "Juggling" );
System.out.println( alice.getName() + " does " + alice.getSkills() );
System.out.println( bob.getName() + " does " + bob.getSkills() );
System.out.println( List.of( alice , bob ) );
When run.
Alice does [Yodeling, Tap Dancing]
Bob does [Juggling]
[LinkedInUser{name='Alice', skills=[Tap Dancing, Yodeling]}, LinkedInUser{name='Bob', skills=[Juggling]}]
You said:
I thought instantiating the Set with:
private Set<String> skillsets = new TreeSet<>();
Yes, that would indeed instantiate a TreeSet object, and store a reference to that set in a variable named skillsets. I expect you are placing that code in the wrong location. Again, look at the two locations I suggested earlier in this Answer: on declaration line, or in constructor.

Java de-serialization backward compatibility

How can I deserialize a class which was modified after serialization?
More specifically, I know this can be done when a class had serialVersionUID in its initial version. Is there any way to do it for classes without serialVersionUID?
I have an object
package com.test.serialize;
import java.io.Serializable;
public class MyObject implements Serializable{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and I serialize classes like this
package com.test.serialize;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializeTest {
public static void main(String[] args) {
try {
MyObject myObject = new MyObject();
myObject.setName("Ajit");
ObjectOutputStream objectOStr = null;
ByteArrayOutputStream byteOStr = null;
try {
byteOStr = new ByteArrayOutputStream();
objectOStr = new ObjectOutputStream(byteOStr);
objectOStr.writeObject(myObject);
} catch (IOException e) {
System.out.println(e);
} finally {
try {
if (objectOStr != null)
objectOStr.close();
} catch (IOException e2) {
}
}
FileOutputStream fo = new FileOutputStream(new File("serialize"));
fo.write(byteOStr.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and deserialize like this
package com.test.serialize;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.RandomAccessFile;
public class DeserializeTest {
public static void main(String[] args) {
try {
// File f = new File("serialize");
// FileInputStream fs = new FileInputStream(f);
RandomAccessFile raF = new RandomAccessFile("serialize", "r");
byte[] b = new byte[(int)raF.length()];
raF.read(b);
ObjectInputStream oIstream = null;
ByteArrayInputStream bIstream = null;
bIstream = new ByteArrayInputStream(b);
oIstream = new ObjectInputStream(bIstream);
Object finalResult = oIstream.readObject();
System.out.println(finalResult.toString());
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
After some time, I added
#Override
public String toString() {
return "MyObject [name=" + name + ", names=" + names + "]";
}
to MyObject. After adding that I got exceptions like
java.io.InvalidClassException: com.test.serialize.MyObject; local class in
compatible: stream classdesc serialVersionUID = 5512234731442983181, local class
serialVersionUID = -6186454222601982895
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:617)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1622)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at com.test.serialize.DeserializeTest.main(DeserializeTest.java:25)
Please help me with this.
Thanks #Gábor Bakos.
This can be solved by creating serialVersionUID for older class (Which signatures should be same as the one during serialization )and adding that serialVersionUID in current class.
serialver -classpath /***PATH***/bin com.test.serialize.MyObject
That returns
com.test.serialize.MyObject: static final long serialVersionUID = 5512234731442983181L;
After that I have added it to my MyObject as below
package com.test.serialize;
import java.io.Serializable;
public class MyObject implements Serializable{
/**
* Added serial version Id of old class, created before adding new fields
*/
private static final long serialVersionUID = 5512234731442983181L;
public MyObject() {
System.out.println("Constructor");
}
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String names ="Altered after change!";
public String getNames() {
return names;
}
public void setNames(String names) {
System.out.println("Setting names");
this.names = names;
}
#Override
public String toString() {
return "MyObject [name=" + name + ", names=" + names + "]";
}
}
It works fine.
More info refer: serialver
First advice: use serialization, because everything is almost done.
Second advice: use a serialVersionUID and keep it fix with one version: it is here to warn you and prevent confusion between different serialized versions.
So : if you change fields or meaning of fields, change the serialVersionUID.
Then you have your backward compatibility problem.
See this for many ideas: Managing several versions of serialized Java objects
IMHO:
whatever solution you take, keep in mind that your program will be managing objects with partial datas: then you have to manage all cases with or without datas.
if you dont change often your version: use several different classes. Perhaps subclasses, or implementations of an interface: then you can get your program, and you manage several versions of object: MyClass_V1, MyClass_V2, etc. When you deserialize, you can test/retry and get the good Object. After that, you perhaps have to convert datas between your classes
if you change your version, by adding new fields (not changing old fields), it is a little more easy (subclasses, converting is direct to parents)
or you could consider use a XML structure to serialize and deserialize: you can have backward and forward compatibility because it is extensible: fields are there, or are null. You have to manage mapping yourself or use some libraries.
Hope it helps !
I would remember following points,
Every Serializable class contains a serialVersionUID ( it doesn't matter if you have specified the one explicitly or not ).
There are compatible changes and there are incompatible changes
e.g. adding a new field is a compatible change, removing a field is not a compatible change. Adding / removing / editing a method are generally compatible changes but in your case surely that is not the way it is ( serialVersionUID got changed after you added toString() method)
3.Prior to modify the class, you can use serialver utility to find serialVersionUID of old class and use that in new class
Don't think there are any other magic tricks :)

Printing contents from an arraylist

so I'm trying to figure out how to print the actual contents, not memory locations, of my array list
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class hw2redo
{
public static void main(String args[]) throws FileNotFoundException
{
//Scan file for data
GeometricObject g = null;
BufferedReader file = new BufferedReader(new FileReader("file.txt"));
Scanner diskScanner = new Scanner(file);
//Create dynamic array list
ArrayList<GeometricObject> list = new ArrayList<GeometricObject>();
//Scan data and add data to list
while(diskScanner.hasNext())
{
String geolist = diskScanner.nextLine();
g = recreateObject(geolist);
list.add(g);
}
showObjects(list);
}
private static GeometricObject recreateObject(String data)
{
GeometricObject object = new GeometricObject(data);
return object;
}
private static void showObjects(ArrayList<GeometricObject> list)
{
for(GeometricObject o : list)
System.out.println(o);
}
}
class GeometricObject
{
public GeometricObject(String data) {
// TODO Auto-generated constructor stub
}
}
So here is my code. I have tried using the toString() and Arrays.toString() but they dont seem applicable for an arraylist (I tried because they worked on my regular arrays).
The output I'm recieving is
// Output
GeometricObject#55f96302
GeometricObject#3d4eac69
GeometricObject#42a57993
GeometricObject#75b84c92
GeometricObject#6bc7c054
GeometricObject#232204a1
which is good because I'm close, I just need to figure out how to print the actual contents.
The content I'm looking for in my file.txt is
Circle,green,false,4.0
Circle,blue,false,2.0
Circle,blue,true,7.0
Rectangle,orange,true,10.0,6.0
Rectangle,green,false,5.0,11.0
Rectangle,red,true,14.0,12.0
Any help would be much appreciated. Thanks!
You need a toString method in your class:
class GeometricObject
{
private String data;
public GeometricObject(String data) {
this.data = data;
}
#Override
public String toString() {
return data;
}
}
Without the Override, you are using Object.toString(). Object's toString prints out the class name and the hashcode of the object, as you have observed.
System.out.println(o);
When you call System.out.println, That apparently calls the toString() method of your Object. Since you didn't ovveride toString(), it calls the default implementation. Ovveride toString() method to print as you wish.
public class GeometricObject {
....
#Override
public String toString() {
// return string representation of your object.
}
}
To starts with :What is the best standard style for a toString implementation?

strange output from ArrayList [duplicate]

This question already has answers here:
what is the number that it shows when I print out the **this** pointer in java?
(9 answers)
Closed 7 years ago.
I'm new to Java and i'm having an issue with objects in ArrayList.
I'm trying to put a object with a text and a timestamp in a ArrayList.
At the start it behaves correctly, so you can type your notes in and if you type "exit" it closes the Input and shows all entries from the ArrayList.
But if i type "exit" it just shows me this output:
Notizblock#4c15c0d7
This is my code:
import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Scanner;
import java.util.ArrayList;
class Notizblock {
//heutiges Datum erzeugen
private static String getDateTime() {
DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyy HH:mm:ss");
Date datum = new Date();
return dateFormat.format(datum);
}
private String text;
private String datum;
//Konstruktor
public Notizblock(String text, String datum){
this.text = text;
this.datum = datum;
}
public void print() {
System.out.println("Datum: "+datum+" Text: "+text);
}
public static void main(String[] args) {
ArrayList<Notizblock> notizen = new ArrayList<Notizblock>();
Scanner eingabe = new Scanner(System.in);
while (true) {
System.out.println("Notiz eingeben:");
String a = eingabe.next();
if (a.equals("exit")) {
break;
}
notizen.add(new Notizblock(a, getDateTime()));
}
System.out.println("alle notizen:");
for (Notizblock notiz :notizen ) {
System.out.println(notiz);
}
}
}
I'm glad if anyone could tell me what i'm doing wrong, I'm open for every improvment to my code.
Hit me up if you need some more Information.
Thanks
P.S. I'm german, sorry for my bad english ;)
You need to override toString method. The Notizblock is a custom class, the default System.out will be classname#hashcode of the object, which is what you are seeing.
once you override the toString it will print the content of the object as per your toString implementation. Here is a sample:
#Override
public String toString() {
return "Notizblock {" +
"text='" + text + '\'' +
", datum='" + datum + '\'' +
'}';
}
Yes. You can call the existing print method which you have defined.
System.out.println("alle notizen:");
for (Notizblock notiz :notizen ) {
System.out.println(notiz.print());
}
The toString() is called automatically when you print (SOUT) anything. That is why overriding toString() will be a better approach then providing a custom method for doing the same job, unless you are doing some extra/special formatting of the data.

ClassCastException when Treeset.add(), despite implementing comparable with compareTo method

I have a class Contact that I have displayed below. I want each Contact object to have a list of other Contacts. I chose a TreeSet because I'd like to avoid duplicate Contacts in the same list. My Contact class implements Comparable and has a constructed compareTo() method that compares instance String variables. I understand the compareTo method is used when adding to a TreeSet because added elements are immediately sorted.
When I try to add a Contact object from a Contact[] (see my setContacts() method below) to my TreeSet, I receive a ClassCastException. My system.out messages is:
Exception in thread "main" java.lang.ClassCastException: shared.Contact cannot be cast to java.lang.String
at java.text.Collator.compare(Unknown Source)
at java.util.TreeMap.compare(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at java.util.TreeSet.add(Unknown Source)
at shared.Contact.setContacts(Contact.java:51) <-- right here is the TreeSet.add()
at server.Server.readInContacts(Server.java:191)
at server.Server.main(Server.java:51)
What I do not understand is that nowhere in any of the classes I have built do I try to convert anything into a String. Below is my entire Contact class.
Does anyone see anything wrong or see why the exception is occuring?
I'd be happy to post more code if someone tells me what else might be relevant. I don't know what else would be important to see. Thanks in advance.
package shared;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.Collator;
import java.util.LinkedList;
import java.util.TreeSet;
public class Contact implements Serializable, Comparable<Contact>{
private static final long serialVersionUID = 1L;
private String name;
private boolean online;
private TreeSet<Contact> contacts;
private ObjectOutputStream oos;
private ObjectInputStream ois;
public Contact(String name){
this(name, null, null);
}
public Contact (String name, ObjectInputStream ois, ObjectOutputStream oos){
this.name = name;
this.ois = ois;
this.oos = oos;
contacts = new TreeSet<Contact>(Collator.getInstance());
}
public String getName(){
return name;
}
public void logIn(ObjectInputStream ois, ObjectOutputStream oos){
this.ois = ois;
this.oos = oos;
}
public ObjectInputStream getObjectInputStream(){
return ois;
}
public ObjectOutputStream getObjectOutputStream(){
return oos;
}
public void setOnlineStatus(boolean status){
online = status;
}
public boolean isOnline(){
return online;
}
public void setContacts(Contact[] contacts){
this.contacts.clear();
for (Contact c: contacts){
this.contacts.add(c); <-- right here is where my exception occurs
}
}
#Override
public int compareTo(Contact c){
return this.name.compareTo(c.getName());
}
public boolean equals(Object o){
Contact c = (Contact)o;
return this.name.equals(c.getName());
}
public void addContact(Contact c){
LinkedList<Contact> list = new LinkedList<Contact>();
for (Contact contact: contacts){
list.add(contact);
}
}
public Contact[] getContacts(){
return contacts.toArray(new Contact[0]);
}
public int hashCode(){
return name.hashCode();
}
public String toString(){
return this.name;
}
}
The answer is right here in Collator.java:
public int compare(Object o1, Object o2) {
return compare((String)o1, (String)o2);
}
It's not immediately obvious to me but why on Earth are you passing in your own Collator?
Are you dealing with Non ascii?
You also have a inconsistency here: compareTo() == 0 SHOULD be the same as equals() especially since in both cases the only thing you seem to care about is 'name'
So, on the one hand you state you want to remove identical entries and thus you use Comparative identity but then you use a Collator which can definitely produce inconsistent results with equals.
If all you want is remove redundancy than skip the Collator and either use HashSet or TreeSet with no Collator
Alternatively if you MUST use Collated names then use a
TreeMap<String,Contact> contacts = new TreeMap<String,Contact>(Collator.getInstance());
contacts.put(contact.getName(),contact);
You can then use:
Collection<Contact> uniqueContacts = contacts.values();
c.getName() return a String and then you call the equals with this.. so a String is passed to equals...
first line of equals try to cast the String into a Contact... Boom
The compare method will call equals on the object it try to compare.

Categories