I posted about this application yesterday, but now I'm having a different problem. I'm currently working on this application for tracking track (tracking track?) day runs and displaying a leaderboard. This is for a class so I'm not looking for code necessarily, just some thoughts on how to go about it. Anyway, the application currently will take input information (from the bottom textfields), create a TreeSet of RaceEntrant objects (class shown below), and create a queue on the right which is emptied as the participants go through their runs. The problem is, I need the TreeSet to be sorted in the (grey) leaderboard area from smallest to largest runTime and update while the times are entered at the top. I'm kind of unsure how to have it sort the objects specifically by the runTime. Any help is appreciated.
RaceEntrant Class
class RaceEntrant
{
private String name,
car;
private double runTime;
public RaceEntrant(String name, String car)
{
this.name = name;
this.car = car;
}
public String getName()
{
return name;
}
public String getCar()
{
return car;
}
public double getTime()
{
return runTime;
}
public void setTime(double time)
{
this.runTime = time;
}
#Override
public String toString()
{
StringBuilder sb = new StringBuilder("");
sb.append(getName());
sb.append(" ");
sb.append(getCar());
sb.append("\n" );
sb.append("Best time: " + getTime() + "\n");
return sb.toString();
}
}
This is an example of the current operation - the RaceEntrant(s) are displayed in order of their runs, not sorted by anything. I apologize for the lengthy post.
Your class, RaceEntrant, should implements Comparable, and you can control order in the implemented method compareTo.
Your class could look like this:
class RaceEntrant implements Comparable<RaceEntrant>
{
private final String name,
car;
private double runTime;
public RaceEntrant(final String name, final String car)
{
this.name = name;
this.car = car;
}
public String getName()
{
return name;
}
public String getCar()
{
return car;
}
public double getTime()
{
return runTime;
}
public void setTime(final double time)
{
this.runTime = time;
}
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder("");
sb.append(getName());
sb.append(" ");
sb.append(getCar());
sb.append("\n" );
sb.append("Best time: " + getTime() + "\n");
return sb.toString();
}
#Override
public boolean equals(final Object obj) {
if(this == obj) return true;
if (obj instanceof RaceEntrant){
return (((RaceEntrant) obj).getTime() == runTime) && ((RaceEntrant) obj).getName().equals(name) && ((RaceEntrant) obj).getCar().equals(car);
}
return false;
}
#Override
public int hashCode() {
return new Double(runTime).intValue();
}
#Override
public int compareTo(final RaceEntrant o) {
return new Double(o.runTime).compareTo(this.runTime)*-1;
}
}
In your RaceEntrant class:
class RaceEntrant implements Comparable<RaceEntrant>{
//..
public int compareTo(RaceEntrant re){
return getTime().compareTo(re.getTime());
}
#Override //optional for Sets
public boolean equals(Object o){
If(o != null && o instanceOf RaceEntrant){
RaceEntrant entrant = (RaceEntrant)o;
return getName().equals(entrant.getName() &&
getCar().equals(entrant.getCar()) &&
getTime() == entrant.getTime();
}
}
}
Then you can sort your List (probably ArrayList) by runTime.
You could also use a TreeSet (this should be sorted automatically) and define a equals method on runTime + name + car if that's a possible approach.
I guess the TreeSet is not the right data structure. A TreeSet is above all a Set -- which keys are considered unique based on comparison.
I think you can have identical run times?
Maybe just use an ArrayList and sort it using Collections.sort() with a custom Comparator.
Related
I have a multitude of objects that are created with multiple instance variables (a string a multiple integers)
I have to create a method that will check for equality between the object that executes the method and another object. By that I mean that I would want to see whether all the instance variables are the same for two objects by calling a method. I'm thinking of something like the equals method (string1.equals(string2)), but can I do the same for an object with multiple instance variables which are not all strings?
example:
//object1
String name1= keyb.nextLine();
int age1= keyb.nextInt();
int monthborn1;
//object2
String name2=keyb.nextLine();
int age2 = keyb.nextInt();
int monthborn2;
I need to make a method that compare both objects and sees if they are equal or not.
Thank you very much.
Yes, you can create an equals method for your class. For example:
public final class Person {
private final String name;
private final int age;
private final int birthMonth;
public Person(String name, int age, int birthMonth) {
this.name = Objects.requireNonNull(name);
this.age = age;
this.birthMonth = birthMonth;
}
#Override
public boolean equals(Object o) {
if (o instanceof Person) {
Person rhs = (Person) o;
return name.equals(rhs.name)
&& age == rhs.age
&& birthMonth == rhs.birthMonth;
}
return false;
}
// Any time you override `equals`, you must make a matching `hashCode`.
// This implementation of `hashCode` is low-quality, but demonstrates
// the idea.
#Override
public int hashCode() {
return name.hashCode() ^ age ^ birthMonth;
}
}
In Java you usually have to manually check every field like this:
class MyObject {
String name;
int age, monthborn;
public boolean isEqual(MyObject other) {
return Objects.equals(name, other.name) &&
age == other.age && monthborn == other.monthborn;
}
}
Objects.equals is used here which is null-safe equivalent of name.equals(other.name). When you add new fields you will have to add new checks in your method as well. The alternative would be to utilize reflection, but it looks ugly and has significant performance drawback. Here's a draft example how to do this (do not take into account possible inheritance):
import java.lang.reflect.Field;
import java.util.Objects;
public class ObjectUtil {
public static <T> boolean allFieldsEqual(T o1, T o2) throws IllegalAccessException {
if(o1 == o2) return true;
if(o1.getClass() != o2.getClass()) return false;
for(Field field : o1.getClass().getDeclaredFields()) {
field.setAccessible(true);
if(!Objects.equals(field.get(o1), field.get(o2))) {
return false;
}
}
return true;
}
}
class MyObject {
String name;
int age, monthborn;
public boolean isEqual(MyObject other) {
try {
return ObjectUtil.allFieldsEqual(this, other);
} catch (IllegalAccessException e) {
return false;
}
}
}
This way upon adding the new field the isEqual method will take it into account as well. However I would not recommend such solution.
Please see this answer . Also, since you are overriding the equals method you should also override the hashcode method (also covered in the linked post)
Once you compare two objects you have to consider about all the members of the class.
We will assume that we have a class named B and with two member variables age and name.
class B :
public class B {
String name;
int age;
public B(String name, int age) {
this.age = age;
this.name = name;
}
}
Then lets compare the two different objects of same class using equals and hashcode methods which are inherited to our class B from Object class.
class A to compare :
public class A {
public static void main(String args[]){
B b1 = new B("a", 22);
B b2 = new B("a",22);
System.out.println(b1.equals(b2));
System.out.println(b1.hashCode());
System.out.println(b2.hashCode());
}
}
As soon as we compile and run class A we will get following out-puts.
false
705927765//returns int value
366712642//returns int value
But here in the class A we have passed same parameters to both objects of the B. Which means we are getting what we did not expect because of equals and hashcode methods which are in Object class not doing what we need.
So in this case we have to override these methods in our class B to make it success.
Class B after override done:
public class B {
String name;
int age;
public B(String name, int age) {
this.age = age;
this.name = name;
}
#Override
public boolean equals(Object obj) {
boolean flag = false;
if (obj instanceof B) {
B b = (B) obj;
if (this.age == b.age) {
if (this.name.charAt(0)==b.name.charAt(0))) {
flag = true;
} else {
flag = false;
}
} else {
flag = false;
}
} else {
flag = false;
}
return flag;
}
#Override
public int hashCode() {
return this.age+this.name.charAt(0);
}
}
If we run our class A again we could get follwing result :
true
119
119
Which means our work is done.
I got two "lists" of objects, which i want to compare if elements are equal. If they are not equal, the loop should take the not equal object and put it into the other list. Very simple. My problem is: the equals method doesnt work as intended.
Here is the object Class with my custom equals method:
public class Profil {
private String vorname;
private String name;
private String adLoginBenutzer;
public Profil() {
}
public String getAdLoginBenutzer() {
return adLoginBenutzer;
}
public void setAdLoginBenutzer(String adLoginBenutzer) {
this.adLoginBenutzer = adLoginBenutzer;
}
public String getVorname() {
return vorname;
}
public void setVorname(String vorname) {
this.vorname = vorname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
if (name == null || vorname == null) {
return "<keiner>";
}
return vorname + ", " + name + " " + adLoginBenutzer;
}
#Override
public boolean equals(Object obj) {
if (getClass() != obj.getClass()) {
return false;
}
Profil other = (Profil)obj;
if(!this.getVorname().equals(other.getVorname()) || !this.getName().equals(other.getName()) || !this.getAdLoginBenutzer().equals(other.getAdLoginBenutzer()))
{
return false;
}
return true;
}
}
And here is the loop: (note: I basically want to merge the list into a comboboxmodel, if the profil-object is not equal than it should add it to the first position in the comboboxmodel)
public void putProfilesIntoCbx(HashSet<Profil> profile)
{
DefaultComboBoxModel<Profil> cbx = (DefaultComboBoxModel <Profil>)cbBearbeiter.getModel();
for(Profil p : profile)
{
for(int i = 0; i< cbx.getSize(); i++)
{
if(!p.equals(cbx.getElementAt(i)))
{
cbx.insertElementAt(p, 0);
}
}
}
cbBearbeiter.setModel(cbx);
}
I debugged the code and took breakpoints at the last if of the equals method. Although there are equal objects, the last if return false for no reason even if the objects are really equal. Even if i invert the equals if-statement it does not work.
As everyone is saying, there is a relationship between the equals() method and the hashcode() method.
If you #Override the equals() method, you need to #Override the hashcode() method as well
Hello my goal is to get the user to input some customerID value and some videoID how would I check to make sure the user inputs a correct customerID and videoID in my array I have made for these fields and tell the user they have inputted the wrong ID. This is what i have so far for my code
public static void HireVideo(){
System.out.println("Enter Customer ID");
String customerID = sc.next();
System.out.println("Enter Video ID");
String videoID = sc.next();
HireList.add(new Hire(customerID, videoID));
}
in an effort to be as close to your code as possible (i.e. what I assume is a static list wrapper class).
public class HireList {
private static List<Hire> hires = new ArrayList<Hire>();
public static void add(Hire hire) {
hires.add(hire);
}
public static boolean contains(Hire other) {
return hires.contains(other);
}
}
the magic however happens in the Hire class:
public class Hire {
private String customerId;
private String videoId;
public Hire(String customerId, String videoId) {
this.customerId = customerId;
this.videoId = videoId;
}
#Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.customerId);
hash = 67 * hash + Objects.hashCode(this.videoId);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
final Hire other = (Hire) obj;
if (!this.customerId.equals(other.customerId)) {
return false;
}
if (!this.videoId.equals(other.videoId)) {
return false;
}
return true;
}
}
List<T>.contains(T other) uses the equals method of T, therefore overriding it will allow us to control the behavior of contains.
test:
public static void main(String[] args) {
HireList.add(new Hire("1", "1"));
HireList.add(new Hire("2", "2"));
System.out.println(HireList.contains(new Hire("2", "2"))); //output: true
}
if contains is all you are concerned with though I would suggest using a HashSet as opposed to a ArrayList.
I would like an object to be comparable (to use it in a TreeSet in that case).
My object got a name field and I would like it to be sorted by alphabetical order.
I thought first that I could use the unicode value of the string and simply do a subtraction, but then AA would be after Ab for example…
Here’s how I started :
public final class MyObject implements Comparable<MyObject> {
private String name;
public MyObject(String name) {
this.name = name;
}
public String name() {
return name;
}
#Override
public int compareTo(MyObject otherObject) {
return WHAT DO I PUT HERE ?;
}
}
Thanks to those who will help,
have a nice day!
You are overthinking the problem. Strings have their own natural ordering, which is alphabetic, so you can just use the String.compareTo like this:
#Override
public int compareTo(MyObject otherObject) {
return this.name.compareTo(otherObject.name);
}
return name.compareTo(otherObject.name);
String already implements Comparable so you don't need do to anything.
I think you want something like this
package mine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class MyObject {
private String name;
public MyObject(String name) {
this.name = name;
}
public MyObject() {
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "MyObject [name=" + name + "]";
}
public static void main(String[] args){
List<MyObject> l = new ArrayList<>();
l.add(new MyObject("Ab"));
l.add(new MyObject("AA"));
l.add(new MyObject());
Collections.sort(l, new Comparator<MyObject>(){
#Override
public int compare(MyObject o1, MyObject o2) {
if (o1.name == null && o2.name == null){
return 0;
}else if (o1.name == null){
return -1;
}else if (o2.name == null){
return 1;
}else{
return o1.name.toUpperCase().compareTo(o2.name.toUpperCase());
}
}
});
System.out.println(l);
}
}
Exist so many way which preferred before it. But for maintain better compatibility, performance and avoiding runtime exceptions (such as NullPointerException) use best practices which is
For String
#Override
public int compareTo(OtherObject o) {
return String.CASE_INSENSITIVE_ORDER.compare(this.name,o.name);
}
For int, double float (to avoid boxing and unboxing which issue for performance use below comparators)
// with functional expression
Comparator.compareInt, Comparator.compareDouble, Comparator.compareFloat
// or with static compare method
/**
* Integer
*/
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
/**
* Double
*/
public int compareTo(Double anotherDouble) {
return Double.compare(value, anotherDouble.value);
}
/**
* Float
*/
public int compareTo(Float anotherFloat) {
return Float.compare(value, anotherFloat.value);
}
/**
* Objects
*/
public int compareTo(Object other) {
return Object.compare(value, other.value);
}
[Effective Java Item 14: Consider implement Comparable]
Finally, whenever you implement a value class that has a sensible ordering, you should have a class implements Comparable interface so that its instances can be easily sorted, searched and used in comparison-based collections. When comparing field values in the implementations of the compareTo methods, avoid the use of the < and > operators. Instead, use the static compare methods in the boxed primitive classes or the comparator construction methods in the Comparator interface
I have the classes below:
public class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
//This POJO does not override equals() and hashCode()
}
public class B{
private Sample sample;
//here i need override hashcode and equals() based on **sample** property.
}
When i tried overriding equals() and hashCode() in the B class I got the error below in Eclipse.
The field type com.mypackage.Sample does not implement hashCode() and equals() - The resulting code may not work correctly.
Now how can I compare two B instances whether equals or not based on the Sample property?
I cannot modify Sample class.
are you looking something like following? Just try it, as from your question i think you want to compare contents of your Sample class also.
class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//This POJO does not override equals() and hashCode()
}
public class Beta implements Comparable{
private Sample sample;
public Sample getSample() {
return sample;
}
public void setSample(Sample sample) {
this.sample = sample;
}
#Override
public int compareTo(Object o) {
if(!(o instanceof Beta)){
return -1;
}
}if(((Beta)o).getSample().getName().equals(this.sample.getName())){
return 0; // return true if names are equal
}
if(((Beta)o).getSample().getId().equals(this.sample.getId())){
//if name are notequal and IDs are equal, do what you need to do
}
return -1;
}
public static void main(String[] args) {
Beta b = new Beta();
Sample s = new Sample();
s.setId(10);
s.setName("Name1");
b.setSample(s);
Beta b2 = new Beta();
Sample s2 = new Sample();
s2.setId(20);
s2.setName("Name2");
b2.setSample(s2);
System.out.println(b2.compareTo(b));
Beta b3 = new Beta();
Sample s3 = new Sample();
s3.setId(10);
s3.setName("Name1");
b3.setSample(s3);
System.out.println(b3.compareTo(b));
}
}
Overriding approach
class Sample implements java.io.Serializable{
//POJO with two fields and getters/setters
private String name;
private Integer id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//This POJO does not override equals() and hashCode()
}
public class Beta /*implements Comparable*/{
private Sample sample;
public Sample getSample() {
return sample;
}
public void setSample(Sample sample) {
this.sample = sample;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Beta other = (Beta) obj;
if ((this.getSample() == null) && (other.getSample() == null)){
return true;
}
if ((this.getSample().getId().equals(other.getSample().getId())) && (this.getSample().getName().equals(other.getSample().getName()))) {
return true;
}
return false;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.getSample().getName() != null ? this.getSample().getName().hashCode() : 0);
hash = 53 * hash + (this.getSample().getId() != null ? this.getSample().getId().hashCode() : 0);
return hash;
}
/* #Override
public int compareTo(Object o) {
if(!(o instanceof Beta)){
return -1;
}
if(((Beta)o).getSample().getId().equals(this.sample.getId()) && ((Beta)o).getSample().getName().equals(this.sample.getName())){
return 0;
}
return -1;
}*/
public static void main(String[] args) {
Beta b = new Beta();
Sample s = new Sample();
s.setId(10);
s.setName("Name1");
b.setSample(s);
Beta b2 = new Beta();
Sample s2 = new Sample();
s2.setId(20);
s2.setName("Name2");
b2.setSample(s2);
System.out.println(b2.equals(b));
Beta b3 = new Beta();
Sample s3 = new Sample();
s3.setId(10);
s3.setName("Name1");
b3.setSample(s3);
System.out.println(b3.equals(b));
}
If you don't explicitly override .equals(), they will be compared based solely off of their references (despite not having a equals(), every object inherits one from Object). If you only want B to be compared based off of Sample, then simply do the following:
#Override
public boolean equals(Object o)
{
if (o istanceof B)
{
return sample.equals(o.sample)
}
return false;
}
Additionally, you should then override hashCode() (and compareTo()) to maintain the contract between equals() and hashCode(). Hence, you should also have the following:
#Override
public int hashCode()
{
return sample.hashCode();
}
EDIT (in response to comment):
My requirement is first i need to check equals property against "name"
property of Sample. IF names are equals then both objects are equal.
If names are not equals then i need to check for equality against "ID"
property of Sample. How can i do that? Thanks!
Determining whether Samples are equivalent should be handled in Sample, by overriding equals(). If equals() for Sample bases off of name and id, then you're fine. If you want to compare Samples in B differently than they are normally compared, then you're not going to be able to maintain the contract between equals() and hashCode() for B if you use hashCode() or equals() from Sample, which means that your hashCode() and equals() for B should be cannot call equals() or hashCode() from Sample. See this tutorial for how to override based on specific fields.