Comparison between abstract objects yields wonky error - java

Numbers a,b;
a = new NumbersType(1);
b = new NumbersType(1);
System.out.println(a.equals(b));
public class NumbersType implements Numbers {
int intType;
public NumbersType (int q) {
this.intType = q;
}
public boolean equals(Numbers n) {
return this == n;
}
}
public interface Numbers {
public boolean equals(Numbers n);
}
This prints false, despite both objects being the same thing. Changing return this == n to return this.intType == n.intType yields error "cannot find symbol: variable intType, location: variable n of type Numbers".
I'm fairly new to ADT and still making my way around it, so excuse me if this is a simple question. I'm not sure why it doesn't work, however, and why I cannot reference n.intType but I can this.intType.

intType is declared on NumbersType but n is a Numbers. So you can't necessarily compare them.
Now, one thing you could do is create a method on the interface that retrieves some value. I say 'some' value instead of 'the' value because the other Numbers may be some other implementation. This is an important aspect of interfaces. If you have a Numbers you cannot know that it is actually a NumbersType. (You can find that out with instanceof but this would not be a good way to program an interface implementation. The interface's declaration should specify its interactions entirely.)
But first there's kind of a side issue which is that you're declaring an overload of Object#equals. You might be intending to declare an override which is a different thing. For the purpose of my answer, I am going to show an example of both and name the overload something different.
Now here's the modified interface:
public interface Numbers {
public int getIntType();
public boolean isIntTypeEqual(Numbers n);
}
Now that you can retrieve the int, you can compare them in the implementation class.
public class NumbersType
implements Numbers {
private int intType;
public NumbersType(int intType) {
this.intType = intType;
}
#Override
public int getIntType() {
return intType;
}
#Override
public boolean isIntTypeEqual(Number n) {
return intType == n.getIntType();
}
// overriding hashCode because we are overriding equals
#Override
public int hashCode() {
return intType;
}
#Override
public boolean equals(Object o) {
if(!(o instanceof Numbers))
return false;
return isIntTypeEqual((Numbers)o);
}
}
You may want to read:
Overriding equals and hashCode in Java
Overriding and Hiding Methods
If you are just learning this stuff, equals may not be a method you should be trying to implement. It is contractual and easy to get wrong.
Another complication is declaring equals in terms of interfaces: because equals must be symmetric, the implementations must override it identically. Otherwise the contract is broken.

Your class is NumbersType not Numbers, so you should type cast a and b in your equals method. This is why you cannot do n.intType
After you type cast, your equals method should compare intTypes of the objects, not direct references. This is why it will not work.
Your naming is a little bit confusing and I would suggest studying Polymorphism in general.

Related

Can Java generics be parameterized with values instead of types?

Assume I want to define types that are similar in structure, but differ in a parameter that could be an integer or could be something else.
Is it possible in Java to define a family of classes parameterized by an integer or even an arbitrary object?
Consider the following pseudocode (which does not compile):
/**
* String of a certain length n and a method to reduce to length n-1
*/
public class StringN<int n> {
private String str;
public StringN( String str) {
if(str.length() != n) {
throw new IllegalArgumentException("string is not of required length!");
}
this.str = str;
}
public StringN<n-1> reduce() {
return new StringN<n-1>(s.substring(0, s.length() - 1));
}
#Override
public String toString() {
return str;
}
}
Other even more natural examples that come to my mind are tensor-products in math, so where to put the parameter 'n', if one wants to define e.g. the space R^n as a Java class or in functional programming the 'arity' of a Function<>-space. So how to define a family of classes with different arity, parameterized by n?
If this is not possible in Java, does this concept exist in other more functional languages and what is the proper name for it? (like maybe 'parameterized class'?)
Edit: as a reaction to comments, the last part was just to know the general name of such a concept, not to make a detour to other languages.
Alas, Java requires type parameters to be types (actually, it even requires them to be reference types), and since all integers are of the same type, you not get the compiler to distinguish generics depending on the value of an integer.
The usual workaround is to declare a separate type for each possible (or needed) value. To share structure, you can use an abstract base class. And if the base class needs any concrete types, the subclasses can pass them as type parameters:
abstract class StringN<S extends StringN<S,P>, P extends StringN<P,?>>
implements Comparable<S> {
final String value;
protected StringN(String value, int n) {
if (value.length() != n) {
throw new IllegalArgumentException(value);
}
this.value = value;
}
#Override
public int compareTo(S o) {
return value.compareTo(o.value);
}
abstract P newP(String value);
public P removeLast() {
return newP(value.substring(0, value.length() - 1));
}
}
class String0 extends StringN<String0, String0> {
protected String0(String value) {
super(value, 0);
}
#Override
String0 newP(String value) {
throw new UnsupportedOperationException();
}
}
class String1 extends StringN<String1, String0> {
protected String1(String value) {
super(value, 1);
}
#Override
String0 newP(String value) {
return new String0(value);
}
}
class String2 extends StringN<String2, String1> {
protected String2(String value) {
super(value, 2);
}
#Override
String1 newP(String value) {
return new String1(value);
}
}
public class Test {
public static void main(String[] args) {
String2 s2 = new String2("hi");
String1 s1 = s2.removeLast();
s1.compareTo(s2); // compilation error: The method compareTo(String1) is not applicable for the arguments (String2)
}
}
As you can see, as long as the set of values is finite and known up front, you can even teach the compiler to count :-)
However, it gets rather unwieldy and hard to understand, which is why such workarounds are rarely used.
Yours is an interesting question, but I think you went too far in assuming that the solution to your need is necessarily a parametrized class.
Parametrized classes are composition of data types, not values.
Since you do not require the compile to enforce any additional static type checkings on your code, I think a programmatic solution would be enough:
First step: Move your pseudo-parameter "int n" to a final variable:
public class StringN {
private final int n;
private String str;
public StringN( String str) {
if(str.length() != n) {
throw new IllegalArgumentException("string is not of required length!");
}
this.str = str;
}
public StringN reduce() {
return new StringN(s.substring(0, s.length() - 1));
}
#Override
public String toString() {
return str;
}
}
Of course, this do not compile yet. You must initialize the n variable on every constructor (declarations and callings).
If you feel uncomfortable with the fact of exposing the parameter n as part of the public constructors calling, that can be solved restricting the constructors to package access, and bringing the construction responsibility to a new Factory class, which must be the only public way to create StringN objects.
public StringNFactory
{
private final int n;
public StringNFactory(int n)
{
this.n=n;
}
public StringN create(String s)
{
return new StringN(this.n, s);
}
}
As the name suggests, a "type parameter" is a type. Not 'a length of a string'.
To be specific: One can imagine the concept of the type fixed length string, and one can imagine this concept has a parameter, whose type is int; one could have FixedString<5> myID = "HELLO"; and that would compile, but FixedString<5> myID = "GOODBYE"; would be an error, hopefully a compile-time one.
Java does not support this concept whatsoever. If that's what you're looking for, hack it together; you can of course make this work with code, but it means all the errors and checking occurs at runtime, nothing special would occur at compile time.
Instead, generics are to give types the ability to parameterize themselves, but only with a type. If you want to convey the notion of 'A List... but not just any list, nono, a list that stores Strings' - you can do that, that's what generics are for. That concept applies only to types and not to anything else though (such as lengths).
Furthermore, javac will be taking care of applying the parameter. So you can't hack it together by making some faux hierarchy such as:
public interface ListSize {}
public interface ListIsSizeOne implements ListSize {}
public interface ListIsSizeTwo implements ListSize {}
public interface ListIsSizeThree implements ListSize {}
and then having a FixedSizeList<T extends ListSize> so that someone can declare: FixedSizeList<ListIsSizeTwo> list = List.of(a, b);.
The reason that can't work is: You can't tell javac what to do, it's not a pluggable system. Java 'knows' how to apply type bounds. It wouldn't know how to enforce size limits, so you can't do this.
I'm answering the question myself, because the useful information is distributed over several comments/answers. I made this a community-wiki answer, so that I don't earn reputation for suggestions of others.
The feature I'm looking for is apparently a particular case of so-called dependent-typing (thanks #DylanSp). Also template parameters of C++ (with the parameter not being a type) are an example of such a feature (thanks #Turing85). All answers agree that this feature unfortunately does not exist in Java, neither within the syntax of Java Generics (#rzwitserloot and others pointed out that Java specification allows only reference types in the diamond <>), nor any other syntax.
One certainly can manually define types in Java for each particular n. So for my example in my question, one can define classes String1, String2, String3, ..., but only finitely many ones. In order to make the definition of each particular type as simple as possible, one can use an approach with an abstract base class that is shared by all of these classes, see #meriton's nice suggestion.
Not what I was thinking of, but with finitely many cases also a code generator (mentioned by #Hulk) should be an option. If I understand correctly that's also what #MC Emperor had in mind when mentioning annotations.
However, if one really wants to stick to infinitely many classes (that's what I want), the only way out seems to be, to make the counter n a member of a single class and just think of them being different types. At compiler-level, there won't be any type-checking, so one has to implement type-safety oneself. The suggestion with the factory made by #Little Santi would be a way to bring more structure into this approach.

How to implement compareTo for any types of comparable objects

I don’t know how I can compare 2 comparable objects without some other variable which tells me which is larger. The question is: Create a class called Max that provides a single class method called max. max takes two arguments to objects that can be compared—that is, that implement the Java Comparable interface as shown above. It returns a reference to whichever is larger. If the two objects are equal, you should return the first. How Comparable is implemented is up to each class, and your method will be called on multiple different kinds of objects.
It gives the int compareTo (Object other) method in the interface but I’m having trouble finding a solution.
public class Max implements Comparable
{
public int compareTo(Object other)
{
}
public static Comparable max(Comparable first, Comparable second)
{
int fi = first.compareTo(second);
if(fi >0)
return first;
else if (fi<0)
return second;
return first;
}
}
java.lang.AssertionError: Class should not implement Comparable: expected [false] but found [true]
That is one of the errors. But also I need help writing the compareTo method.
I deleted my previous answer because I think, imho, you are over complicating this. Since the two arguments to max have implemented the Comparable<T> interface, all you have to do is call it as:
int ret = first.compareTo(second);
Then return first or second like you are doing based on the value of ret. That way you don't need to know anything about how it was implemented. Perhaps you could get some clarification from either your instructor or someone else who is working on this (I presume it is for an assignment).
It would be worthwhile for you to create some test classes which implement the interface. You can just make up some variable that represents size.
The keyword for your question is generics. You might want to do some research and read something about it. Take a look at the following example. I've implemented the class Max as a static class to keep it simple:
import java.time.LocalDate;
public class MyTestClass{
public static void main(String args[]) {
Integer i = 16;
Integer j = 15;
Integer m = Max.max(i, j);
System.out.println(m);
String k = "aaaa";
String n = "zzzz";
String s = Max.max(k, n);
System.out.println(s);
LocalDate d = LocalDate.now();
LocalDate e = LocalDate.now().plusDays(2);
LocalDate f = Max.max(d , e);
System.out.println(f);
}
static class Max{
public static <T extends Comparable> T max(T first, T second) {
if (first.compareTo(second) >= 0)
return first;
else
return second;
}
}
}
As you can see, there is a class Max with a single method max which accepts two objects, for example two integers, two strings or two date objects.
Since all these classes implement the comparable interface, you can use the max method for all object types. The compiler then decides during the runtime which comapreTo method to call, that is the compareTo of the class Integer, String, LocalDate or whatever.

Is there any Comparable not comparable to itself?

In the contract of Comparable, there's nothing forcing an object to be comparable to itself. It's just
strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y))
which implies that it's recommended for x.compareTo(x) not to throw. But it's possible to write a
class X implements Comparable<Y> {
...
}
where X and Y are two unrelated classes. I can't see what it could be good for, but in the Java 8 version of HashMap there's even a corresponding check.
Is it allowed to implement X implements Comparable<Y> with two unrelated classes?
Does it make any sense?
I guess the answers are yes and no, but it's just a guess
Comparable promotes a contract where comparisons should be consistent with equals, i.e. (a.compareTo(b) == 0) == a.equals(b). But it does not force you to do so and any weird contract can be enforced.
So you could create a:
class DumbInteger implements Comparable<DumbInteger> {
private final int i;
public DumbInteger(int i) { this.i = i; }
public int compareTo(DumbInteger di) { return 0; }
public boolean equals(Object other) { /* checks */ return other.i == this.i; }
}
And you could also create a:
class DumberInteger implements Comparable<String> {
private final int i;
public DumberInteger(int i) { this.i = i; }
public int compareTo(String s) { return 0; }
public boolean equals(Object other) { /* checks */ return other.i == this.i; }
public static void main(String[] args) {
System.out.println(new DumberInteger(0).compareTo("abc"));
}
}
but there is probably no point in doing that. In any case this is not specific to Java 8 as the Comparable interface has been there since Java 2 and "generified" in Java 5.
But it is probably not a flaw in the Comparable interface per se, because I don't think there is a way in Java to create a generic interface I<T> that can only be implemented by classes that are subtypes of T.
I see I missed one part of the contract and also failed to see the reason why HashMap.comparableClassFor exists.
The contract says
(x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0
so whenever there's an X greater than a Y and a Y greater than an X, then the two instances of X must be comparable to each other. This doesn't leave much freedom:
Either one of the types is empty. This makes no sense at all.
Or all instances of X are smaller or equal to all instances of Y (or the other way round). This is slightly less nonsensical.
So, I'm concluding that it's possible, but makes no sense. The simplest example is
class X implements Comparable<Void> {
public int compareTo(Void v) {
return 43; // or throw or whatever, it doesn't matter
}
}
I guess that the reason for HashMap.comparableClassFor is to support different implementations of a common superclass like
abstract class AByteArray implements Comparable<AByteArray> {}
class SparseByteArray extends AByteArray {...}
class DenseByteArray extends AByteArray {...}
This seems to make sense and can be even consistent with equals.
Does it make any sense?
One issue of having two classes Comparable with each other, is because it tightly couples these classes together. This makes it difficult to re-use the class in another scenario.
Just tried it, it is possible to compare two objects with different classes.
Here is the full code.
https://gist.github.com/cevaris/11099129
X x = new X();
x.xTest = 10;
Y y = new Y();
y.yTest = 100;
System.out.println("x.compareTo(y) == -1: " + (x.compareTo(y) == -1)); //True
System.out.println("y.compareTo(x) == 1: " + (y.compareTo(x) == 1)); //True
Here is the Y implementation.
class Y implements Comparable<X> {
int yTest;
#Override
public int compareTo(X o) {
if(this.yTest < o.xTest) return -1;
if(this.yTest > o.xTest) return 1;
return 0;
}
}
Here is the X implementation.
class X implements Comparable<Y> {
int xTest;
#Override
public int compareTo(Y o) {
if(this.xTest < o.yTest) return -1;
if(this.xTest > o.yTest) return 1;
return 0;
}
}
Well, it can technically be done (as per #cevaris' answer) and can be understood when you have several ways of representing the same object, e.g. an object and its String representation. But it would only make sense if you could implement the same interface twice like:
public class CompInt implements Comparable<CompInt>, Comparable<String> {
but that is forbidden in Java because of type erasure.

Priority Queue for HashMap Object in Java

I have created a HashMap object which stores a String as key and corresponding value as int. Now I want to have a Priority Queue which have all the String present in HashMap object with value as reference for assigning priorities. I have written the following code
public class URIQueue {
private HashMap<String,Integer> CopyQURI;
private PriorityQueue<String> QURI;
public class TComparator<String> {
public int compareTo(String s1, String s2) {
if (CopyQURI.get(s2) - CopyQURI.get(s1) >= 0) {
return 1;
} else {
return 0;
}
}
}
public URIQueue() {
CopyQURI=new HashMap<>(100);
TComparator<String> tc=new TComparator<>();
QURI=new PriorityQueue<>(100, tc); //Line x
}
}
Line x is showing error cannot infer type argument for priority queue. Please guide me what mistake I have done.
The error you are referring to states, that it cannot guess the generic type parameter which you have omitted. The reason for that is that the constructor you are using is not known. It is not known, because you second argument is not a comparator. Your comparator has to implement the java.util.Comparator interface in order to be type safe for the constructor to accept.
public class TComparator<String> implements Comparator<String> {
#Override
public int compare(String arg0, String arg1) {
// ...
}
}
Also mind, in the Comparator interface the appropriate method is called compare and not compareTo.
A general advice, I have to agree with Louis Wasserman, for two given arguments a comparator should always return the same result and not depend on the state of the application. It's just too easy not to think of some case and the application is eventually flawed.

When overriding equals in Java, why does it not work to use a parameter other than Object?

I ran into an interesting behavior recently. It seems that if I override .equals() to take a parameter other than Object, it doesn't get called. Can anyone explain to me why this is happening? It seems to violate my understanding of polymorphism in OOP, but maybe I'm missing something.
Here's much simpler code that shows what I'm seeing:
public class MyClass {
private int x;
public MyClass(int n) { x = n; }
public boolean equals(Object o) { return false; }
public boolean equals(MyClass mc) { return x == mc.x; }
public static void main(String[] args) {
List<MyClass> list = new ArrayList<MyClass>();
list.add(new MyClass(3));
System.out.println("Contains 3? " + list.contains(new MyClass(3)));
}
}
When this is run, it prints "Contains 3? false". It looks like the equals(Object) function is called, even though there is another that would work. By contrast, if I write equals like this the code works as expected:
public boolean equals(Object o) {
if(!(o instanceof MyClass))
return false;
MyClass mc = (MyClass)o;
return x == mc.x;
}
Why isn't it figuring out which version of the function to call based on the type of the parameter?
You're mixing up "overriding" and "overloading".
Overriding -- adding a replacement definition of an existing method for purposes of polymorphism. The method must have the same signature. The signature consists of the name and argument types. Overridden methods are selected at runtime based on the runtime type of the target object.
Overloading -- adding a method with the same name but a different signature. Overloaded methods are selected at compile time based on the compile time type of the target object.
equals(Object) is overriding a super method; you can not override a super method without using the exact same signature (Well, there are some exceptions like covariant returntypes and exception).
Notice that the method you are calling is defined in the javadoc for ArrayList<E> as
boolean contains(Object o)
Returns true if this list contains the specified element.
instead of
boolean contains(E o)
Returns true if this list contains the specified element.
Implementation of ArrayList.java:
private transient Object elementData[];
public boolean contains(Object elem) {
return indexOf(elem) >= 0;
}
public int indexOf(Object elem) {
if (elem == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (elem.equals(elementData[i]))
return i;
}
return -1;
}
It uses the equals method defined in the Object superclass since the equals method is not overridden in ArrayList<E>'s implementation.
When overriding Object equals in java, you should override the Object hashCode method as well.
Anyway you might want to try the following code:
class A{
public int content;
A(){
this(0);
}
A(int value){
content = value;
}
public boolean equals(Object obj){
System.out.println("overriding equals method");
return this.content == ((A) obj).content;
}
public boolean equals(A a){
System.out.println("overloading equals method");
return this.content == a.content;
}
public static void main(String[] args){
A x = new A(1);
A y = new A(2);
Object z = new A(1);
System.out.println(x.equals(y));
System.out.println(x.equals(x));
System.out.println(x.equals(z));
//override as z is declared as Object at compile time
//so it will use methods in class Object instead of class A
System.out.println(x.equals((Object) y));
System.out.println(x.equals((Object) x));
}
}
//rant: they didn't teach me these in javaschool and I had to learn it the hard way.
there are different types of http://en.wikipedia.org/wiki/Polymorphism_(computer_science). java does not do http://en.wikipedia.org/wiki/Double_dispatch.
The ArrayList implementation of the contains(Object) method is bound to use Object.equals(Object) method internally, so it'll never know about your overloading of the equals(MyClass) method. Only an overriding method (with matching signature) will be found.
Ok let me re-phrase.
(1)Because the compiler eliminates all information regarding to Generics (erasure, see here), and (2) because you cannot override a method without the exact same signature (equals(Object)), (3) during runtime all objects inside the List are treated as Objects and not as instances of MyClass. Hence, the method that gets called is equals(Object) since this is the one that is been overwritten by your class.
You're assuming that the contains() method in List knows the type of the object at runtime, which is incorrect.
Because of erasure, List<MyClass> becomes just a regular List at runtime, so the contains() method sees its parameter as an Object, thus invoking Object's equals() instead of the one you defined for MyClass in its execution.

Categories