Is String not considered an object? - java

What I do not understand is why I am getting an error compiling my code when a String is in fact an object, and the compiler is saying otherwise. I dont know why I keep getting this error message
symbol: method compareTo(Object)
location: variable least of type Object
.\DataSet.java:17: error: cannot find symbol
else if(maximum.compareTo(x) < 0)
here is the code. I'm trying to utilize the class comparable to allow two objects to use the compareTo method. In the tester, I'm just trying to use a basic string object to compare.
public class DataSetTester
{
public static void main(String[] args)
{
DataSet ds = new DataSet();
String man = "dog";
String woman = "cat";
ds.add(man);
ds.add(woman);
System.out.println("Maximum Word: " + ds.getMaximum());
}
}
Class:
public class DataSet implements Comparable
{
private Object maximum;
private Object least;
private int count;
private int answer;
public void add(Object x)
{
if(count == 0){
least = x;
maximum = x;
}
else if(least.compareTo(x) > 0)
least = x;
else if(maximum.compareTo(x) < 0)
maximum = x;
count++;
}
public int compareTo(Object anObject)
{
return this.compareTo(anObject);
}
public Object getMaximum()
{
return maximum;
}
public Object getLeast()
{
return least;
}
}
Comparable Interface:
public interface Comparable
{
public int compareTo(Object anObject);
}

Of course String is an Object.
Comparable is generic now. Why do you feel the need to make those references Object if they are type String? Your code is poor; it's not a Java problem.
I don't see why DataSet needs to implement Comparable. You just need to compare incoming Strings as they're added. Do it this way and you'll fare better:
public class DataSet {
private String maximum;
private String least;
private int count;
private int answer;
public void add(String x) {
if(count == 0){
least = x;
maximum = x;
} else if (least.compareTo(x) > 0) {
least = x;
} else if(maximum.compareTo(x) < 0) {
maximum = x;
}
count++;
}
public String getMaximum() { return this.maximum; }
public String getLeast() { return this.least; }
public int getCount() { return this.count; }
}

The problem is that DataSet implements Comparable, but Object doesn't.
Instead of storing Objects, you want to store Comparables. However, if you do get this to compile, you will get into an infinite loop right here:
public int compareTo(Object anObject)
{
// Yeah, never stop loopin'!
return this.compareTo(anObject);
}
It's recommended that in newer code, you use the generic Comparable<T> interface. Your code would then look like this:
public class DataSet implements Comparable<DataSet>
{
private String maximum;
private String least;
private int count;
private int answer;
public void add(String x)
{
if(count == 0){
least = x;
maximum = x;
}
else if(least.compareTo(x) > 0)
least = x;
else if(maximum.compareTo(x) < 0)
maximum = x;
count++;
}
public int compareTo(DataSet anObject)
{
// I don't really know how you want this to work.
// Come up with your own criteria on what makes a DataSet greater or less than
// another one.
count - anObject.count
}
// Good practice to include this if you're doing a compareTo.
#Override
public boolean equals(Object other)
{
return (other instanceof DataSet) && compareTo((DataSet)other) == 0;
}
public String getMaximum()
{
return maximum;
}
public String getLeast()
{
return least;
}
}
Edit - just saw that you're comparing strings. In that case, you don't really need DataSet to implement Comparable. However, if you do need it for something else, what I wrote still stands.

least and maximum are simply Objects, and the Object class doesn't have a compareTo(...) method, simple as that. least and maximum need to be declared Comparable, not Object. And as written, it makes no sense declaring DataSet to implement the Comparable interface since there are no DataSet objects present and certainly none being compared.

java.lang.Object does not have a compareTo() method.

First of all there is an infinite loop in you code:
public int compareTo(Object anObject)
{
return this.compareTo(anObject);
}
this method is continuously calling itself.
Regarding your compile error: you have declared variable as Object, which obviously does not have a compareTo method.

There is no compareTo() method in Object. I guess you're looking for String.compareTo().

Type checking is done at compile time and not runtime. At compile time, least and maximum are considered to be objects of type Object and not String.

Related

The use of relational operator inside binarySearch() method which is a generics is giving error.How to handle this situation?

Here's my java code and the problem is that the use of relational
operator(<) inside binarySearch() is giving error.
I guess this error I am getting because the operands are of type object.
How to remove this error so my function runs perfectly?
import java.util.Random;
import java.util.Arrays;
class BinarySearch
{
public static void main(String $[])
{
Integer arr[]=new Integer[20];
for(int i=0;i<20;i++)
arr[i]=(new Random()).nextInt()%10000;
display("Initial array :\n");
array(arr);
Arrays.sort(arr);
display("After sorting :\n");
array(arr);
display("Enter the element to be searched for : ");
Integer elem=(new java.util.Scanner(System.in)).nextInt();
display(elem+(binarySearch(arr,elem)?" Found":" Not found")+"\n");
}
public static <T>boolean binarySearch(T arr[],T val)
{
int start=0;
int end=arr.length-1;
while(start<=end)
{
int mid=(start+end)/2;
if(arr[mid]==val)
return true;
if(arr[mid]<val)
start=mid+1;
else
end=mid-1;
}
return false;
}
public static void display(Object o)
{
System.out.print(o);
}
public static <T>void array(T arr[])
{
for(int i=0;i<arr.length;i++)
display(arr[i]+" ");
display("\n");
}
}
The problem is that your binarySearch() method is accepting parameters that will be Objects rather than primitive types, so it is unwise to compare them using the equality operator == and invalid to compare them using the less than operator <. Instead define your binarySearch method as follows:
public static <T extends Comparable<T>> boolean binarySearch(T arr[],T val) {
int start = 0;
int end = arr.length-1;
while(start <= end) {
int mid=(start+end)/2;
int comparison = arr[mid].compareTo(val);
if(comparison == 0) {
return true;
}
if(comparison < 0) {
start = mid+1;
}
else {
end = mid-1;
}
}
return false;
}
Read here about generics. Since all generics are objects - you can't use comparison operators with them. Even if you type <T extends Number.
There are two ways to handle this:
Pass Comparator<T> to the method and use comparator.compare(arr[mid], val) for comparing values.
Write <T extends Comparable> and call arr[mid].compareTo(val).
Both these methods return an integer value:
0, if values are equal
negative, if first value less than second
positive, if first value greater than second

Calling a 'dynamic' Object of a HashMap

I just came to the problem where I want to call a function of an Object inside a HashMap. I already searched it up and found one thread but sadly I don't understand it.
So here's my code
public class Seat {
//some attributes
public int getNumber() {
return number;
}
public boolean isReserved() {
return status;
}
}
public class Hall {
private HashMap mySeats;
public HashMap getMeinePlaetze() {
return meinePlaetze;
}
public void createSeats() {
for (int i = 1; i <= this.getnumberOfSeats(); i++) {
this.getMySeats().put(i, new Seat(i, 1));
}
}
}
public class Main {
Hall h1 = new Hall(...);
h1.createSeats();
h1.getMySeats().get(2).isReserved(); //How do I have to write this to work out?
}
I hope my intend is reasonable. Feel free to correct me if my code sucks. I already apologize for it.
Thank you very much.
Since version 5, Java has a feature called Generics. You'll find a lot about generics on the web, from articles, blog posts, etc to very good answers here on StackOverflow.
Generics allows Java to be a strongly typed language. This means that variables in Java can not only be declared to be of some type (i.e. HashMap), but also to be of some type along with one or more generic type parameters (i.e. HashMap<K, V>, where K represents the type parameter of the keys of the map and V represents the type parameter of the values of the map).
In your example, you are using a raw HashMap (raw types are types that allow for generic type parameters to be specified, however the developer has not specified them). Raw types are considered bad practice and are highly error-prone, as you are experiencing right now.
HashMap allows two generic type parameters (one for the keys and another one for the values). In your case, you are using Integer for the keys and Seat for the values. Put into simple words, you are mapping integers to seats, or you can also say that your map is a map of integers to seats.
So, inside you Hall class, you should define your map with its generic type parameters:
private Map<Integer, Seat> mySeats = new HashMap<>();
Then, this code:
h1.getMySeats().get(2)
will return an instance of type Seat, because your map already knows that all its values are of type Seat.
So your code:
h1.getMySeats().get(2).isReserved();
will compile fine and will work without any errors.
Please note that, apart from declaring the generic types of your map, I've also changed two additional things.
First, I've created an actual instance of HashMap by using its constructor:
mySeats = new HashMap<>()
If you don't create an instance of your type with new, there won't be any HashMap instance where to put your seats later, and you'll get a NullpointerException (try it!).
Secondly, I've changed the type of the variable from HashMap to Map. HashMap is a class, while Map is just an interface. The thing is that the HashMap class implements the Map interface, so, unless your code explicitly needs to access a method of HashMap that is not declared in the Map interface (which is almost never the case), you will be fine with the mySeats variable being of type Map<Integer, Seat> instead of HashMap<Integer, Seat>. This is called programming to the interface and is a best practice that you should embrace from the very beginning. It will save you a lot of headaches in the future.
Following my tip in the comments, I wouldn't use a Map to link a meaningful row or number to a map-key or an array-index.
So, actually I would do it this way (because you asked, what I mean with my tip):
Seat:
public class Seat {
private final int row;
private final int number;
private boolean reserved = false;
public Seat(int row, int number) {
this.row = row;
this.number = number;
}
public boolean reserve() {
if (!reserved) {
reserved = true;
return reserved;
}
return !reserved;
}
public int getRow() {
return row;
}
public int getNumber() {
return number;
}
public boolean isReserved() {
return reserved;
}
public boolean is(int row, int number) {
return this.row == row && this.number == number;
}
#Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + this.row;
hash = 23 * hash + this.number;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Seat other = (Seat) obj;
if (this.row != other.row) {
return false;
}
return number == other.number;
}
}
Hall:
public class Hall {
public final Set<Seat> seats = new HashSet<>();
public Set<Seat> getSeats() {
return Collections.unmodifiableSet(seats);
}
public void createSeats(int lastRow, int seatsPerRow) { // This is an example; in case you have different count of seats per row, you better make an boolean addSeat(int row, int number) function; boolean to check if it has been added or if the seat already exists
for (int row = 1; row <= lastRow; row++) {
for (int number = 1; number <= seatsPerRow; number++) {
seats.add(new Seat(row, number));
}
}
}
public Seat get(int row, int number) {
for (Seat seat : seats) { // or you use seats.iterator; I personally hate Iterators; it is my subjective point of view.
if (seat.is(row, number)) {
return seat;
}
}
return null;
}
public boolean reserve(int row, int number) {
Seat seat = get(row, number);
if (seat != null) {
return seat.reserve();
}
return false;
}
}
And my Test-drive:
public class TestDrive {
public static void main(String[] args) {
Hall hall = new Hall();
int lastRow = 15;
int seatsPerRow = 10;
hall.createSeats(lastRow, seatsPerRow);
boolean reserved = hall.reserve(5, 9);
System.out.println("Seat(Row=5, Number=9) is reserved: " + (reserved == hall.get(5, 9).isReserved()));
boolean reservedAgain = hall.reserve(5, 9);
System.out.println("Seat(Row=5, Number=9) cannot be reserved again: " + (reservedAgain != hall.get(5, 9).isReserved()));
}
}
h1.getMySeats().get(2).isReserved();
Please use an IDE like IntelliJ IDEA. It will tell you about mistakes like forgetting parentheses while typing.

Why is this a static binding instead of dynamic binding?

I'm still a little confused with regards to the difference between static and dynamic. From what I know dynamic uses object while static use type and that dynamic is resolved during runtime while static is during compile time. so shouldn't this.lastName.compareTo(s1.lastName) use dynamic binding instead?
key.compareTo(list[position-1]) use dynamic binding
public static void insertionSort (Comparable[] list)
{
for (int index = 1; index < list.length; index++)
{
Comparable key = list[index];
int position = index;
while (position > 0 && key.compareTo(list[position-1]) < 0) // using dynamic binding
{
list[position] = list[position-1];
position--;
}
list[position] = key;
}
}
Why does (this.lastName.compareTo(s1.lastName)) use static binding?
private String firstName;
private String lastName;
private int totalSales;
#Override
public int compareTo(Object o) {
SalePerson s1 = (SalePerson)o;
if (this.totalSales > s1.getTotalSales())
{
return 1;
}
else if (this.totalSales < s1.getTotalSales())
{
return -1;
}
else //if they are equal
{
return (this.lastName.compareTo(s1.lastName)); //why is this static binding??
}
}
Your question isn't complete and doesn't include all relevant the code. However this is the basic difference between the different bindings
Java has both static and dynamic binding. Binding refers to when variable is bound to a particular data type.
Static/Early binding is done at compile time for: private, final and static methods and variables. And also for overloaded methods
Dynamic/late binding is done at runtime for: methods which can be overriden methods. This is what enables polymorphic behaviour at runtime.
To further demonstrate this point have a look at this code and see if you can determine when it would be early and late binding:
/* What is the output of the following program? */
public class EarlyLateBinding {
public boolean equals(EarlyLateBinding other) {
System.out.println("Inside of overloaded Test.equals");
return false;
}
public static void main(String[] args) {
Object t1 = new EarlyLateBinding(); //1
Object t2 = new EarlyLateBinding(); //2
EarlyLateBinding t3 = new EarlyLateBinding(); //3
Object o1 = new Object();
Thread.currentThread().getStackTrace();
int count = 0;
System.out.println(count++);
t1.equals(t2);//n
System.out.println(count++);
t1.equals(t3);//n
System.out.println(count++);
t3.equals(o1);
System.out.println(count++);
t3.equals(t3);
System.out.println(count++);
t3.equals(t2);
}
}
Answer:
++ is after the count and hence the result returned is the 0 before incrementing it. Hence starts with 0 and proceeds as you expect.
The only scenario where the equals methods of EarlyLateBinding object
is actually invoked is is statement 3.
This is because the equals method is overloaded (Note: the different
method signature as compared to the object class equals)
Hence the type EarlyLateBinding is bound to the variable t3 at
compile time.
.
in this code
public static void insertionSort (Comparable[] list)
{
for (int index = 1; index < list.length; index++)
{
Comparable key = list[index];
int position = index;
while (position > 0 && key.compareTo(list[position-1]) < 0)
{
list[position] = list[position-1];
position--;
}
list[position] = key;
}
}
key can be anything that implements the Comparable interface so in the compile time compiler doesn't know the exact type so type is resolved in the runtime by using the object that key referring to.
But in this code,
#Override
public int compareTo(Object o) {
SalePerson s1 = (SalePerson)o;
if (this.totalSales > s1.getTotalSales())
{
return 1;
}
else if (this.totalSales < s1.getTotalSales())
{
return -1;
}
else //if they are equal
{
return (this.lastName.compareTo(s1.lastName));
}
}
compiler knows the type of the s1 so it use the static binding

loop to get closest object to input value

I have this Martian class:
public abstract class Martian implements Cloneable {
int id;
public Martian(int id) {
this.id = id;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int getId() {
return id;
}
public boolean equals(Object o){
if( o != null);
return this.getId() == ((Martian)o).getId();
}
public abstract void speak();
public String toString(){
return "Martian" + getId();
}
}
and a MartianManager class:
public class MartianManager {
private ArrayList<Martian> martians;
private ArrayList<Martian> teleporters;
public void addMartian(Martian m) {
martians.add(m);
if(m instanceof GreenMartian)
teleporters.add(m);
}
//public Object clone() {
public Martian getMartianClosestToID(int id) {
}
public void groupSpeak() {
for(Martian m : martians) {
m.speak();
}
}
public void groupTeleport(String dest) {
for (Martian m : martians){
if (m instanceof GreenMartian)
((GreenMartian) m).teleport(dest);
}
}
//public obliterateTeleporters()
//removeMartian(int id)
}
In the MartianManager class I have a method getMartianClosestToId() which returns the martian with the id closest to the input id. My question basically is what would be the simplest logic to use in a loop to do this, or is their an easier way to do it such as compareTo which I don't know if compare would even work in a situation like this.
This isn't the simplest, but in a lot of cases it will be the fastest.
If you're willing to keep your list of martians always sorted by id (which is easy to do if you aren't adding martians very often, you can just sort when you add them), you can do this:
Comparator<Martian> compareById = new Comparator<Martian>() {
public int compare(Martian a, Martian b) {
return Integer.compare(a.getId(), b.getId());
}
}
Then you can use a binary search on your list to find the spot where it would go in the list if it were to be inserted.
int location = Collections.binarySearch(martians, idToGetClosestTo, compareById);
Now at this point, you're going to have where it should go, and you'll have one of five options:
the location has the id you're looking for. If so, return martians.get(location);
the location provided wasn't in the list, meaning you're looking for something lower than the lowest, or higher than the highest.
2.a. lower than the lowest: return the lowest, martians.get(0);
2.b. higher than the highest: return the highest, martians.get(martians.length()-1);
the location is higher than the id you're looking for. (it won't be lower, otherwise you would have been given a result 1 lower than what you did!) So look at martians.get(location) and martian.get(location - 1) and see which one you're closest to and return the appropriate one.
This has an expensive upfront cost (sorting) but after you have it sorted, you can use binary search which is very cheap to find the closest martian very fast every time.
If you're going to be adding very often, then I recommend adding the new martians to the end and flagging your collection as unsorted, then only sorting when you're about to find one.
public Martian getMartianClosestToID(int id) {
if(!martiansAreSorted) Collections.sort(martians,compareById);
int loc = Collections.binarySearch(martians,id,compareById);
if(loc >= 0) return martians.get(loc); // found exact match
// we know loc is negative because it wasn't found - read the docs
loc = -loc;
if(loc == 0) return martians.get(0);
if(loc == martians.size()) return martians.get(loc - 1);
Martian high = martians.get(loc);
Martian low = martians.get(loc - 1);
int highid = high.getId();
int lowid = low.getId();
int highdiff = Math.abs(id - highid);
int lowdiff = Math.abs(id - lowid);
if(highdiff < lowdiff) return high;
return low;
}
Something like this ought to work.
Whether this is exactly what you want depends on some assumptions. Are the IDs unique? Can a Martian be closest to itself? What if there are two equally close Martians? Or no other Martians? I've assumed that the 'id' argument may be one of the IDs in the collection - and that you don't want that one.
But the biggest question is: what does 'closest' mean? The concept of 'closeness' doesn't usually apply to IDs.
public Martian getMartianClosestToId(int id) {
Martian closest = null;
int leastDist = -1;
for(Martian m : martians) {
int mId = m.getId();
if(mId == id)
continue; // Skip the Martian with the same id.
int d = Math.abs(mId - id);
if(leastDist == -1 || d < leastDist) {
leastDist = d;
closest = m;
}
}
return closest;
}
I haven't compiled/tested this - you may need to fix typos/errors.
This I think is simpler than the other answers so far (OP requested the "simplest logic"):
public Martian getMartianClosestToID(int id)
{
if (martians == null || martians.isEmpty())
return null;
Martian result = martians.get(0);
for (Martian m : martians)
if (Math.abs(id - m.getId()) < Math.abs(id - result.getId()))
result = m;
return result
}

Sort a list that contains a custom class

so I'm currently doing an exercise for college that has several optional parts (because we havn't done this in class yet), one of them being to use lists instead of arrays (so it'd be variable size) and another one printing the list sorted by points (I'll get to that now)
So, I have the Player.java class which looks like this.
public class Player {
String name;
String password;
int chips;
int points;
public Player(String n, String pw, int c, int p) {
name = n;
password = pw;
chips = c;
points = p;
}
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public void setPW(String pw) {
password = pw;
}
public String getPW() {
return password;
}
public void setChips(int c) {
chips = c;
}
public int getChips() {
return chips;
}
public void setPoints(int p) {
points = p;
}
public int getPoints() {
return points;
}
}
Pretty simple, then I'm creating a List with this (in another class):
List<Player> lplayer = new ArrayList<Player>();
Adding players with this:
lplayer.add(new Player(n,pw,c,p))`
And finally reading their stats with this:
public int search_Player (String n) {
String name;
int i = 0;
boolean found = false;
while ((i <= tp) && (!found)) {
name = lplayer.get(i).getName();
if (name.equals(n)) {
found = true;
}
i++;
}
return (found == true) ? i-1 : -1;
}
public Player show_Player (int i) {
return lplayer.get(i);
}
public void list_Players() {
Collections.sort(lplayer);
int i2;
if (tp > 0) { // variable which contains number of total players
for (int i = 0;i<tp;i++) {
i2 = i+1;
System.out.println ("\n"+i2+". "+lplayer.get(i).getName()+" [CHIPS: "+lplayer.get(i).getChips()+" - POINTS: "+lplayer.get(i).getPoints()+"]");
}
}
else {
System.out.println ("There are no players yet.");
}
}
So that's basically all the code. As you can see the I already have a list_Players function but that just prints it in the order it was added. I need a way to print in sorted by the points each player has (so basically a ranking).
As you can see I'm pretty new to java so please try not to come up with a very complicated way of doing it.
I've already searched for it and found things like Collections.sort(list) but I guess that's not what I need right here.
Thank you!
You can use the public static <T> void sort(List<T> list, Comparator<? super T> c) overload in Collections - provide the comparator you need (can be just an anonymous class) - and you are all set!
EDIT:
This describes how the method works. In brief, you'll implement your call as
Collections.sort(list, new Comparator<Player>() {
int compare(Player left, Player right) {
return left.getPoints() - right.getPoints(); // The order depends on the direction of sorting.
}
});
That's it!
Collections.sort(list) could definitely by a solution for your problem. It's a way to sort your collections provided by Java. If you are writing a "real world" application (not an exercise for collage) this would be the way you doing it.
To let Collections.sort(list) works, you have to implement an interface call Comparaple. By implementing this interface, the sort will know how to order your elements.
But because it's a exercise for collage, this is perhaps a little bit to easy. If you want (or must) implement you own sorting algorithm, try first to sort a common list of numbers (1, 5, 2, 7...). You can extend such an sorting algorithm easily for your own classes.
A new approach using lambdas, that is a lot shorter to write is
myList.sort((obj1, obj2)->(condition)?1:-1);
where you can use the objects for your condition, and anything greater than 0 returned means swap (in this case if condition returns true)

Categories

Resources