Let's say I have the following class A that implements an interface M:
class A implements M {
int i;
int hashCode() { return i; }
}
And a wrapper for A, for example
class AWrapper implements M {
A a;
public Wrapper(A a) {
this.a = a;
}
int hashCode() { ??? }
}
This hierarchy is a sort of Composite Pattern. My question is what is a good hashcode for the AWrapper class? I can use a.hashCode(), but then all A's and
AWrapper's will have the same hashcode. What is the best way to implement such a hash code?
As some people ask what's the rationale behind this design, let me make it more concrete. I'm writing a data type for regular expressions. So A is a symbol, and there are regular operators such as *, +, ? that are essentially wrappers of symbols, e.g., Star(A). I also want to make sure there is only one instance of an object, that's why I need sharing, so if someone writes:
r1 = a*a
r2 = a*c
represented by Seq(Star('a'), 'a') and Seq(Star('a'), 'c'), I want two instances of Star('a') be shared, of course via a factory call.
Putting As and AWrappers as keys in the same map does not sound right. But if that's what you want you could use Objects.hash(a).
When a single object reference is supplied, the returned value does not equal the hash code of that object reference.
As a side note, if AWrapper is immutable and the hashCode method is called often and A::hashCode is not trivial and memory footprint is not an issue, you may want to precalculate the hashcode (worth testing if it is worth it in your scenario):
class AWrapper implements M {
private final A a;
private final int hash;
public Wrapper(A a) {
this.a = a;
hash = Objects.hash(a);
}
int hashCode() { return hash; }
}
Related
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.
I have a class representing a column. It has a comparator which looks something like this:
class Column
{
int xposition;
int usage;
#Override
public int compare(Object arg0, Object arg1)
{
// sort logic
}
}
I have a TreeSet of Columns. I want to sort the TreeSet first by x-position, and then at some point by usage.
What I tried is to create a superclass, such as Column2, that extends Column and has a different compare method. However that makes converting from Column to Column2 (or visa versa) very ugly. I also thought of a flag in the Column that indicates how to do the sort, but that would mean modifying all the objects in order to change the sort criteria.
Is there any better way to do this?
I would have the comparison logic in a set of external Comparators to represent the different sorting cases you have, and then create a new TreeSet when you want to change the sort:
class Column
{
int xposition;
int usage;
public static final Comparator<Column> SortByX = new Comparator<Column>() {
#Override
public int compare(Column c1, Column c2)
{
return Integer.compare(c1.xposition, c2.xposition);
}
};
public static final Comparator<Column> SortByUsage = new Comparator<Column>() {
#Override
public int compare(Column c1, Column c2)
{
return Integer.compare(c1.usage, c2.usage);
}
};
}
TreeSet<Column> cols = new TreeSet<>(Column.SortByX);
Then, to change the sort:
TreeSet<Column> updated = new TreeSet<>(Column.SortByUsage);
updated.addAll(cols);
cols = updated;
With appropriate synchronization if this is happening in a multi-threaded environment.
Whatever you do, do not change the behavior of an object's Comparator using mutable state. If you do, you could easily "lose track" of an object after it has been put into a collection like TreeSet.
Strategy pattern
What you want to achieve seems a classic use case for the Strategy pattern (e.g. Real World Example of the Strategy Pattern)
In essence, you want to package up this comparison function into something that you can put in a separate field for your column class - a plain class with that single function that implements Comparable would work. Then, your column would just delegate the call to whatever comparator is stored in that field.
This is exact use case of Guava's ComparisionChain:
Example taken from here :
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(this.xposition, that.xposition)
.compare(this.usage, that.usage)
.result();
}
Like Sean Bright answer, I'd use external Comparator and if you are working with Java 8, you can do it pretty easily:
public static final Comparator<Foobar> NAME_THEN_AGE =
Comparators.comparing(Foobar::getName, String.CASE_INSENSITIVE_ORDER)
.thenComparing(Foobar::getAge)
;
....
TreeSet<Foobar> foobar = new TreeSet<>(NAME_THEN_AGE);
However, better remaindered that not, it is generally a bad idea to override Comparable on a child class - perhaps it should be final on the parent or one should create a protected compareTo0(A) doing the common work (to avoid comparing object by their parent class).
There are reason for that, and one such is the following (from the Javadoc of Comparable.compareTo):
The implementor must ensure sgn(x.compareTo(y)) ==
-sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an
exception.)
Let's say you have class B and C extending A and A implements Comparable<A>:
class A implements Comparable<A> {
#Override
public int compareTo(A other) {return ...;}
}
class B extends A {
#Override
public int compareTo(A other) {return compareToAsB(((B)other));}
}
class C extends A {
#Override
public int compareTo(A other) {return compareToAsC(((C)other));}
}
It does not really matter what A::compareTo returns. Neither what compareToAsB and compareToAsC does.
The problem is however here:
A a = ...;
B b = ...;
C c = ...;
a.compareTo(b); // ok
a.compareTo(c); // ok
b.compareTo(a); // ko ClassCastException
b.compareTo(c); // ko ClassCastException
c.compareTo(a); // ko ClassCastException
c.compareTo(b); // ko ClassCastException
As quoted in the javadoc, a.compareTo(b) should throw a ClassCastException.
Also, there are part in the Java code (Collections.sort) where it is important to ensure that sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.
I'm currently taking a Java course and have a question about polymorphism.
Given
public class A {
private int a1;
public A(){}
public A(int a1) { this.a1 = a1;}
}
class B extends A {
private int b1;
public B() {}
public B(int b1, int a1) {
super(a1);
this.b1 = b1;
}
}
class C extends B {
private int c1;
public C(){}
public C(int c1, int b1, int a1) {
super(b1, a1);
this.c1 = c1;
}
}
What would be the best way to assign to fields a1, b1, and c1, all in one swoop? My first guess would be to make an instance of C and call its three-arg constructor.
But what happens when each class contains 10s or 100s of data fields? Wouldn't this approach mean calling constructors with huge numbers of arguments, like
C(arg1, arg2, ..., arg100), setting k of C's fields, then making a call to
B(arg1, arg2, ..., arg100-k), and so on,
all the way up to the top? Is there a better way to proceed?
Having so many parameters is a definite code smell; in all probability you want to split the object up into smaller self-contained objects and/or or collections.
On the other hand, there is the Builder pattern, where you use a helper class to set all the parameters and it constructs the object for you, possibly sanity-checking that all required fields are set and there are no conflicts.
Not in this particular case because the fields in the parent classes are declared private.
If they were protected then you could set all 3 of them from the class C constructor. However this breaks encapsulation because if the constructor for B did something else after the value was assigned you'd have to duplicate that logic in C in order to not violate it's contract, and as you can imagine that gets very messy when you have more constructors or parent classes in the type tree.
Having multiple calls chained in the manner you proposed is the safest way at the cost of having to call all those constructors up the chain. I'd recommend profiling your code to see if this is actually a problem and not just a premature optimization.
What you're suggesting would work if you set the class fields to public. Class C will have a1 and c1, but won't be able to access them due to them being private.
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.
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.