Improve Override / Abstract Method Resolution Algorithm - java

The following chunks of code define how the compiler for my custom JVM programming language resolves missing abstract methods and links methods to their supertype methods. The inheritance model is like in Java 8, you can have both abstract and concrete (default) methods in interfaces and abstract classes and concrete methods only in non-abstract classes. Multiple inheritance is obviously only allowed for interfaces:
CodeClass.java:
public class CodeClass extends AbstractClass
{
// ...
public void checkTypes(MarkerList markers, IContext context)
{
// ...
if (this.superType != null)
{
this.superType.getTheClass().checkMethods(markers, this, this.superType);
}
for (int i = 0; i < this.interfaceCount; i++)
{
IType type = this.interfaces[i];
type.getTheClass().checkMethods(markers, this, type);
}
}
// ...
}
AbstractClass.java:
public class AbstractClass
{
protected ClassBody body;
// ...
public boolean checkImplements(MarkerList markers, IClass iclass, IMethod candidate, ITypeContext typeContext)
{
if (candidate.getTheClass() == this)
{
return !candidate.hasModifier(Modifiers.ABSTRACT);
}
if (this.body != null && this.body.checkImplements(markers, iclass, candidate, typeContext))
{
return true;
}
if (this.superType != null)
{
if (this.superType.getTheClass().checkImplements(markers, iclass, candidate, this.superType.getConcreteType(typeContext)))
{
return true;
}
}
for (int i = 0; i < this.interfaceCount; i++)
{
IType type = this.interfaces[i];
if (type.getTheClass().checkImplements(markers, iclass, candidate, type.getConcreteType(typeContext)))
{
return true;
}
}
return false;
}
public void checkMethods(MarkerList markers, IClass iclass, ITypeContext typeContext)
{
if (this.body != null)
{
this.body.checkMethods(markers, iclass, typeContext);
}
if (this.superType != null)
{
this.superType.getTheClass().checkMethods(markers, iclass, this.superType.getConcreteType(typeContext));
}
for (int i = 0; i < this.interfaceCount; i++)
{
IType type = this.interfaces[i];
type.getTheClass().checkMethods(markers, iclass, type.getConcreteType(typeContext));
}
}
// ...
}
ClassBody.java:
public class ClassBody
{
// ...
public boolean checkImplements(MarkerList markers, IClass iclass, IMethod candidate, ITypeContext typeContext)
{
for (int i = 0; i < this.methodCount; i++)
{
if (this.methods[i].checkOverride(markers, iclass, candidate, typeContext))
{
return true;
}
}
return false;
}
public void checkMethods(MarkerList markers, IClass iclass, ITypeContext typeContext)
{
for (int i = 0; i < this.methodCount; i++)
{
IMethod candidate = this.methods[i];
if (iclass.checkImplements(markers, iclass, candidate, typeContext))
{
continue;
}
if (candidate.hasModifier(Modifiers.ABSTRACT) && !iclass.hasModifier(Modifiers.ABSTRACT))
{
markers.add(iclass.getPosition(), "class.method.abstract", iclass.getName(), candidate.getName(), this.theClass.getName());
}
}
}
// ...
}
method.checkOverride simply checks if the signature of the candidate and the receiver match, and if the iclass parameter and the container class of the method are the same type, the candidate gets added to the list of overriden methods.
This code is all nice and pretty, and also works how I intended it to work, but I fear that it will blow up for a deep class hierarchy with lots of methods (like a collection framework), because the entire process is a strongly recursive operation that requires checking lots and lots of types and iterating through arrays of methods over and over again. Is there a less complex and more performant solution for large class trees, and how do other compilers (e.g. javac or scalac) solve this problem?

Related

How to make custom Tuple class generic?

I'm trying to make a generic tuple class. It stores its elements as an ArrayList. Of course, this class should override hashcode and equals methods.
How could I make hashcode method for this class? You see, in the code, I am having trouble.
Also, for the equals method, why does the compiler force me to use the '?'. Why couldn't I just use the T?
public static class Tuple<T> {
ArrayList<T> tuple = new ArrayList<>();
public Tuple(ArrayList<T> items) {
for (T item : items) {
tuple.add(item);
}
}
#Override
public int hashCode() {
T sum = ???;
for (T item : tuple) {
sum += item.hashCode();
}
return sum;
}
#Override
public boolean equals(Object o) {
if (o instanceof Tuple<?>) {
Tuple<?> tup= (Tuple<?>) o;
if (tup.tuple.size() != this.tuple.size()) {
return false;
}
for (int i = 0; i < this.tuple.size(); i++) {
if (this.tuple.get(i) != tup.tuple.get(i)) {
return false;
}
}
return true;
} else {
return false;
}
}
}
As mentioned in the comments, we should delegate the hashCode and the equals methods to the ArrayList<T> tuple instance variable. For the hashCode it's trivial. For the equals it's just a little more complicated than that because we don't want our custom Tuple to be equals with an ArrayList. So here it is:
public class Tuple<T> {
// I made this private because I'm pedantric ;)
private final ArrayList<T> tuple = new ArrayList<>();
// this does the same as your code, it's just easier to read
public Tuple(ArrayList<T> items) {
tuple.addAll(items);
}
#Override
public int hashCode() {
return tuple.hashCode();
}
// generated by eclipse
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tuple other = (Tuple) obj;
if (tuple == null) {
if (other.tuple != null)
return false;
} else if (!tuple.equals(other.tuple))
return false;
return true;
}
}
If you want to deal with the case when the tuple can be null, then you can use a slightly more complex hashCode:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tuple == null) ? 0 : tuple.hashCode());
return tuple.hashCode();
}
In general, I don't like to write these methods myself. Usually, I make my IDE to generate the stuff. All I need to take care of is to re-generate it when I add new fields. Apache HashCodeBuilder and EqualsBuilder are also great alternatives.

Is it possible to avoid duplicate code when implementing methods for two similar class?

I have two classes: Fish and Plant. They do not inherit from any classes.
But both of them have one method called isAlive() which have the same implementation details. Now I have a list of fish and another list of dog and I need to remove dead fish and dead dog. I want my method to have same name but it is not possible without adding additional field to method signature. Is it possible I do not need to write additional chunk of code which does the same as the last chunk of code?
Below is the code. For class Model, Fish and Plant are two data members and they are ArrayList of Fish and Plant objects.
Is there any way I can write only one method called count and I do not need to add additional field to my method signature or modify my return type?
public class Fish{
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Plant{
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Model{
private int countDeadFish() {
int totalCount = 0;
for(Fish aFish : this.fish) {
if(aFish.isAlive() == false) {
totalCount += 1;
}
}
return totalCount;
}
private int countDeadPlants() {
int totalCount = 0;
for(Plant plant : this.plants) {
if(plant.isAlive() == false) {
totalCount += 1;
}
}
return totalCount;
}
}
If you do not want to use inheritance, then you can use a common method:
public class AliveChecker {
public static boolean isAlive(int size) {
return size > 0;
}
}
public class Plant{
public boolean isAlive(){
return AliveChecker.isAlive(this.size);
}
}
public class Fish{
public boolean isAlive(){
return AliveChecker.isAlive(this.size);
}
}
Since Fishand Plant do not inherit from anything yet you can consider creating a superclass and extend from it:
public class LivingThing {
protected int size = 1;
public boolean isAlive() {
return size > 0;
}
}
public class Plant extends LivingThing {
}
public class Fish extends LivingThing {
}
This example uses inheritance to classify Plantand Fish into the superclass LivingThing. You can set the size for example in the constructor of the Plant or an instance method:
public class Plant extends LivingThing {
public Plant(int size){
this.size = size;
}
}
Your Model could then be:
public class Model{
private int countDeadFish() {
return countDead(this.fish);
}
private int countDeadPlants() {
return countDead(this.plants);
}
private int countDead(ArrayList<LivingThing> things) {
int totalCount = 0;
for(LivingThing thing: things) {
if(!thing.isAlive()) {
totalCount++;
}
}
return totalCount;
}
}
Use interface
public interface LiveObject {
boolean isAlive();
}
public class Fish implements LiveObject {
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Plant implements LiveObject {
public boolean isAlive(){
if(this.size > 0){
return true;
}
return false;
}
}
public class Model{
private int countDead(Collection<LiveObject> objects) {
int totalCount = 0;
for(LiveObject obj : objects) {
if(obj.isAlive() == false) {
totalCount += 1;
}
}
return totalCount;
}
private int countDeadFish() {
return countDead(this.fish);
}
}
Based on the comments it seems you can't modify Fish or Plant. Here's an approach to reduce duplication in countDead<Something> methods which does not require this.
Basically you want to count items in an array which satisfy certain criteria. With Java 8 you can capture this criteria in a predicate using lambdas or method references. You do not need inheritance or implementation of a certain interface for this.
private long countDeadFish() {
return countDeadItems(this.fish, Fish::isAlive);
}
private long countDeadPlants() {
return countDeadItems(this.plants, Plant::isAlive);
}
private <T> long countDeadItems(Collection<T> items, Predicate<? super T> isAlive) {
return items.stream().filter(isAlive.negate()).count();
}
You could create a utility method (in a utility class somewhere):
public final class Liveliness {
private Liveliness() {
}
public static boolean isAlive(final IntSupplier sizer) {
return sizer.getAsInt() > 0;
}
}
Your method then becomes:
public boolean isAlive(){
return Liveliness.isAlive(this::getSize);
}
Alternatively, use an interface Life:
public interface Life {
int getSize();
default boolean isAlive(){
return getSize() > 0;
}
}
This way, adding a getSize method and inheriting from Life will add the method.
Note, avoid the following antipattern:
if(test) {
return true;
} else {
return false;
}
Use return test.

GreenDao - caching of custom data does not work correctly

I have an entity with 3 one-to-many relations
private List<Data1> Data1;
private List<Data2> Data2;
private List<Data3> Data3;
and I want to summurize this data in a manually created list (TotalData just combines the three lists, for easier management...)
private transient TotalData mTotalData;
public TotalData getTotalData()
{
if (mTotalData == null)
mTotalData = new TotalData(getData1(), getData2(), getData3());
return mTotalData;
}
I load my entity with DaoSession.get...Dao().load(id)... On first creation everything works fine, on second creation, my mTotalData already exists and contains empty sublists... Why?
EDIT: my TotalData implementation
All data in the TotalData class are Entities!
public class WWorkoutObjectList
{
private ComparatorWWorkoutObject mComparator = new ComparatorWWorkoutObject();
private List<WWorkoutObject> mObjects = new ArrayList<WWorkoutObject>();
public WWorkoutObjectList(List<WExercise> wExercises, List<WCardio> wCardio, List<WPause> wPause)
{
init(wExercises, wCardio, wPause);
}
public void init(List<WExercise> wExercises, List<WCardio> wCardio, List<WPause> wPause)
{
synchronized (mObjects)
{
mObjects.clear();
for (int i = 0; i < wExercises.size(); i++)
mObjects.add(new WWorkoutObject(wExercises.get(i)));
for (int i = 0; i < wCardio.size(); i++)
mObjects.add(new WWorkoutObject(wCardio.get(i)));
for (int i = 0; i < wPause.size(); i++)
mObjects.add(new WWorkoutObject(wPause.get(i)));
sort();
}
}
public void add(WWorkoutObject wObject)
{
synchronized (mObjects)
{
mObjects.add(wObject);
sort();
}
}
public int size()
{
return mObjects.size();
}
public WWorkoutObject get(int index)
{
return mObjects.get(index);
}
public WWorkoutObject remove(int index)
{
return mObjects.remove(index);
}
// ----------------
// Hilfsfunktionen
// ----------------
public WExercise getNextExercise(int currentIndex)
{
synchronized (mObjects)
{
for (int i = currentIndex + 1; i < mObjects.size(); i++)
{
if (mObjects.get(i).isWCardio())
return null;
if (mObjects.get(i).isWExercise())
return mObjects.get(i).getWExercise();
}
}
return null;
}
public int getFragmentCount()
{
int counter = 0;
synchronized (mObjects)
{
for (int i = 0; i < mObjects.size(); i++)
{
if (mObjects.get(i).isFragmentObject())
counter++;
}
}
return counter;
}
public WWorkoutObject getFragmentObject(int fragmentIndex)
{
if (fragmentIndex < 0 || fragmentIndex >= mObjects.size())
return null;
int counter = 0;
synchronized (mObjects)
{
for (int i = 0; i < mObjects.size(); i++)
{
if (mObjects.get(i).isFragmentObject())
{
if (counter == fragmentIndex)
return mObjects.get(i);
counter++;
}
}
}
return null;
}
public List<WWorkoutObject> getFragmentsObjectsList()
{
List<WWorkoutObject> list = new ArrayList<WWorkoutObject>();
synchronized (mObjects)
{
for (int i = 0; i < mObjects.size(); i++)
{
if (mObjects.get(i).isFragmentObject())
list.add(mObjects.get(i));
}
}
return list;
}
public List<WWorkoutObject> list()
{
return mObjects;
}
// ----------------
// private Funktionen
// ----------------
private void sort()
{
Collections.sort(mObjects, mComparator);
}
}
Edit2: Flow example
I create an activity and load my Entity with id 1 (DaoSession.load(1))
I call getTotalData() => mTotalData is correct
I turn the screen and reload my now CACHED Entity with id 1 (DaoSession.load(1))) => mTotalData != null but all fields of it are empty... Because it is not null, if I now call getTotalData(), I get a TotalData object that did not update it's values... It looks like an object that was created with an empty constructor (which does not even exist)
I may solve that if I add a isInitialised variable to my TotalData and check this variable in getTotalData()... But still I don't know how the caching is working and why it's not working with my custom field...
Edit3
I am thankful for the feedback, but I think it's still not clear what exactly the problem is.
// Activity onCreate
public void onCreate(Bundle savedInstanceState)
{
WWorkout workout = DaoSession.load(1);
WWorkoutObjectList sortedData = workout.getWWorkoutObjects();
}
// Dao Entity custom function
public WWorkoutObjectList getWWorkoutObjects()
{
// I make sure, with calling the getter functions, that I load all sub entities before creating the list!!!
if (wWorkoutObjectList == null)
wWorkoutObjectList = new WWorkoutObjectList(getWExercise(), getWCardio(), getWPause());
return wWorkoutObjectList;
}
What I do:
I call getWWorkoutObjects() and get all correct data (all lists in WWorkout are loaded and sortedData is correct and filled
I NEVER edit data!!!
I recreate the activity (i.e. turn the screen) and get a correct entity (all lists in WWorkout are correct), BUT mObjects in sortedData is empty, but it exists already!!! Why?
As far as I understand, mObjects should be null or it should hold all data from the entity, but it can't differ, because the only constructor that exists is the one you can see above (that implicitly loads the sub lists of the entity).
Btw, the init function was private before, I only have made it public for a workaround and I did NOT edit any data to get this behaviour.
Probably the problem doesn't lie within the scope of greendao.
Remember that for example on orientation change the actual activity gets destroyed and recreated. Thus a private field of your activity is not garanteed to stay the same on orientation change. You have to take care of the correct state of your fields yourself.
You can do that:
by initializing your fields in onCreate()
by saving the state of your fields in onPause() and restoring it in onResume()
Of course you can also prevent your activity from being recreated on orientation changes. There are a lot posts about how to do that.
Try to move DaoSession.load(1) in the onCreate-method and call getTotalData() there as well. If you already have done that, please post your onCreate-method.
On top of that I'd recommend the following minor changes to your class.
Especially using synchronized on the methods, because there may be strange behaviours if variables you use inside the synchronized block, but that are defined outside the block.
public class WWorkoutObjectList
{
private ComparatorWWorkoutObject mComparator = new ComparatorWWorkoutObject();
private List<WWorkoutObject> mObjects = new ArrayList<WWorkoutObject>();
public WWorkoutObjectList(List<WExercise> wExercises, List<WCardio> wCardio, List<WPause> wPause)
{
init(wExercises, wCardio, wPause);
}
public synchronized void init(List<WExercise> wExercises, List<WCardio> wCardio, List<WPause> wPause)
{
mObjects.clear();
if (wExercises != null) {
for (WExercise we : wExercises) {
mObjects.add(new WWorkoutObject(we));
}
}
if (wCardio != null) {
for (WCardio wc : wCardio) {
mObjects.add(new WWorkoutObject(wc));
}
}
if (wPause != null) {
for (WPause wp : wPause) {
mObjects.add(new WWorkoutObject(wp));
}
}
sort();
}
public synchronized void add(WWorkoutObject wObject)
{
mObjects.add(wObject);
sort();
}
public int size()
{
return mObjects.size();
}
public WWorkoutObject get(int index)
{
return mObjects.get(index);
}
public synchronized WWorkoutObject remove(int index)
{
return mObjects.remove(index);
}
// ----------------
// Hilfsfunktionen
// ----------------
public synchronized WExercise getNextExercise(int currentIndex)
{
for (int i = currentIndex + 1; i < mObjects.size(); i++)
{
if (mObjects.get(i).isWCardio())
return null;
if (mObjects.get(i).isWExercise())
return mObjects.get(i).getWExercise();
}
return null;
}
public synchronized int getFragmentCount()
{
int counter = 0;
for (WWorkoutObject wo : mObjects)
{
if (wo.isFragmentObject())
counter++;
}
return counter;
}
public synchronized WWorkoutObject getFragmentObject(int fragmentIndex)
{
if (fragmentIndex < 0 || fragmentIndex >= mObjects.size())
return null;
int counter = 0;
for (WWorkoutObject wo : mObjects)
{
if (wo.isFragmentObject())
{
if (counter == fragmentIndex)
return mObjects.get(i);
counter++;
}
}
return null;
}
public synchronized List<WWorkoutObject> getFragmentsObjectsList()
{
List<WWorkoutObject> list = new ArrayList<WWorkoutObject>();
for (WWorkoutObject wo : mObjects)
{
if (wo.isFragmentObject())
list.add(wo);
}
return list;
}
public synchronized List<WWorkoutObject> list()
{
ArrayList<WWorkoutObject> result = new ArrayList<WWorkoutObject>();
for (WWorkoutObject wo : mObjects)
result.add(wo);
return result;
}
// ----------------
// private Funktionen
// ----------------
private void sort()
{
Collections.sort(mObjects, mComparator);
}
}

Java: Get method with interface parameter with its implementation

I would like to call method(using reflection) which has parameter Interface - i.e: List but with implementation of List.
For example:
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test1.class.getMethod("method", new Class[]{ArrayList.class});
}
public class Test1 {
public void method(List list) {
System.out.println("method");
}
}
}
I get NoSuchMethodException. In this case i know which params i get, problem is that I want to use this in general when i don't "statically" know param types.
Is possible that getMethod returns also method which has interface as parameter? Or i have to write my own "methodsearcher"
Thank you.
EDIT:
It's much more complicated. I'm trying to write something like "dynamic modular architecture" in my program. I have Core, which should comunicate with other modules. So i don't know params classes in programming time but in runtime.
public Object processMessage(String target, String methodName, List<Object> params, Object returnNonExist) {
Module m = modules.get(target);
if (m == null) {
return returnNonExist;
} else {
Class[] paramsTypes = new Class[params.size()];
for (int i = 0; i < params.size(); i++) {
paramsTypes[i] = params.get(i).getClass();
}
}
try {
Method method = m.getClass().getMethod(methodName, paramsTypes);
Object result = method.invoke(m, params.toArray());
return result;
}
Is it better?
I probably found solution - I have to write my own "method searcher" which respect interface implementation and superclases. It looks like this:
public static Method findMethod(Object m, String methodName, Class[] paramsTypes) {
Method[] metody = m.getClass().getDeclaredMethods();
List<Method> sameNames = new ArrayList<Method>();
// filter other names
for (Method meth : metody) {
if (meth.getName().equals(methodName)) {
sameNames.add(meth);
}
}
// lets find best candidate
if (sameNames.isEmpty()) {
return null;
} else {
// filter other count of parameters
List<Method> sameCountOfParameters = new ArrayList<Method>();
for (Method meth : sameNames) {
if (meth.getParameterTypes().length == paramsTypes.length) {
sameCountOfParameters.add(meth);
}
}
if (sameCountOfParameters.isEmpty()) {
return null;
} else {
for (Method meth : sameCountOfParameters) {
// first one, which is suitable is the best
Class<?>[] params = meth.getParameterTypes();
boolean good = true;
for (int i = 0; i < params.length && good; i++) {
if (params[i].isInterface() && Arrays.asList(paramsTypes[i].getInterfaces()).contains(params[i])) {
//if i-th paramater type is Interface and we search method with its implementation
good = true;
continue;
} else {
// if we call it with subclass and parameter typ is superclass
if (paramsTypes[i].getSuperclass().equals(params[i])) {
good = true;
continue;
}
}
good = false;
}
if (good) {
return meth;
}
}
}
}
return null;
}
I'am using this after standard getMethod throws "NoSuchMethodException" (It is in about 5% cases, so i don't care about speed.
You should use List class, not ArrayList.
Method method = Test1.class.getMethod("method", new Class[]{List.class});
Great answer from #radeczek. I extended it to work on subclasses ...
public Method findMethod(String name, Class<?>[] paramsTypes) {
Method[] methods = object.getClass().getMethods();
List<Method> sameNames = new ArrayList<Method>();
// filter other names
for (Method m : methods) {
if (m.getName().equals(name)) {
sameNames.add(m);
}
}
// lets find best candidate
if (sameNames.isEmpty()) {
return null;
} else {
// filter other count of parameters
List<Method> sameCountOfParameters = new ArrayList<Method>();
for (Method m : sameNames) {
if (m.getParameterTypes().length == paramsTypes.length) {
sameCountOfParameters.add(m);
}
}
if (sameCountOfParameters.isEmpty()) {
return null;
} else {
for (Method m : sameCountOfParameters) {
// first one, which is suitable is the best
Class<?>[] params = m.getParameterTypes();
boolean good = true;
for (int i = 0; i < params.length && good; i++) {
// Recurse into subclasses
good = findSubclass(paramsTypes[i],params[i]);
}
if (good) {
return m;
}
}
}
}
return null;
}
/**
* Recursive check for interfaces of superclasses.
*
* #param paramType
* #param param
* #return
*/
private boolean findSubclass(Class<?> paramType, Class<?> param) {
if (param.isInterface() && Arrays.asList(paramType.getInterfaces()).contains(param)) {
return true;
} else {
if (paramType.getSuperclass() != null) {
return findSubclass(paramType.getSuperclass(), param);
} else {
return false;
}
}
}

Is there any way to implement compareTo method which would compare any supplied argument?

The compiler says " cannot find symbol: method compareTo(java.lang.Object) ". Could you please advice where is the mistake here?
Here is the part of the code:
public class OBTComparable<ObjectType> implements Comparable<OBTComparable>
{
public OTBComparable leftNode = null;
public OBTComparable mainNode = null;
public OBTComparable rightNode = null;
public ObjectType object = null;
public OBTComparable(ObjectType requiredObject)
{
object = requiredObject;
}
#Override
public int compareTo(OBTComparable other)
{
if(object.compareTo(other.object) == 0)
return 0;
else
if (object.compareTo(other.object) > 0)
return 1;
else return -1;
}
}
You need to scope ObjectType to Comparable too, because OBTComparable is delegating compareTo() to ObjectType:
If you change <ObjectType> to <ObjectType extends Comparable<ObjectType>>, it will compile:
public class OBTComparable<ObjectType extends Comparable<ObjectType>> implements Comparable<OBTComparable>
I think this is the proper code you are looking for (I replaced ObjectType with T for clarity):
class OBTComparable<T extends Comparable<? super T>> implements Comparable<OBTComparable<T>> {
public OBTComparable<T> leftNode = null;
public OBTComparable<T> mainNode = null;
public OBTComparable<T> rightNode = null;
public T object = null;
public OBTComparable(T requiredObject) {
object = requiredObject;
}
#Override
public int compareTo(OBTComparable<T> other) {
if (object.compareTo(other.object) == 0) {
return 0;
} else if (object.compareTo(other.object) > 0) {
return 1;
} else return -1;
}
}
What did I change here:
OBTComparable uses a type parameter, so you should show it when you implement Comparable. Therefore you have implements Comparable<OBTComparable<T>> instead of simply implements Comparable<OBTComparable>.
You compare two objects in the compareTo method, but are they comparable? To make sure this requirement is fulfilled, you should write OBTComparable<T extends Comparable<T>> instead of just OBTComparable<T>. Then you will know that you can call compareTo.
ObjectType must also implement Comparable<ObjectType>.
And if you do this, I believe that this:
public int compareTo(OBTComparable other)
{
if(object.compareTo(other.object) == 0)
return 0;
else
if (object.compareTo(other.object) > 0)
return 1;
else return -1;
}
can be simplified to this:
public int compareTo(OBTComparable other)
{
return object.compareTo(other.object);
}

Categories