I am brand new in JAVA, and I didn't understand the line talking about "Item temp = (Item)obj;". What does the "(Item)" mean? Does it force to change type of obj? Please help me to figure it out, thanks!
public class Item implements Comparable {
private String id;
private String name;
private double retail;
private int quantity;
private double price;
Item(String idIn, String nameIn, String retailIn, String quanIn) {
id = idIn;
name = nameIn;
retail = Double.parseDouble(retailIn);
quantity = Integer.parseInt(quanIn);
if (quantity > 400)
price = retail * .5D;
else if (quantity > 200)
price = retail * .6D;
else
price = retail * .7D;
price = Math.floor( price * 100 + .5 ) / 100;
}
public int compareTo(Object obj) {
Item temp = (Item)obj;
if (this.price < temp.price)
return 1;
else if (this.price > temp.price)
return -1;
return 0;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public double getRetail() {
return retail;
}
public int getQuantity() {
return quantity;
}
public double getPrice() {
return price;
}
}
Item temp = (Item)obj; is performing type conversion (or typecasting) Object obj to the type Item. If obj is not an Item, then it will throw a ClassCastException, the Javadoc of which says (in part)
Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance. For example, the following code generates a ClassCastException:
Object x = new Integer(0);
System.out.println((String)x);
However, because Comparable is generic, it's also possible to make Item like
public class Item implements Comparable<Item>
and then compareTo(Item) like
#Override
public int compareTo(Item temp) {
return Double.compare(this.price, temp.price);
// if (this.price < temp.price)
// return 1;
// else if (this.price > temp.price)
// return -1;
// return 0;
}
This line: Item temp = (Item)obj;
Taking another object of this class for comparing. This is for sorting of group/list of item class objects.
So When we will sort list of Item, It will take this(current) object with the passing object of this class.
This is known as the casting(Genrally its categorised in two type Down & Up Casting).
Casting allows the use of generic programming in Java,
where code is written to work with all objects of classes descended from some base class (often java.lang.Object, for utility classes).
However, the use of casting causes a unique set of problems.If you try to cast two object which doesn't share same type hierarchy,
i.e. there is no parent child relationship between them, you will get compile time error.On the other hand if you type cast objects from same type hierarchy butthe object which you are casting are not of the same type on which you are casting then it will throw ClassCastException in Java.
And #Elliot have already explained it by example
Related
I've still learning java so bear with me.
Building off previous work. So I have a abstract Stock class with class ETF and class Dividend that both extends Stock class. ETF and Dividend override a calculatePrice from Stock. In another StockManager class, I can take some input as stock name, stock price, and either a value for ETF or dividend. Previously I stored these inputs into a object array
Stock[] stk = new Stock[STOCKLIMIT]
Now since Stock is an abstract class I can't do that anymore. How do I store these values? or print them?
Along with that, in StockManager you can add, remove, print, or find total cost of the stocks.
Deleted some things that are unneeded
Just need some help for adding, printing, and total cost
StockManager class
public class StockManager
{
Scanner stdin = new Scanner(System.in);
final int STOCKLIMIT = 6;
int numberOfStocks = 0;
Stock[] stk = new Stock[STOCKLIMIT]; //before stock was abstract
String name;
Double namePrice;
int etfDividendVal;
public void run()
{
String command = stdin.next();
while (!command.equalsIgnoreCase("Q"))
{
if (command.equalsIgnoreCase("A"))
{
else
{
String commandTwo = stdin.next(); //either e for etf or d for dividend
if (commandTwo.equalsIgnoreCase("E"))
{
name = stdin.next();
namePrice = stdin.nextDouble();
etfDividendVal = stdin.nextInt();
//stk[numberOfStocks] = new Stock(name, namePrice); //object array when stock wasn't abstract
//store name, namePrice, and etfDividendVal somewhere now that stock is abstract
numberOfStocks++;
}
else if (commandTwo.equalsIgnoreCase("D"))
{
name = stdin.next();
namePrice = stdin.nextDouble();
etfDividendVal = stdin.nextInt();
//stk[numberOfStocks] = new Stock(name, namePrice);
//where to store name, namePrice, and etfDividendVal somewhere now that stock is abstract
Stock stk = new Dividend();
numberOfStocks++;
}
}
}
}
else if (command.equalsIgnoreCase("R")) //remove a stock
{
else
{
name = stdin.next();
namePrice = stdin.nextDouble();
for (int i = 0; i < numberOfStocks; i++)
{
if (stk[i].getTicker().equals(name))
{
for(int z = i; z < numberOfStocks; z++)
{
if (z + 1 == numberOfStocks)
stk[z] = null;
else
stk[z] = stk[z+1];
}
numberOfStocks--;
}
}
}
}
else if (command.equalsIgnoreCase("P"))
{
else
{
// print stock name, price, and etf/divident value
}
}
}
else if (command.equalsIgnoreCase("C"))
{
else
{
//print the total cost
}
}
}
}
}
Abstract Stock class
abstract public class Stock
{
protected String commandTwo;
protected String ticker;
protected Double price;
protected int etfDividendVal;
public Stock()
// default constructor
public Stock(String commandTwo, String ticker, Double price,
int etfDividendVal)
{
this.commandTwo = commandTwo;
this.ticker = ticker;
this.price = price;
this.etfDividendVal = etfDividendVal;
}
public String getTicker()
{
return ticker;
}
public String setTicker(String name)
{
ticker = name;
return ticker;
}
public Double getPrice()
{
return price;
}
public Double setPrice(Double namePrice)
{
price = namePrice;
return price;
}
#Override
public String toString()
{
return this.ticker + " " + this.price + "\t";
}
public abstract double calculatePrice();
}
ETF class
public class ETF extends Stock
{
public float numberOfStocks;
#Override
public double calculatePrice()
{
return (price * numberOfStocks);
}
}
Dividend class
public class Dividend extends Stock
{
public float yieldPercentage;
#Override
public double calculatePrice()
{
return (price * yieldPercentage);
}
}
It should look something like this
Pick an option: A-Add R-Remove P-Print C-Total cost Q-Quit
A
E
AMD
30.45
10
Pick an option: A-Add R-Remove P-Print C-Total cost Q-Quit
A
D
FXAIX
100
3
Pick an option: A-Add R-Remove P-Print C-Total cost Q-Quit
P
AMD 30.45 10.0
FXAIX 100.0 0.03
Pick an option: A-Add R-Remove P-Print C-Total cost Q-Quit
C
The total cost is: 307.4999999329448
You can still create an array Stock[], since ETF and Dividend both extend Stock, they can be added to the array. To use the methods declared in ETF and Dividend on the objects you retrieve from the array, you'll have to cast them, like so: ETF etf = (ETF) stk[someIndexHere];. Note that you don't know which objects are actually ETF and which are actually Dividend, and if you cast them to a type they actually aren't, you'll get an error. You can check if an object from stk is ETF or Dividend using the instanceof operator:
Stock stock = stk[0]; // Provided that there is a Stock at stk[0]
if (stock instanceof ETF) {
ETF etf = (ETF) stock;
// Now you can use etf as an ETF object
} else if (stock instanceof Dividend) {
// The second if-statement is redundant since there are only
// two possibilities, but in the future there might be more
// classes extending Stock
Dividend div = (Dividend) stock;
// Now you can use div as a Dividend object
}
Although since neither ETF nor Dividend implements any new methods, casting is unnecessary. instanceof too, unless you want to tell your user which type of stock they're dealing with.
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.
I am doing a problem on inheritance and hierarchy of classes.
The problem is this: I have superclass that contains quantity as the attribute.
The code for that class is here:
class Items {
private int quantity;
public Items(int quantity) {
this.quantity = quantity;
}
Then i have two subclasses that contains prices and other attributes.
Code snippet:
class Coffee extends Items {
private String size;
public Coffee (int quantity, String size) {
super(quantity);
this.size = size;
}
}
class Donuts extends Items {
private double price;
private String flavour;
public Donuts(int quantity, double price, String flavour) {
super(quantity);
this.price = price;
this.flavour = flavour;
}
}
What i want to do is calculate the total price for each object.
My program reads a text file and creates object and stores them in an arrayList. The text file i am reading is this, Please note i have commented the first two lines just to explain what each token is, They are not included in the real file.:
Coffee,3,medium // name of item then the quantity and then size
Donut,7,0.89,chocolate // name then quantity then price then flavor
Donut,3,1.19,eclair
Coffee,1,large
I want to calculate the total price without duplication of the code. What i have done so far in my superclass is this:
public double totalPrice(Items x) {
double total = 0;
if(x instanceof Coffee) {
total = getQuantity() * getSizePrice();
} else {
if (x instanceof Donuts) {
total = totalPrice();
}
}
return total;
}
public abstract String getSizePrice();
In my Coffee subclass:
public double getSizePrice() {
double priceSmall = 1.39;
double priceMed = 1.69;
double priceLar = 1.99;
if(size == "small") {
return priceSmall;
} else {
if (size == "medium" ) {
return priceMed;
}
}
return priceLar;
}
I believe i am going in circles with this one so i was wondering if the SO community could guide me in the right direction. If the question is confusing, feel free to ask and i would explain it further.
Is it possible to get a totalPrice() method in each class and then through ploymorphism the class calculates the price of those items in the main method.
I have made an inheritance hierarchy with one super-class called Employe and two subclasses called Lecturer and Assistant. In addition to this I made a class called Subject which has an array of employees.
What I want to do here is create a method for adding Employe objects into the array.
I made the same one that works for ArrayList, but it didn't seem to work for Arrays.
If it is possible, how can I create a method for doing the same thing with arrays?
public class Subject {
private String subjectcode;
private Employe[] employees;
public Subject(String subjectcode) {
this.subjectcode = subjectcode;
Employe[] employees = new Employe[5];
}
public void setSubjectcode(String code) {
this.subjectcode = code;
}
public String getSubjectcode() {
return this.subjectcode;
}
public boolean addStaff(Employe employe) {
if (employe instanceof Lecturer || employe instanceof Assistant) {
this.employees.add(employe);
return true;
} else {
return false;
}
}
}
You need to use an ArrayList :
public class Subject
{
private String subjectcode;
private final List<Employee> employees = new ArrayList<Employee>();
public Subject(String subjectcode){
this.subjectcode = subjectcode;
}
public boolean addStaff(Employe employe){
return this.employees.add(employe);
}
Or if you still want to use an array :
public boolean addStaff(Employe employe){
List<Employee> tempList = Arrays.asList(this.employees);
boolean added = tempList.add(employe);
this.employees = tempList.toArray(this.employees);
return added;
}
Arrays cannot grow or shrink dynamically by themselves as ArrayLists do, that's why the don't have add() method — it'd stop working after array instance is full.
What you have with arrays are, essentially, a get(index) and set(index, value), so when you know that you will have at maximum N employees, Subject may look like this:
public class Subject {
private static final int N = 5;
private String subjectcode;
private Employe[] employees = new Employe[N];
private int size = 0;
public Subject(String subjectcode){
this.subjectcode = subjectcode;
}
public void setSubjectcode(String code){
this.subjectcode = code;
}
public String getSubjectcode(){
return this.subjectcode;
}
public boolean addStaff(Employe employe){
if (size == employees.length) {
// cannot add when is full
return false;
}
if(employe instanceof Lecturer || employe instanceof Assistant){
this.employees[size++] = employe;
return true;
}
return false;
}
}
On the other hand, if you don't know how many employees Subject may have even at a time when Subject is created (if you'd know it, you may pass N as a constructor argument), you'd have to implement method for growing internal array and call it whenever new employe is added, which may look like this:
private void ensureCapacity(int n) {
int oldCapacity = employees.length;
if (oldCapacity >= n) {
// there's nothing to do
return;
}
// grow at least in half, to minimize copying data on each add
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - n < 0)
newCapacity = n;
employees = Arrays.copyOf(employees, newCapacity);
}
public boolean addStaff(Employe employe) {
ensureCapacity(size + 1);
if (employe instanceof Lecturer || employe instanceof Assistant) {
this.employees[size++] = employe;
return true;
}
return false;
}
For better example of growing arrays see default implementation of ArrayList's ensureCapacity(int minCapacity) in JDK.
But again, this growing-shrinking stuff is just reimplementing what is done already in ArrayList for you.
In case of Java arrays, unlike ArrayList you do not have add method. So, you cannot add like it. Array operates as below:
String[] employees = new String[5];
employees[0] = "ad";
So, array needs index based approach, where you specify that at index 0 put this element, at index 1 put this element, and so on .... employees[0] = "as";
In your case, why you need to use array? I think ArrayList fits best, as per information you have provided.
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.