Issue implementing the java Comparable<T> class - java

The graphic below shows a compilation error involving my if-else conditional when attempting to implement the compareTo() method located in my Tool class. I am uncertain of the issue, as it would appear that the method is public and within my Tool class (from which the two objects being compared are constructed).
public interface Product {
public abstract String getName();
public abstract double getCost();
}
public abstract class Vehicle implements Product {
private String name;
private double cost;
public Vehicle(String name, double cost) {
this.name = name;
this.cost = cost;
}
public String getName() {
return name;
}
public double getCost() {
return cost;
}
}
public class Car extends Vehicle {
public Car(String s, double d) {
super(s, d);
}
}
public class Truck extends Vehicle {
public Truck(String s, double d) {
super(s, d);
}
}
public class Tool implements Product, Comparable<Product> {
private String name;
private double cost;
public Tool(String name, double cost) {
this.name = name;
this.cost = cost;
}
public String getName() {
return name;
}
public double getCost() {
return cost;
}
public int compareTo(Product obj) {
if (getCost() < obj.getCost()) {
return -1;
} else if (getCost() == obj.getCost()) {
return 0;
} else {
return 1;
}
}
}
import java.util.*;
public class InventoryDemo
{
public static void main(String [] args) {
ArrayList<Product> list = new ArrayList<Product>();
list.add(new Car("Jagur", 1000000));
list.add(new Car("Neon", 17000));
list.add(new Tool("JigSaw", 149.18));
list.add(new Car("Jaguar", 110000));
list.add(new Car("Neon", 17500));
list.add(new Car("Neon", 17875.32));
list.add(new Truck("RAM", 35700));
list.add(new Tool("CircularSaw", 200));
list.add(new Tool("CircularSaw", 150));
list.add(new Tool("saw1", 200));
list.add(new Tool("saw2", 150));
if(list.get(9).compareTo(list.get(10)) == 0) {
System.out.println("\nThey are the same size using compareTo().");
} else {
System.out.println("\nThey are not the same size using compareTo().");
}
}
}

The Problem is your list is of type List<Product>, but product does not implement the Comparable interface, therefore this type does not implement the method.
Make
public interface Product extends Comparable<Product> {
public abstract String getName();
public abstract double getCost();
}

Your Product interface doesn't extend Comparable<Product> which adds
int compareTo(Product other);
list is declared as ArrayList<Product>, so list.get(9) will return you Product object.
To resolve issue you have either to make Product extend Comparable<Product> and implement method in Vehicle, or, maybe, use equals() method instead, overriding default implementation. Actually the second way is preferrable, because equals() method checks whether objects are equal, while compareTo() tells you if this object is greater then other, or other is greater than this, or none of that is applicable - which makes equals() usage more semantically correct in your case.

Your list is an ArrayList<Product>, so list.get(9) returns a Product.
The compareTo(Product) method is not defined in interface Product. It's defined in class Tool, but you're trying to call it on a Product, which is not (always) a Tool.
To solve this: Make your interface Product extend Comparable<Product>:
interface Product extends Comparable<Product> {
Ofcourse that means that any (non-abstract) class that implements interface Product must also have a public int compareTo(Product obj) method.

The list item you are trying to call compareTo() on is a Product, because the list is declared as a list of Products:
ArrayList<Product> list = new ArrayList<Product>();
When accessing items in the list, Java is only aware that the items implement the Product interface, irrespective of whether the actual class also implements Comparable.
One solution is to define Product as extending Comparable:
public interface Product extends Comparable<Product> {
public abstract String getName();
public abstract double getCost();
}

Related

How to cast an object of an ArrayList of objects (of type superclass) to an object of type subclass

If I have a superclass, let's call it Car, with the constructor parameters String name, String color, double wheelSize, and a subclass of this, let's call it Truck, with the constructor parameters String name, String color, double wheelSize, and double truckBedArea, and in the subclass (Truck), I have a method called modifyCar with the paramaters Car car, String newName, String newColor, double newWheelSize, and double newTruckBedArea, how can I find a way to take that Car object and specify that it is indeed a Truck, so I can then use a Truck setter (setTruckBedArea) to set the new truck bed area? This example isn't a great comparison to my actual assignment, but I have an ArrayList field of my superclass (Cars) called "ArrayList cars" of "Car" objects, and I need to find a way to change that "Car" object in this ArrayList field, which I have already found a way of doing. I simply loop through each item in the ArrayList of "Cars" until it equals the instance of the Car put in as a parameter, and if it does, I then say "cars.get(i).//setter" (essentially). However, it would not work if I say "cars.get(i).setTruckBedArea(newTruckBedArea)". I am not sure how to cast the Car object within this list of Cars to a Truck specifically, so I can then access the setter I want to use. The main issue is that I am required to implement an interface (let's call it "Vehicle") wherein the ArrayList cars has to be of type cars, since it is specified to be that in the Vehicle interface (otherwise I would just change the ArrayList field to be ArrayList trucks).
Example:
public class Truck implements Vehicle { //have to implement this interface
//... other fields
private ArrayList<Car> cars;
//... other methods/constructors
public void modifyCar(Car car, String newName, String newColor, double newWheelSize, double newTruckBedArea) {
//have to have "Car car" as parameter for this method because of interface
for (int i = 0; i < cars.size(); i++) {
if (cars.get(i).equals(car)) {
cars.get(i).setColor(newColor);
cars.get(i).setName(newName);
cars.get(i).setWheelSize(newWheelSize);
cars.get(i).setTruckBedArea(newTruckBedArea); //will produce error
}
}
}
}
As far as I understand the question, you can use "instanceof" operator:
if(cars.get(i) instanceof Truck){
Truck truck = (Truck) cars.get(i);
truck.setTruckBedArea(newTruckBedArea);
}
instanceof operator returns a boolean value in result of whether an object is an instance of given type or not.
Vehicle should be an Abstract class.
Car Interface
public interface Car {
void modifyCar(Car car, String newName, String newColor, double newWheelSize, double newTruckBedArea);
}
Vehicle Abstract Class
public abstract class Vehicle implements Car {
String name;
String color;
double wheelSize;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWheelSize() {
return wheelSize;
}
public void setWheelSize(double wheelSize) {
this.wheelSize = wheelSize;
}
}
Truck Class
public class Truck extends Vehicle {
double truckBedArea;
private ArrayList<Car> cars;
public double getTruckBedArea() {
return truckBedArea;
}
public void setTruckBedArea(double truckBedArea) {
this.truckBedArea = truckBedArea;
}
public ArrayList<Car> getCars() {
return cars;
}
public void setCars(ArrayList<Car> cars) {
this.cars = cars;
}
#Override
public void modifyCar(Car car, String newName, String newColor, double newWheelSize, double newTruckBedArea) {
for (int i = 0; i < cars.size(); i++) {
if (cars.get(i).equals(car)){
((Vehicle)cars.get(i)).setColor(newColor);
((Vehicle)cars.get(i)).setWheelSize(newWheelSize);
((Truck)cars.get(i)).setTruckBedArea(newTruckBedArea);
}
}
}
}
Run code.
public static void main(String[] args) {
// TODO code application logic here
Truck trucks = new Truck();
trucks.setColor("Red");
trucks.setName("Nissan");
trucks.setWheelSize(20.15);
trucks.setTruckBedArea(3.5);
ArrayList<Car> cars = new ArrayList<Car>();
cars.add(trucks);
trucks.setCars(cars);
trucks.modifyCar(trucks, "Kia", "Blue", 15.5, 14.0);
System.out.println(trucks.getTruckBedArea());
}

Problem with Array.sort() and objects in JAVA [duplicate]

I am not sure how to implement a comparable interface into my abstract class. I have the following example code that I am using to try and get my head around it:
public class Animal{
public String name;
public int yearDiscovered;
public String population;
public Animal(String name, int yearDiscovered, String population){
this.name = name;
this.yearDiscovered = yearDiscovered;
this.population = population; }
public String toString(){
String s = "Animal name: "+ name+"\nYear Discovered: "+yearDiscovered+"\nPopulation: "+population;
return s;
}
}
I have a test class that will create objects of type Animal however I want to have a comparable interface inside this class so that older years of discovery rank higher than low. I have no idea on how to go about this though.
You just have to define that Animal implements Comparable<Animal> i.e. public class Animal implements Comparable<Animal>. And then you have to implement the compareTo(Animal other) method that way you like it.
#Override
public int compareTo(Animal other) {
return Integer.compare(this.year_discovered, other.year_discovered);
}
Using this implementation of compareTo, animals with a higher year_discovered will get ordered higher. I hope you get the idea of Comparable and compareTo with this example.
You need to:
Add implements Comparable<Animal> to the class declaration; and
Implement a int compareTo( Animal a ) method to perform the comparisons.
Like this:
public class Animal implements Comparable<Animal>{
public String name;
public int year_discovered;
public String population;
public Animal(String name, int year_discovered, String population){
this.name = name;
this.year_discovered = year_discovered;
this.population = population;
}
public String toString(){
String s = "Animal name: "+ name+"\nYear Discovered: "+year_discovered+"\nPopulation: "+population;
return s;
}
#Override
public int compareTo( final Animal o) {
return Integer.compare(this.year_discovered, o.year_discovered);
}
}
While you are in it, I suggest to remember some key facts about compareTo() methods
CompareTo must be in consistent with equals method e.g. if two objects are equal via equals() , there compareTo() must return zero otherwise if those objects are stored in SortedSet or SortedMap they will not behave properly.
CompareTo() must throw NullPointerException if current object get compared to null object as opposed to equals() which return false on such scenario.
Read more: http://javarevisited.blogspot.com/2011/11/how-to-override-compareto-method-in.html#ixzz4B4EMGha3
Implement Comparable<Animal> interface in your class and provide implementation of int compareTo(Animal other) method in your class.See This Post
You would need to implement the interface and define the compareTo() method.
For a good tutorial go to - Tutorials point link
or
MyKongLink
Emp class needs to implement Comaparable interface so we need to Override its compateTo method.
import java.util.ArrayList;
import java.util.Collections;
class Emp implements Comparable< Emp >{
int empid;
String name;
Emp(int empid,String name){
this.empid = empid;
this.name = name;
}
#Override
public String toString(){
return empid+" "+name;
}
#Override
public int compareTo(Emp o) {
if(this.empid==o.empid){
return 0;
}
else if(this.empid < o.empid){
return 1;
}
else{
return -1;
}
}
}
public class JavaApplication1 {
public static void main(String[] args) {
ArrayList<Emp> a= new ArrayList<Emp>();
a.add(new Emp(10,"Mahadev"));
a.add(new Emp(50,"Ashish"));
a.add(new Emp(40,"Amit"));
Collections.sort(a);
for(Emp id:a){
System.out.println(id);
}
}
}
Possible alternative from the source code of Integer.compare method which requires API Version 19 is :
public int compareTo(Animal other) {
return Integer.valueOf(this.year_discovered).compareTo(other.year_discovered);
}
This alternative does not require you to use API version 19.
Use a Comparator...
public class AnimalAgeComparator implements Comparator<Animal> {
#Override
public int compare(Animal a1, Animal a2) {
...
}
}
This thing can easily be done by implementing a public class that implements Comparable. This will allow you to use compareTo method which can be used with any other object to which you wish to compare.
for example you can implement it in this way:
public String compareTo(Animal oth)
{
return String.compare(this.population, oth.population);
}
I think this might solve your purpose.

Working with enum types in java

I need to create a "super" enum (here ESideItem) which will keep record of "sub" enums (SALAD, FRY, TACO) & I need to access "sub" enum's fields(price) from outside too.
I meant "super" as main type & "sub" as sub-type of that main type.
There can be many types of SideItems (FRY, SALAD, TACO) for a meal & each of these sideitems can be of many types (i.e SALAD can be CHICKEN or AFGHAN or MIMOSA etc).
Following Ray Tayek's answer to this question I've implemented this:
public abstract class SideItem {
public enum FRY {
FRENCHFRY(25.25f), SEASONEDCURLYFRY(30.10f);
private float price;
FRY(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
}
public enum SALAD{
AFGHANSALAD(50.25f), CHICKENSALAD(40.10f), MIMOSASALAD(45.89f);
private float price;
SALAD(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
}
public enum TACO{
MONSTERTACO(26.25f), NACHOMONSTERTACO(35.10f);
private float price;
TACO(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
}
public enum ESideItem {
FRY(SideItem.FRY.FRENCHFRY), SALAD(SideItem.SALAD.AFGHANSALAD), TACO(SideItem.TACO.MONSTERTACO);
ESideItem(Enum e) {
this.e = e;
}
public Object[] subValues() {
return e.getDeclaringClass().getEnumConstants();
}
final Enum e;
}
}
I implementd Main.java as follows:
public class Main {
public static void main(String[] args) {
for(SideItem.ESideItem aSideItem : SideItem.ESideItem.values()){
System.out.println(aSideItem);
for(Object o : aSideItem.subValues()){
System.out.format("%-15s",o);
System.out.println();
}
System.out.println();
}
}
}
The output is:
FRY
FRENCHFRY
SEASONEDCURLYFRY
SALAD
AFGHANSALAD
CHICKENSALAD
MIMOSASALAD
TACO
MONSTERTACO
NACHOMONSTERTACO
Main.java is like client side & SideItem.java is like server side. I can change or add any instance in the ESubItem enum from SideItem.java. Main.java should give output according to that change
But I do need to get price of these individual TACO's, SALAD's, FRY's . Is there any way to access these fields from Main.java using enum?
If not then what kind of data structure should I use to solve this problem ?
You should be using an interface:
interface Food
{
float getPrice();
}
public enum Fry implements Food
{
FRENCH_FRY(25.25f), SEASONED_CURLY_FRY(30.10f);
private final float price;
FRY(float price) {
this.price = price;
}
#Override
public float getPrice() {
return price;
}
}
And the same for the other two...
Then you can compose them like so:
public enum Meal implements Food {
HAPPY_MEAL(Fry.FRENCH_FRY, Fry.SEASONED_CURLY_FRY),
SAD_MEAL(Salad.AFGHAN_SALAD);
private final List<Food> items;
Meal (Food... items) {
this.items = Arrays.asList(food);
}
#Override
public float getPrice()
{
return (float) items.stream().mapToDouble(Food::getPrice).sum();
}
}
If you want to access the price for calculations etc. the easiest way is to make all those enums implement an interface with public float getPrice().
For display purposes you would only need to modify the toString() of each enum.
The enum ESideItem and SideItem classes seem unnecessary though. Especially the ESideItem doesn't seem like it should be an enum at all, and the way you're using getDeclaringClass().getEnumConstants() is just a really bad idea.
You will need to something like:
for(Object o : aSideItem.subValues()){
if(o instanceof SideItem.FRY)
((SideItem.FRY)o).getPrice()
You can define an interface, say
public interface Priced {
double getPrice();
}
The enums can implement that
public enum FRY implements Priced { // no further change needed, method already there
and you can return an array of Priced with your subValues().
public Priced[] subValues() {
return Stream.of(FRY.values(), SALAD.values(), TACO.values()).
toArray(Priced[]::new);
}
I'm not entirely sure if the latter works this way, but being able to implement an interface in your enum is the main point.

java compareTo method implementation

currently I'm trying to find out how java's interface "Comparable" works.
As far as I know inteface cannot have any non-static (besides default ones) methods so when we implement an interface we need to define its methods first.
But when I implement "Comparable" interface I obviously can use its compareTo method. Where is that method defined?
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
How come that I'm able to use interface's method without even defining it?
My apoligies if there was already an answer to that question, wasn't able to find it though.
Thx.
The elements of your T[] array must be of some type that implements Comparable<T> (as a result of the <T extends Comparable<T>> type bound). Therefore you can call compareTo() on elements of that array.
Where compareTo is implemented depends on which array you are passing to your method. If, for example, you pass a String[], the compareTo method of the String class will be used.
To your code:
You have defined a type T as a sub-class of "Comparable" within your signature and it is used within the parameters as you pass in an array of "T" ( T[] ). The compiler now knows that any T must be at least a Comparable.
Further information:
In general I do not suggest to implement Comparable directly. The reason for that is that comparison is always within a context you do not know.
You should favor the Comparator-interface over the Comparable-interface to implement comparisons with a specific contexts. If you want to define a natural order you can provide a natural comparator as a public constant.
Some examples:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorExample {
public static void main(String[] args) {
List<SomeObject> list = new ArrayList<>();
list.add(new SomeObject(1, "dhjf", "A"));
list.add(new SomeObject(4, "ghdg", "A"));
list.add(new SomeObject(6, "uztzt", "B"));
list.add(new SomeObject(1, "jhgf", "C"));
list.add(new SomeObject(3, "vbbn", "A"));
list.add(new SomeObject(99, "cvcxc", "A"));
list.add(new SomeObject(2, "dfdd", "G"));
// examples
Collections.sort(list, SomeObject.NATURAL);
Collections.sort(list, LexicographicOrderByCategoryAndName.INSTANCE);
LexicographicOrderByName.INSTANCE.compare(new SomeObject(99, "cvcxc", "A"), new SomeObject(54, "fdjnn", "C"));
}
public static class SomeObject {
public static Comparator<SomeObject> NATURAL = new Comparator<SomeObject>() {
#Override
public int compare(SomeObject arg0, SomeObject arg1) {
return arg1.getId() - arg0.getId();
}
};
private int id;
private String name;
private String category;
public SomeObject(int id, String name, String category) {
this.id = id;
this.name = name;
this.category = category;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getCategory() {
return category;
}
}
public static class LexicographicOrderByName implements Comparator<SomeObject> {
public static LexicographicOrderByName INSTANCE = new LexicographicOrderByName();
private LexicographicOrderByName() {
}
#Override
public int compare(SomeObject o1, SomeObject o2) {
return o1.getName().compareTo(o2.getName());
}
}
public static class LexicographicOrderByCategoryAndName implements Comparator<SomeObject> {
public static LexicographicOrderByCategoryAndName INSTANCE = new LexicographicOrderByCategoryAndName();
private LexicographicOrderByCategoryAndName() {
}
#Override
public int compare(SomeObject o1, SomeObject o2) {
int c = o1.getCategory().compareTo(o2.getCategory());
if (c == 0) {
c = o1.getName().compareTo(o2.getName());
}
return c;
}
}
}
The problem with the Comparable-interface is that once you decided a specific comparison of an object you are bound to it forever. You may may change it but expect side effects as you do not know if all contexts have the same erasure and should change too.

CompareTo of comparable does not take arguments other than Object type.

It seems odd that this is not working as I expected. I wrote a simple java class that implements Comparable interface and override the compareTo() method. However, It doesn't let me pass arguments of specific type other than Object. I looked on other guys' codes online which they did used other typed objects and I copied their code into eclipse and still I got the same error.
My question is; what I have to do to compare this object with object of type lets say Person. I do have the same issue with Comparator Interface (compare() method).
This code is the one I found it online.
public class Person implements Comparable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return this.age;
}
public String getName() {
return this.name;
}
#Override
public String toString() {
return "";
}
#Override
public int compareTo(Person per) {
if(this.age == per.age)
return 0;
else
return this.age > per.age ? 1 : -1;
}
public static void main(String[] args) {
Person e1 = new Person("Adam", 45);
Person e2 = new Person("Steve", 60);
int retval = e1.compareTo(e2);
switch(retval) {
case -1: {
System.out.println("The " + e2.getName() + " is older!");
break;
}
case 1: {
System.out.println("The " + e1.getName() + " is older!");
break;
}
default:
System.out.println("The two persons are of the same age!");
}
}
}
You need to use generics to provide a specific type.
public class Person implements Comparable<Person> { // Note the generic to Person here.
public int compareTo(Person o) {}
}
The Comparable interface is defined something like this,
public interface Comparable<T> {
public int compareTo(T o);
}
You can make use of generics to use custom object types. Change your class definition from
public class Person implements Comparable {
to
public class Person implements Comparable<Person> {
Now you should be able to pass Person object to your compareTo method as mentioned here:
#Override
public int compareTo(Person personToCompare){
Learn more about generics here:
https://docs.oracle.com/javase/tutorial/java/generics/types.html

Categories