I have 2 methods isArithmetric and isRelational, both of these methods are used to see if e belongs to a certain instance of a class (eg. if e is a type like 2 + 3 then its in isArithmetric and is an instanceof Additiona, and if e is like 3 > 2 then its in isRelational and is an instanceof GreaterThan). I need to implement the isTypeCorrect method which I know uses the two methods mentioned above to see if when used, returns true if e is either one of the two methods above, and false otherwise. The thing is, I don't know how to implement isTypeCorrect, I tried to call the method from isTypeCorrect and used an if statement but it would not work. Any help would be appreciated.
Code:
private boolean isArithmetic(Expression e) {
return
e instanceof Addition
|| e instanceof Subtraction
|| e instanceof Multiplication;
}
/**
* sub-routine that can be used to check if this is type correct
* true if e is one of the three classes, or their subclasses (if any)
*/
private boolean isRelation(Expression e) {
return
e instanceof Equal
|| e instanceof GreaterThan
|| e instanceof LessThan;
}
/**
* If this collector is AddAll or TimesAll, then all stored expressions must be integer expressions
* (i.e., Addition, Subtraction, Multiplication).
* If this collection is ConjoinAll or DisjoinAll, then all stored expressions must be boolean expressions
* (i.e., GreaterThan, LessThan, Equal)
* #return whether it is possible to evaluate the stored collection of expressions.
*/
boolean isTypeCorrect() {
}
Look at this code.
boolean isTypeCorrect() {
boolean result = false;
AddAll a = new AddAll();
TimesAll t = new TimesAll();
if (this.isArithmetic(a) || this.isRelation(t)) {
result = true;
}
return result;
}
a and t are new instances of AddAll and TimesAll respectively with no changeable arguments to a constructor. How could they ever be anything different each time you invoke this method. In fact, they are going to be local values and go out of scope when you exit the method. I can't tell what is going on but it looks like a design flaw.
Related
This question already has answers here:
Java generics type erasure: when and what happens?
(7 answers)
Closed 7 months ago.
Given a Set<X>, I want to write a method that acts differently depending on the class X is. In actuality, I'd have 2 cases: A or B.
The method looks like:
public<X> boolean myMethod(Set<X> mySet)
{
// if X is actually the class A
...
// if X is B
...
}
I am not sure how to check this. I tried X::getClass, but it wouldn't let me use equals method.
In a general sense, this is not possible
Due to type erasure, a Java Set does not have a generic type at runtime. Generics act as compile-time checks on the objects passed into methods, but consequently the specific values are not available at runtime. A Set<String> is the same class as a Set<Map<Integer, Thread>> and the same class as a bare Set.
Potential workaround with class parameter
If you really need to know this, you could change the signature of your method to be:
public <X> boolean myMethod(Set<X> mySet, Class<X> clazz)
Now you have a Class instance available at runtime, which is guaranteed to be compatible with X. This you can introspect (e.g. String.class.isAssignableFrom(clazz)).
There are two drawbacks to this approach: firstly, you'll have to explicitly pass in the extra parameter each time the method is called. Secondly, if A and B can be subclasses of one another, this is not going to work; you could pass in e.g. B.class even when the generic parameter was A.
However, this feels like a code smell
You shouldn't be trying to do fundamentally different things based on a generic parameter. Instead of switching behaviour in your method here, do something different within the classes A and B:
public<X> boolean myMethod(Set<X> mySet)
{
boolean result = false;
for (X x : mySet) {
result &= x.doSomething();
}
return result;
}
class A implements MyDoSomethingInterface {
public boolean doSomething() {
// Here you put the logic for "if X is A"
}
}
class B implements MyDoSomethingInterface {
public boolean doSomething() {
// Here you put the logic for "if X is B"
}
}
And if your reaction is that this won't work because A and B are built-in classes, you'll need to wrap them in your own domain objects (which is the correct approach anyway because you want to associate this extra behaviour with them).
I suggest you take one object from set and check class of single object
like below, please check
public<X> boolean myMethod(Set<X> mySet)
{
Object tmpObj = null;
for(Object obj : set){
tmpObj = obj;
break;
}
if(tmpObj instanceof A){
// if X is actually the class A
}else if(tmpObj instanceof B){
// // if X is B
}
}
It's written in all decent java courses, that if you implement the Comparable interface, you should (in most cases) also override the equals method to match its behavior.
Unfortunately, in my current organization people try to convince me to do exactly the opposite. I am looking for the most convincing code example to show them all the evil that will happen.
I think you can beat them by showing the Comparable javadoc that says:
It is strongly recommended (though not required) that natural
orderings be consistent with equals. This is so because sorted sets
(and sorted maps) without explicit comparators behave "strangely" when
they are used with elements (or keys) whose natural ordering is
inconsistent with equals. In particular, such a sorted set (or sorted
map) violates the general contract for set (or map), which is defined
in terms of the equals method.
For example, if one adds two keys a and b such that (!a.equals(b) &&
a.compareTo(b) == 0) to a sorted set that does not use an explicit
comparator, the second add operation returns false (and the size of
the sorted set does not increase) because a and b are equivalent from
the sorted set's perspective.
So especially with SortedSet (and SortedMap) if the compareTo method returns 0, it assumes it as equal and doesn't add that element second time even the the equals method returns false, and causes confusion as specified in the SortedSet javadoc
Note that the ordering maintained by a sorted set (whether or not an
explicit comparator is provided) must be consistent with equals if the
sorted set is to correctly implement the Set interface. (See the
Comparable interface or Comparator interface for a precise definition
of consistent with equals.) This is so because the Set interface is
defined in terms of the equals operation, but a sorted set performs
all element comparisons using its compareTo (or compare) method, so
two elements that are deemed equal by this method are, from the
standpoint of the sorted set, equal. The behavior of a sorted set is
well-defined even if its ordering is inconsistent with equals; it just
fails to obey the general contract of the Set interface.
If you don't override the equals method, it inherits its behaviour from the Object class.
This method returns true if and only if the specified object is not null and refers to the same instance.
Suppose the following class:
class VeryStupid implements Comparable
{
public int x;
#Override
public int compareTo(VeryStupid o)
{
if (o != null)
return (x - o.x);
else
return (1);
}
}
We create 2 instances:
VeryStupid one = new VeryStupid();
VeryStupid two = new VeryStupid();
one.x = 3;
two.x = 3;
The call to one.compareTo(two) returns 0 indicating the instances are equal but the call to one.equals(two) returns false indicating they're not equal.
This is inconsistent.
Consistency of compareTo and equals is not required but strongly recommended.
I'll give it a shot with this example:
private static class Foo implements Comparable<Foo> {
#Override
public boolean equals(Object _other) {
System.out.println("equals");
return super.equals(_other);
}
#Override
public int compareTo(Foo _other) {
System.out.println("compareTo");
return 0;
}
}
public static void main (String[] args) {
Foo a, b;
a = new Foo();
b = new Foo();
a.compareTo(b); // prints 'compareTo', returns 0 => equal
a.equals(b); // just prints 'equals', returns false => not equal
}
You can see that your (maybe very important and complicated) comparission code is ignored when you use the default equals-method.
the method int compareTo(T o) allow you know if the T o is (in some way) superior or inferior of this, so it allow you to order a list of T o.
In the scenario of int compareTo(T o) you have to do :
is o InstanceOfThis ? => true/false ;
is o EqualOfThis ? => true/false ;
is o SuperiorOfThis ? => true/false ;
is o InferiorOfThis ? true/false ;
So you see you have the equality test, and the best way to not implement the equality two times is to put it in the boolean equals(Object obj) method.
It is stated in Object's .equals(Object) javadoc:
It is symmetric: for any non-null reference values x and y,
x.equals(y) should return true if and only if y.equals(x) returns
true.
Almost everywhere in example code I see overridden .equals(Object) method which uses instanceof as one of the first tests, for example here: What issues / pitfalls must be considered when overriding equals and hashCode?
public class Person {
private String name;
private int age;
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
...
}
}
Now with class SpecialPerson extends Person having in equals:
if (!(obj instanceof SpecialPerson))
return false;
we con not guarantee that .equals() is symmetric.
It has been discussed for example here: any-reason-to-prefer-getclass-over-instanceof-when-generating-equals
Person a = new Person(), b = new SpecialPerson();
a.equals(b); //sometimes true, since b instanceof Person
b.equals(a); //always false
Maybe I should add in the beginning of SpecialPerson's equals direct call to super?
public boolean equals(Object obj) {
if( !obj instanceof SpecialPerson )
return super.equals(obj);
...
/* more equality tests here */
}
A lot of the examples use instanceof for two reasons: a) it folds the null check and type check into one or b) the example is for Hibernate or some other code-rewriting framework.
The "correct" (as per the JavaDoc) solution is to use this.getClass() == obj.getClass(). This works for Java because classes are singletons and the VM guarantees this. If you're paranoid, you can use this.getClass().equals(obj.getClass()) but the two are really equivalent.
This works most of the time. But sometimes, Java frameworks need to do "clever" things with the byte code. This usually means they create a subtype automatically. Since the subtype should be considered equal to the original type, equals() must be implemented in the "wrong" way but this doesn't matter since at runtime, the subtypes will all follow certain patterns. For example, they will do additional stuff before a setter is being called. This has no effect on the "equalness".
As you noticed, things start to get ugly when you have both cases: You really extend the base types and you mix that with automatic subtype generation. If you do that, you must make sure that you never use non-leaf types.
You are missing something here. I will try to highlight this:
Suppose you have Person person = new Person() and Person personSpecial = new SpecialPerson() then I am sure you would not like these two objects to be equal. So, its really working as required, the equal must return false.
Moreover, symmetry specifies that the equals() method in both the classes must obey it at the same time. If one equals return true and other return false, then I would say the flaw is in the equals overriding.
Your attempt at solving the problem is not correct. Suppose you have 2 subclasss SpecialPerson and BizarrePerson. With this implementation, BizarrePerson instances could be equal to SpecialPerson instances. You generally don't want that.
don't use instanceof. use this.getClass() == obj.getClass() instead. then you are checking for this exact class.
when working with equalsyou should always use the hashCode and override that too!
the hashCode method for Person could look like this:
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
and use it like this in your equals method:
if (this.hashCode() != obj.hashCode())
{
return false;
}
A type should not consider itself equal to an object of any other type--even a subtype--unless both objects derive from a common class whose contract specifies how descendants of different types should check for equality.
For example, an abstract class StringyThing could encapsulate strings, and provide methods to do things like convert to a string or extract substrings, but not impose any requirements on the backing format. One possible subtype of StringyThing, for example, might contain an array of StringyThing and encapsulate the value of the concatenation of all those strings. Two instances of StringyThing would be defined as equal if conversion to strings would yield identical results, and comparison between two otherwise-indistinguishable StringyThing instances whose types knew nothing about each other may have to fall back on that, but StringyThing-derived types could include code to optimize various cases. For example, if one StringyThing represents "M repetitions of character ch" and another represents "N repetitions of the string St", and the latter type knows about the first, it could check whether St contains nothing but M/N repetitions of the character ch. Such a check would indicate whether or not the strings are equal, without having to "expand out" either one of them.
This question already has answers here:
When does HashSet 'add' method calls equals? [duplicate]
(4 answers)
Closed 4 years ago.
The documentation for HashSet.add says
Adds the specified element to this set if it is not already present. More formally, adds the specified element e to this set if this set contains no element e2 such that (e==null ? e2==null : e.equals(e2)). If this set already contains the element, the call leaves the set unchanged and returns false.
Since my code below will return false for e.equals(e2), I'd expect it to let me add the same instance twice. But the set only contains my instance once. Can someone explain why?
package com.sandbox;
import java.util.HashSet;
import java.util.Set;
public class Sandbox {
public static void main(String[] args) {
Set<A> as = new HashSet<A>();
A oneInstance = new A();
System.out.println(oneInstance.equals(oneInstance)); //this prints false
as.add(oneInstance);
as.add(oneInstance);
System.out.println(as.size()); //this prints 1, I'd expect it to print 2 since the System.out printed false
}
private static class A {
private Integer key;
#Override
public boolean equals(Object o) {
if (!(o instanceof A)) {
return false;
}
A a = (A) o;
if (this.key == null || a.key == null) {
return false; //the key is null, it should return false
}
if (key != null ? !key.equals(a.key) : a.key != null) {
return false;
}
return true;
}
#Override
public int hashCode() {
return key != null ? key.hashCode() : 0;
}
}
}
HashSet (really HashMap under the hood) has an "optimization" in that it checks for object reference equality before calling the equals() method. since you are putting the same instance in twice, they are considered equal even though the equals() method does not agree.
Relevant line from HashMap.put():
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
You're breaking the contract of Object.equals(Object), which starts with:
The equals method implements an equivalence relation on non-null object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
As your sample code says:
System.out.println(oneInstance.equals(oneInstance)); //this prints false
It seems that HashSet<E> (entirely reasonably) assumes reflexivity, and doesn't check for equality when it finds that the exact same object is already in the set, as an optimization. Therefore it will not even call your equals method - it considers that the object is already in the set, so doesn't add a second copy.
In particular, if x.equals(x) is false, then any containment check would also be useless.
I'd implement equals like this:
public boolean equals(Object o) {
// Normal reflexive optimization
if (this == o) {
return true;
}
// "Correct type" check
if (!(o instanceof A)) {
return false;
}
A a = (A) o;
// If both keys are null, the objects are equal. This is the most normal
// approach; you *could* make non-identical objects with null keys non-equal,
// but that would be odd.
if (this.key == null && a.key == null) {
return true;
}
// If exactly *one* key is null, the objects are not equal.
if (this.key == null || a.key == null) {
return false;
}
// By now we know that both keys are non-null; use normal equality.
return this.key.equals(a.key);
}
Or if you're using Java 7:
public boolean equals(Object o) {
// Normal reflexive optimization
if (this == o) {
return true;
}
// "Correct type" check
if (!(o instanceof A)) {
return false;
}
A a = (A) o;
return Objects.equals(this.key, a.key);
}
Hash maps/tables work by taking an object and 'hashing' it with a 'hash' function to produce a Psuedo Random Uniformly Distributed unique id representing the object where said id can be used as a key into an indexable structure like an array. Ideally you would have a perfect hash where each unique item produces a unique indexable id.
Obviously your array is fixed in size (you can grow the array but this will dramatically affect runtime performance) so at some point, if you continue to add elements to the Hash map/table you will eventually get 2 items with the same hash code and then you will have a collision; this is where equals comes into play.
When this occurs equality is used to disambiguate WHICH key/value you are seeking by iterating through (usually by storing a LinkedList at the index position and not just the element) the available objects and checking the equals method.
So, the problem for your case is easy: If your hash implementation is wrong then HashSet (which is backed by HashMap) fails to find your object in it's table and thus never bothers to call equals (have a look at HashMap.get() to see their implementation).
Whatever you use in equals MUST be used in hashCode() if you want this to work and vice versa. If you implement equals() it's a damn good idea to implement hashCode(). If you implement hashCode() then you MUST implement equals for hashing to actually work.
I don't know exactly why but I feel compelled to point out that when you implement equals, part of the contract for the equals method that you should uphold is that it is reflexive, meaning the same object equals itself. So your equals should return true.
My thought for an answer to your question is that the .equals() method is not getting called when you merely add the two items of the same instance to the HashSet. Probably only hashCode is called up to that point. Since hashCode returns the key it will return the same key each time and the item just gets hashed to the same place twice, leaving only one item in the set.
What's the most compact code to compare three objects for (semantic) equality using Java? I have a business rule that the objects must be unique i.e. A is different to B, A is different to C and B is different to C.
Assume that the objects are all of the same class and have correctly overridden equals and hashCode methods. A slight wrinkle is that object C could be null—if this is the case then A and B have to be different to each other.
I have some code but it's a bit workmanlike for my tastes.
As the OP said A and B are never null, C may be null, use this:
if(A.equals(B) || B.equals(C) || A.equals(C))
// not unique
and, as others have already suggested, you can put it in a method for reuse. Or a generic method if you need more reuse ;-)
Note that in Java, a feature of equals is that if its argument is null it should not throw, but return false.
Since I never start a Java project without using Apache commons-lang, try ObjectUtils.equals (it's null safe):
if (ObjectUtils.equals(a, b) || ObjectUtils.equals(b, c) || ObjectUtils.equals(a, c)) {
// error condition
}
Put that logic in a generic method, and you'll do even better.
While the business logic allows C to be null, in scenarios like this, it's often better to code defensively and assume that either A or B could be null as well.
You can abstract that method in a utilities method like:
public boolean allUnique(Object... objs) {
Set<Object> set = new HashSet<Object>();
for (Object o : objs)
set.add(o);
return set.size() == objs.length
}
The method may not perform well for small numbers (due to the overhead of creating the Set and the varargs array). However, it grows linearly O(n), and for large values it's better than the quadratic growth of a nested if statements.
boolean areDistinct(Object a, Object b, Object c) {
return (!a.equals(b) &&
(c == null || (!c.equals(a) && !c.equals(b))));
}
As the apache's common.lang3.ObjectUtils.equals() is #Deprecated. Use Objects.equals(aObj,bObj). Comparison should be made with && if you want that all 3 objects are the same. Use || if you want that just one combination of a&b, a&c or b&c is the same.
/**
* Compare 3 objects of the same {#link TYPE}, if they are all equal using {#link Objects#equals(Object, Object)}.
*
* #param aObj the 1st object
* #param bObj the 2nd object
* #param cObj the 3th object
* #param <TYPE> the type of the objects
* #return true if the are all the same
*/
public static <TYPE> boolean equals(TYPE aObj, TYPE bObj, TYPE cObj) {
return Objects.equals(aObj, bObj) && Objects.equals(bObj, cObj) && Objects.equals(cObj, aObj);
}
As long as your objects implement equals, you can use the Stream API to get a distinct set of values, and if that distinct count is 1, they are all the same.
boolean allEqual = Stream.of(obj1, obj2, obj3).distinct().count() == 1
package com.test;
public class Equality {
public static void main(String[] args) {
Boolean flag;
int[] arr={1,1,1,12};
flag=check_equal(arr);
System.out.println(flag);
}
public static Boolean check_equal(int[] arr){
Boolean flag=true;
outerloop:
for(int i=1; i< arr.length; i++)
{
for(int j=1; j< arr.length; j++){
if(arr[i]==arr[j]){
flag=true;
}
else{
flag=false;
break outerloop;
}
}
}
return flag;
}
}