I am simply trying to write an equals method that compares students names and sections. If the names and sections are the same, then the equals method should print true. Otherwise it should print false.
Below is what I have so far.
public class Student {
private String name;
private int section;
public Student(String name, int section) {
this.name = name;
this.section = section;
}
public boolean equals(Object y) {
if (this.name.equals(y.name) && this.section.equals(y.section)) {
return true;
}
else {
return false;
}
}
}
The error is with y.name and y.section. Eclipse tells me name and section cannot be resolved to a field.
My question is, can anybody show me how to fix my code so that I can compare student names and sections using the .equals() method?
#Override // you should add that annotation
public boolean equals(Object y) {
Your y is any Object, not necessarily a Student.
You need to have code like
if (y == this) return true;
if (y == null) return false;
if (y instanceof Student){
Student s = (Student) y;
// now you can access s.name and friends
Hmm.. I'm not sure, but I think Eclipse should this function too - 'add standard equals method' - use it and then your IDE generate absolutely right equals method... But it is about coding speed optimization. Now let's tell about equals method. Normally equals method contract defines transitiveness on itself... So if a equal to b then b equal to a. In this case it is recommended to have strict restrictions:
public boolean equals(Object x) {
if (x == this) {
return true; // here we just fast go-out on same object
}
if (x == null || ~x.getClass().equals(this.getClass())) {
return false; // in some cases here check `instanceof`
// but as I marked above - we should have
// much strict restriction
// in other ways we can fail on transitiveness
// with sub classes
}
Student student = (Student)y;
return Objects.equals(name, student.name)
&& Objects.equals(section, student.section);
//please note Objects - is new (java 8 API)
//in order of old API usage you should check fields equality manaully.
}
You are missing to type cast Object to Student class;
Student std = (Student)y;
Related
The criteria is that equals() method where the objects are considered equal if the value of the double variable is within +/- 10 of the other object's value of the double variable.
I'm not sure how to correctly implement hashCode() so that the hashCode would be equal if it satisfies the conditions of the equals() method.
I would really appreciate your input! Thanks!
public class Test
{
private double value;
private boolean isEqualValues (final double valueOne, final double valueTwo)
{
if(valueOne == valueTwo)
{
return true;
}
else if((valueOne - valueTwo <= 10) &&
(valueOne - valueTwo >= -10))
{
return true;
}
else
{
return false;
}
#Override
public boolean equals(final Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
Test test = (Test) o;
if(isEqualValues(test.value, value))
{
return true;
}
else
{
return false;
}
}
//How to implement hashCode()
#Override
public int hashCode()
{
//unsure how to correctly implement hashCode() so that the hashCode would be equal if it
//satisfies the conditions of the equals() method above
}
}
There's no way to consistently implement this, since equals() demands transitivity:
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
new Test(1), new Test(9) and new Test(14) would fail that test (assuming a trivial one-argument constructor that assigns its argument to value).
One way to work around that is to not check for the absolute distance, but "categorize" your objects using some formula, for example take the floor of value / 10 and compare that.
This way some "close" values like new Test(9) and new Test(11) would compare as not-equal, but other than that you'd get a similar result to what you described.
private long getEquivalenceGroup() {
return Math.floorDiv((long) value, 10);
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Test test = (Test) o;
return test.getEquivalenceGroup() == this.getEquivalenceGroup();
}
#Override
public int hashCode()
{
return Long.hashCode(getEquivalenceGroup());
}
As long as getEquivalenceGroup() is implemented in a stable manner this will produce "groups" of slightly different objects that still compare as equal and has a valid hashCode() implementation.
Note: if you want a comparison as described in the question but you don't necessarily need it to be returned by equals() then adding a boolean isClose(Test other) is perfectly fine. The only problem is you are trying to implement the equals method specifically with that semantic.
You can't and you shouldn't.
You should implement a comparator and do such operations using that.
I am currently trying to get a List with unique values.
Technically, it should be really simple, and the obvious choice would be a HashSet.
However, I want the properties of my "points" to be the uniqueness criteria and not their "IDs".
After that, I wanted to use the stream().distinct() method. Hoping that that one is using the overridden equals method. Sadly, this won't work either.
Any solution/Idea that works for double[] is welcome as well.
PointType Class
public class PointType{
private double x;
private double y;
public PointType(x,y){
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object other){
if(other instanceof PointType && this.x == other.x && this.y==other.y){
return true;
}
return false;
}
}
I am aware of the flaw of double == double. For a minimum sample, it is sufficient.
Now to the issue:
#Test
public void testUniquness(){
Set<PointType>setA = new HashSet<>();
Set<PointType>setB = new HashSet<>();
ArrayList<PointType> listA= new ArrayList<>();
ArrayList<PointType> listB= new ArrayList<>();
PointType p1 = new PointType(1.0,2.0);
PointType p2 = new PointType(1.0,2.0);
PointType p3 = new PointType(2.0,2.0);
PointType p4 = new PointType(2.0,2.0);
// Trying to use the unique properties of a HashSet
setA.add(p1);
setA.add(p2);
setA.add(p1);
setA.add(p2);
setB.add(p1);
setB.add(p2);
setB.add(p3);
setB.add(p4);
//Now with array lists and streams.
listA.add(p1);
listA.add(p2);
listA.add(p1);
listA.add(p2);
listA = (ArraList<PointType>) listA.stream().distinct().collect(Collectors.toList());
listB.add(p1);
listB.add(p2);
listB.add(p3);
listB.add(p4);
listB = (ArraList<PointType>) listB.stream().distinct().collect(Collectors.toList());
assertTrue(p1.equals(p2)); // Test passes
assertTrue(p3.equals(p4)); // Test passes
assertTrue(setA.size() == 2); // Test passes (obviously)
assertTrue(setB.size() == 2); // Test failes. How can I use my custom equality condition?
assertTrue(listA.size() == 2); // Test passes (obviously)
assertTrue(listb.size() == 2); // Test failes. How can I use my custom equality condition?
}
Any help is appreciated.
For sure, a for loop would solve this too. But there has to be a more elegant way.
First issue, your implementation of equals is not correct, this is what it should look like (auto-generated with IntelliJ) :
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PointType pointType = (PointType) o;
return Double.compare(pointType.x, x) == 0 && Double.compare(pointType.y, y) == 0;
}
Second and most important problem, as the word Hash in HashSet suggests, you should not only implement equals but also hashCode, and this is not only true for hash collections but in general (every time you implement equals, you also implement hash code):
#Override
public int hashCode() {
return Objects.hash(x, y);
}
Once you have done these two things, your test using Set<PointType> setB = new HashSet<>() will pass.
You always need to override equals() together hashCode(). This requirement is reflected in the documentation:
API Note:
It is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for
the hashCode method, which states that equal objects must have equal
hash codes.
You can find more information on how to implement equals/hashCode contract properly on SO, and in other sources, for instance, there's a separate item dedicated to this topic in "Effective Java" by Joshua Bloch.
That how the correct implementation might look like (for conciseness I've used Java 16 Pattern matching for instanceof):
public class PointType {
private double x;
private double y;
public PointType(double x, double y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object other) {
return other instanceof PointType o
&& Double.compare(x, o.x) == 0
&& Double.compare(y, o.y) == 0;
}
#Override
public int hashCode() {
return Objects.hash(x, y);
}
}
This question already has answers here:
What is the difference between == and equals() in Java?
(26 answers)
Closed 1 year ago.
I want to compare two objects. However, it tells me they do not match when I run it, even though they do. Please let me know what I am doing wrong, thank you. Here is my code:
Player p1 = new Player("Mo", "Food", 200.0,0.0);
Player p2 = new Player("Mo", "Food", 200.0,0.0);
System.out.println(p1.equals(p2)); // -- false
Your equals() is calling the default Object class's method, which compares the Objects's identity*, that is, p1==p2, not its contents. This is the default equals from Object:
public boolean equals(Object obj) {
return (this == obj);
}
If you want to define your logic in order to decide if two Players are equal, you need to override:
equals() method
hashCode() method to honor the equals-hash contract
class Player {
private String firstName;
private String lastName;
private double score;
private double rating;
// ...
#Override
public int hashCode() {
return Objects.hash(firstName, lastName, score, rating);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
Player other = (Player) obj;
return Objects.equals(firstName, other.firstName) && Objects.equals(lastName, other.lastName)
&& score == other.score && rating == other.rating;
}
// ...
}
Java SE 16
Java 16 Records feature helps you get rid of all this boilerplate code. Most of the ceremonial code mentioned above is automatically available to you with just the following declaration:
record Point(String firstName, String lastName, double score, double rating) { }
If you want to work with Collections:
Implement Comparable -- this won't let you directly compare, but useful for collections
Implement Comparator
If you want to work with Collections, in order to be able to sort, for example, you could implement the Comparable interface. This avoids breaking the equals and hashcode contract, which is pretty difficult to achieve manually.
As Holger comments (he's giving me some lessons today) use this when there's a numeric based ordering involved.
If not, you can use the Comparator interface.
In this example I'm using Comparable:
class Player implements Comparable<Player>
{
#Override
public int compareTo(Player p2)
{
/* Allows returning : (0)-> this==p2 | (1)-> this>p2 | (-1)-> this<p2
Anyway, the meaning of 1 and -1 is up to you.
if (this.name.equals(p2.name) && ...)
return 0;
else if ...
return 1;
return -1; */
}
}
* Thanks to Henry Twist for pointing this out.
with the new record class type this is finally addressed.
record Player(String name, String item, double val1, double val2){}
Player p1 = new Player("Mo", "Food", 200.0, 0.0);
Player p2 = new Player("Mo", "Food", 200.0, 0.0);
System.out.println("equals:"+p1.equals(p2));
System.out.println("==:"+(p1==p2));
will print
equals:true
==:false
I have two arrayLists<myObject>, where myObject is an object of a custom class I've created. I want to be able to compare those arrayLists using the equals() method.
After reading and looking for answers, I've read that certain objects like int[] are only considered equal by the equals() method when they are referencing the same thing.
To fix that, I tried to override the equals method in my custom object. My objects have 3 atributes (all basic types), so my equals method now returns true if all the 3 atributes are equal to those of the object compared, and false otherwise. However, comparing the arraylists still doesn't work. What am I doing wrong?
Excuse me for explaining the code instead of posting it, I do it because the variables and names aren't in English.
EDIT: Ok, here's the code. Compra is my custom class; cantidad,concepto and id are its atributes.
#Override
public boolean equals(Object obj) {
boolean result = true;
if (obj == null) {
result = false;
}else{
Compra comprobada = (Compra) obj;
if(!(this.id == comprobada.getId())){
result = false;
}
if(!(this.cantidad == comprobada.getCantidad())){
result = false;
} if(!this.concepto.equals(comprobada.getConcepto())){
result = false;
}
}
return result;
}
Based on this one :
How can I check if two ArrayList differ, I don't care what's changed
If you have implemented your custom object equals correct (you actually override it and have your one) and the size of the arrayList is the same and each of the pair of the objects is equal then it will return equal. In other words what you are trying to do is totally correct but your arrayLists are not actually having exactly the equal objects in exact order.
Make sure that your equal is called when you check for collection equality by doing a System.out.println() to investigate what is going on.
If you don't mind please send the equals of your object.
I run your code in an isolated example and works fine (outtputs true) - I improved the equals method so it doesn't do so many if checks as if only one of them is not equal it should return false.
class stackoverflow {
public static void main(String args[]){
ArrayList<Compra> array1 = new ArrayList<>();
ArrayList<Compra> array2 = new ArrayList<>();
array1.add(new Compra(1,2,"test"));
array2.add(new Compra(1,2,"test"));
System.out.println(array1.equals(array2));
}
}
class Compra {
int id;
int cantidad;
String concepto;
public Compra(int id, int cantidad, String concepto){
this.id = id;
this.cantidad = cantidad;
this.concepto = concepto;
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}else{
Compra comprobada = (Compra) obj;
if(!(this.id == comprobada.getId())){
return false;
}
if(!(this.cantidad == comprobada.getCantidad())){
return false;
}
if(!this.concepto.equals(comprobada.getConcepto())){
return false;
}
}
return true;
}
public int getId() {
return id;
}
public int getCantidad() {
return cantidad;
}
public String getConcepto() {
return concepto;
}
}
Some things to check:
Are you sure you don't change the order of the things in ArrayList??:
Do you print to make sure that these equals checks happen and return true or false as expected?
Are you sure that concepto Strings are exactly the same, with the same case and don't contain extra spaces etc?
As you haven't posted code i suggest you to check into Comparable class and method compareTo and how to use it for custom classes.
I have 2 classes.
public class klass1 {
String bir;
String myID;
klass1(String bir, String myID)
{
this.bir=bir;
this.myID=myID;
}
}
.
import java.util.*;
public class dd {
public static void main(String[] args) {
ArrayList<Object> ar=new ArrayList();
ar.add(new klass1("wer","32"));
ar.add(new klass1("das","23"));
ar.add(new klass1("vz","45"));
ar.add(new klass1("yte","12"));
ar.add(new klass1("rwwer","43"));
ar.remove(new klass1("vz","45"));//it's not worked!!!
System.out.println(ar.size());
}
}
What I want is removing or getting an object from array list with object's second attribute. How can I do that? Is there an easy way for it?
Just implement the equals method in the class Klass1.
public class Klass1 {
String bir;
String myID;
Klass1(String bir, String myID)
{
this.bir=bir;
this.myID=myID;
}
public boolean equals(Object o){
if(o instanceof Klass1)
return ((Klass1)o).myID.equals(myID);
else
return false;
}
}
Its because you are trying to delete a new object which isnt in the arraylist. When you use new klass1("vz","45") you are creating a new instance of this class which isnt in the arraylist.
What the system does internally is to compare those classes using equals. Why this doesn't work is explained in the following code:
Object o1 = new Object();
Object o2 = new Object();
System.out.println(o1 == o2); // false, obviously
System.out.println(o1.equals(o2)); // false
System.out.println(o1); // java.lang.Object#17046822
System.out.println(o2); // java.lang.Object#22509bfc
You can tell by the number following the # that these objects have a different hash values, and this is what the equals function of Object does check.
This is relevant for your klass, because unless you overwrite equals, you will use the equals of Object. And if you implement equals you should always implement hashcode as well. Because both tell you something about whether or not two objects are the "same", and if the one says something else than the other, some part of your code might get confused.
How to properly implement equals for your class:
#Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + Objects.hashCode(this.bir);
hash = 17 * hash + Objects.hashCode(this.myID);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final klass1 other = (klass1) obj;
if (!Objects.equals(this.bir, other.bir)) {
return false;
}
if (!Objects.equals(this.myID, other.myID)) {
return false;
}
return true;
}
This can be done in most IDEs btw with a shortcut (i.E. alt-insert in Netbeans). Note that I did this in Java 7 using Objects. If you are in Java 6, you need to manually type(a == b) || (a != null && a.equals(b)); with the appropriate objects to compare.
Creating a proper hashcode is not always trivial, for more complex objects you might want to read a bit about hashcodes first. For simple objects: multiply primes with something.
The equals method is usually trivial, it is just important to first check for null and for class equality. This is often forgotten by programmers and a common source for NullPointerExceptions and ClassCastExceptions.