Calling methods with objects trouble - java

So, I need to do this for part of my homework :
Create a method in the Customer class called hasMoreMoneyThan(Customer c)
which returns true if the customer calling the method has more money than the
customer c, otherwise it should return false.
I am looking to be pointed in the right direction for the line that says "the customer calling the method"
This is very confusing to me and doesn't make sense, this my Customer is a class.
Here is the necessary code :
public class Customer
{
private String name;
private int age;
private float money;
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public Customer(String n, int a, float m)
{
name = n;
age = a;
money = m;
}
I started writing the method:
public boolean hasMoreMoneyThan(Customer c)
{
}
But am not sure how to call that with my Customer object (which I think the question is asking.
Other relevant code :
public class StoreTestProgram {
public static void main(String args[]) {
Customer[] result;
Store walmart;
walmart = new Store("Walmart off Innes");
walmart.addCustomer(new Customer("Amie", 14, 100));
}
}

When a method is called on an object, the objects variables are in the current scope. In this case, the 'customer calling the method' is the object that the method is being called on (object being an instance of the class).
So, if boolean hasMoreMoneyThan(Customer c) is being called on Customer a, then you should think of it as asking Customer a has more money than Customer c?.
You can use the this keyword to refer to the current object (to help the reader differentiate from Customer c).
So, in your hasMoreMoneyThan method, you can compare this.money with c.money.
And to call this method, you need a reference to the current customer and the customer you want to compare with. You could do something like:
Customer currentCustomer = new Customer(...
Customer customerToCompareWith = new Customer(...
if (currentCustomer.hasMoreMoneyThan(customerToCompareWith)) {
// do something
}
Edit Let's try a different example. Let's say you want a method to know whether a customer is older than another customer. That code might look like:
public boolean isOlderThan(Customer c) {
return this.age > c.age;
}
And to call the method:
if (currentCustomer.isOlderThan(customerToCompareWith)) {
// the current customer is older
} else {
// the current customer is not older
}

this is how you reference an object from methods that are members of an object. this.money ><=? c.money
if in your constructor you you used public Customer(String name, int age, float money) you would use this.name= name instead of name= n to clear up ambiguity.

Related

Store different object type in one array and print each one with their methods

I am trying to create a parent class for cars and subclasses from it. Each one has separate methods and store them in an array then if the class are subclass try to call the method on it.
Parent class
public class car {
public String name ;
public double price ;
public car (String name , int price) {
this.name = name ;
this.price = price;
}
public String toString() {
return "car name : "+this.name
+" Price : " +this.price ;
}
}
Sub class
public class CarMotors extends car {
public float MotorsCapacity ;
public CarMotors( String name, int price , float MotorsCapacity) {
super(name, price);
this.MotorsCapacity = MotorsCapacity ;
}
public float getMotorsCapacity() {
return this.MotorsCapacity;
}
}
Main class
public class Test {
public static void main(String[] args) {
car [] cars = new car[2] ;
cars[0] = new car("M3" , 78000);
cars[1] = new CarMotors("M4" , 98000 , 3.0f);
for(int i=0 ;i<2;i++){
if(cars[i] instanceof CarMotors) {
System.out.println(cars[i].getMotorsCapacity()); // error here
}else {
System.out.println(cars[i].toString());
}
}
}
}
As you can see, I can't print the getMotorsCapacity(). I am new to Java. I think there is a cast that need to happen, but I don't now how.
Being short... a class only can see what its yours behaviors.
In your example CarMotors is a Car, that's fine.
But the behavior getMotorsCapacity() is created in CarMotors and it wasn't in Car.
That error occurs because, it's OK in a variable Car you are able to put an instance of CarMotors because CarMotors is a Car. So, any method that is in Car is also in CarMotors, yes, you can call. Look at cars[i].toString() there's no problem here.
You need explicitly say to compiler:
"- oh, right, originally this variable is a Car, but I know that is a CarMotors inside that. I will make a cast here, OK compiler? Thanks."
System.out.println(((CarMotors) cars[i]).getMotorsCapacity());
Or, to be more clear:
CarMotors carMotors = ((CarMotors) cars[i]);
System.out.println(carMotors.getMotorsCapacity());

Is there a way to efficiently audit statistics attributes of objects in Java?

Say I have a class Person, and I created 10 instances of Person, and each person has several different attributes, such as enum Gender{MALE, FEMALE}, enum Profession{CEO, POLICE, TEACHER}, etc.
And I somehow have to randomly create many persons with random attributes and use a dedicated class to audit the statistics of created persons' attributes.
So, eventually, I need to generate a list of attributes with some statistics accordingly, such as, "FEMALE: [number], POLICE: [number],...".
Currently, I'm planning to add all kinds of the persons' attributes count, as a bunch of new attributes to the audit class, such as, "femaleCount int, policeCount int, ..." then manipulate the counts based on generated persons.
But, I got 10-ish attributes for each person, so I wonder if there is a better way to do this.
Thanks for your reading.
One possible approach is below, but do not say that it's the only one neither the best.
It's only depends of the purpose and your design.Other option maybe it's to store all Persons in a data-structure List and just compute the statistic based on data at a certain time (have also update/delete here)
Version where only add is counting ...
public class Statistic
{
private static Statistic s=null;
public int countPerson;
public int countMale;
public int countFemale;
public static Statistic getInstance()
{
if(s==null)
s = new Statistic(0, 0, 0);
return s;
}
public static Statistic getInstace(int cP,int cM, int cF)
{
if(s==null)
s = new Statistic(cP, cM, cF);
return s;
}
//do whatever init wanted
private Statistic(int cP,int cM, int cF)
{
countPerson = cP;
countMale = cM;
countFemale = cF;
}
public String toString()
{
return "Total="+countPerson+", Male="+countMale+", Female=" + countFemale;
}
}
...
public class Person
{
public int id;
public String name;
public Gender g;
public Profession p;
public enum Gender{MALE, FEMALE};
public enum Profession{CEO, POLICE, TEACHER}
Person(int id,String name, Gender g, Profession p)
{
this.id = id;
this.name = name;
this.g = g;
this.p = p;
Statistic.getInstance().countPerson++;
if(g.equals(Gender.MALE))
{
Statistic.getInstance().countMale++;
}
else
{
Statistic.getInstance().countFemale++;
}
}
}
...
public class TestStat {
public static void main(String[] args)
{
//cPersons,cMale,cFemale - init
Statistic.getInstace(10, 5, 5);
System.out.println(Statistic.getInstance());
new Person(1,"Male",Person.Gender.MALE, Person.Profession.TEACHER);
System.out.println(Statistic.getInstance());
new Person(2,"Female",Person.Gender.FEMALE, Person.Profession.CEO);
System.out.println(Statistic.getInstance());
}
}
Output
//custom start from (10,5,5) based on Singleton Custom Constructor
Total=10, Male=5, Female=5
//start update counters
Total=11, Male=6, Female=5
Total=12, Male=6, Female=6
Thinking twice maybe it's better to keep a List with Persons on Singleton
and make each time a new Computation - from Singleton instead on Person.
About Delete a person which can be translated in "moving from a Company to other" and then it's not to be reflected on Statistic.
Even so, on current you could add a delete method on person which could be reflected with adjust Statistic with minus and Person-Instance with null.
Further, it's up to you to update design as wanted.

Why can't I seem to find the error in my program when compiling. Help needed

The pet store program should start with the user being able to choose to adopt a pet or give a pet the to the shop. If the user wants to adopt a pet, they should be able to see either all available pets, unless they say they know what type of pet they want, then show only available pets of that type.
The 4 methods that will need to be created for this program should:
add new pets
get a pet adopted
show pets by type
show pets available for adoption
Object Class: Pets.java
import java.util.*;
public class Pets {
public static void main(String[] args){
private double age; // age of the animal (e.g. for 6 months the age would be .5)
private String petName; // name of the animal
private String aType; // the type of the pet (e.g. "bird", "dog", "cat", "fish", etc)
private int collarID; // id number for the pets
private boolean isAdopted = false; // truth of if the pet has been adopted or not
private String newOwner;
private Date adoptionDate;
public double getAge() {
return age;
}
public void setAge(double age) {
this.age = age;
}
public String getPetName() {
return petName;
}
public void setPetName(String petName) {
this.petName = petName;
}
public String getaType() {
return aType;
}
public void setaType(String aType) {
this.aType = aType;
}
public int getCollarId() {
return collarID;
}
public void setCollarId(int collarId) {
this.collarID = collarId;
}
public boolean isAdoptated() {
return isAdopted;
}
public void setAdoptated(boolean isAdoptated) {
this.isAdopted = isAdoptated;
}
public Date getAdoptionDate() {
return adoptionDate;
}
public void setAdoptionDate(Date adoptionDate) {
this.adoptionDate = adoptionDate;
}
#Override
public String toString() {
return "Pets [age=" + age + ", petName=" + petName + ", aType=" + aType + ", collarId=" + collarID
+ ", isAdoptated=" + isAdopted + ", adoptionDate=" + adoptionDate + "]";
}
}
}
You should define the data fields and methods inside the class, but not inside the main()-method. The main()-method is the entry point of your java application and could be used to create an instance of your Pets class.
e.g.:
public static void main(String[] args) {
Pets pet = new Pets();
}
This code is not compiling for 2 main reasons:
You are specifying access modifiers on variables inside a method (in this case main), which is forbidden;
You are writing methods (e.g. getAge) inside another method (main) and trying to return a variable (e.g. age) that is out of that scope, in fact the variable age is not known inside the getAge method, because it's declared in the main method.
You should move the variable declaration to class level, and then have all methods separated using those variables. I'll give you a sketch, not the complete solution:
import java.util.*;
public class Pets {
/* Insert all variable declarations here */
private double age;
/* Constructor if you need it */
public Pets(/* parameters you think you need */) {
// Set attributes when you declare a new Pets()
}
/* Insert all methods you need here */
public double getAge() {
return this.age;
}
The positioning of the main method - for what I've understoon from your description - should be placed outside this class, in another class where the whole application will start to run. The Pet class should serve only for anything concerning pets (the four methods you will need to implement and all getters/setters for retrieving private class variables).
You’ve happened to put about everything — private fields and public methods — inside you main method. That doesn’t make sense. Everything that is in your main, move it outside, right under the line public class Pets {. That should fix your compiler error.

Storing and calling specific class methods in/from an array

I've been reading and googling for hours on how I can call
public class Fee {
int id;
String name;
double amount;
FeeCategory feeCategory; // miscellaneous, other, tuition, etc
GradeLevel gradeLevel;
SchoolYear schoolYear;
String description;
boolean isActive;
public boolean isIsActive() {
return isActive;
}
public void setIsActive(boolean isActive) {
this.isActive = isActive;
}
public FeeCategory getFeeCategory() {
return feeCategory;
}
public void setFeeCategory(FeeCategory feeCategory) {
this.feeCategory = feeCategory;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public GradeLevel getGradeLevel() {
return gradeLevel;
}
public void setGradeLevel(GradeLevel gradeLevel) {
this.gradeLevel = gradeLevel;
}
public SchoolYear getSchoolYear() {
return schoolYear;
}
public void setSchoolYear(SchoolYear schoolYear) {
this.schoolYear = schoolYear;
}
I have a number of different getter methods along with its setter methods.
I need to be able to call the method to fill the cells of a JTable with specific values returned by corresponding getter method.
So what I did was create a DefaultTableCellRenderer
public class JTableRenderer extends DefaultTableCellRenderer{
#Override
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int col)
{
Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
if(row%2 == 0){
cellComponent.setBackground(Color.YELLOW);
}
else{
cellComponent.setBackground(Color.CYAN);
}
for(int i=0; i<table.getRowCount(); i++){
for(int j=0; j<table.getColumnCount(); j++){
if(table.getValueAt(i, j) instanceof Fee){
Fee fee = (Fee)table.getValueAt(i, j);
table.setValue(fee.getId(),i,j);
}
}
}
return cellComponent;
}
}
The problem is with the for loop which I plan to use to set specific values for certain cells.
As you can see, it filled all the cells with just the id because I can't think of a way to iterate through getId(),getName(),getAmount(),getDescription().
Is it possible to put all 4 methods in an array maybe something like
Methods[] myMethods = {getId(),getName(),getAmount(),getDescription()};
then,
for(int i=0; i<table.getRowCount(); i++){
for(int j=0; j<table.getColumnCount(); j++){
if(table.getValueAt(i, j) instanceof Fee){
Fee fee = (Fee)table.getValueAt(i, j);
table.setValue(fee.myMethod[j],i,j);
}
}
}
I want to call just the 4 getter methods but not all of them.
Any solution or suggestion?
You are going to need some sort of switching logic to handle the mapping of index to getter method. For me, the neatest way is to use Java 8 lambda functions, something like the example below. As you can see, this adds a getValue(int index) method to the Fee class which does what you want. The mapping is handled by a Map created in the static initialisation.
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class Fee {
private String name;
private int fee;
private static Map<Integer, Function<Fee, Object>> getterIndex = new HashMap<>();
static {
getterIndex.put(0, Fee::getName);
getterIndex.put(1, Fee::getFee);
}
public String getName() {
return name;
}
public Fee setName(String name) {
this.name = name;
return this;
}
public int getFee() {
return fee;
}
public Fee setFee(int fee) {
this.fee = fee;
return this;
}
public Object getValue(int index) {
return getterIndex.get(index).apply(this);
}
public static void main(String[] args) {
Fee fee = new Fee().setName("Barry").setFee(1000);
System.out.println("name: " + fee.getValue(0));
System.out.println("fee : " + fee.getValue(1));
}
}
In order to dynamically call methods like that, you'll need to use reflection and possibly introspection.
Reflection is when you programmatically use the structures of your program itself, such as Class instances, the methods they define. If you take a look at the Java Class class, you'll find it has methods for accessing its constructors, fields, methods and more.
Introspection is the ability to use properties of some object at run-time. Classes that conform to the JavaBeans specification allow introspection, which offers some abstraction that's easier to use than pure reflection. The Introspector class in package java.beans allows you to obtain bean info for a class. From there, the "properties" of that class can be used. A property could be a field with a getter and/or setter, or a getter/setter not backed by a field (that may simply operate on logic). It allows for more than that, such as registering a listener with a property on an instance so that if the property is changed through a setter, the listener is called. This is useful for a model-view-controller approach, where changes to some instance may require update events being fired on the view. For example, if some part of your code changes properties of objects that are represented as rows in your table, outside of the GUI, the listener could be used to update the corresponding cell.
If you want to use an array, you'll have to populate it with Method instances. These would be the read methods (and possibly a separate array with write methods) for the corresponding PropertyDescriptors you get via the introspection. Such a Method can then be invoked on an object, provided the access rules allow it. It might actually be better to use a Map, which maps names to the Method, so the actual order doesn't matter. This would make it easier to refactor your user interface later. You may also want some way of mapping the actual column names to the property names, but if you set specific rules regarding naming and stick to them, you could derive the property names from the column names, or reverse things and show a column for each property automatically.
EDIT: Maybe interesting to know why you need to do these things in such a round-about way. Java does not have first class methods. This means that methods cannot be passed around as arguments or treated as any other piece of data, the way you could in JavaScript or Scala. So reflection is needed to obtain and invoke methods indirectly. Java 8 introduced some functional programming concepts with lambdas, but they are a form of single-method interface in disguise. Furthermore, Java is not a dynamic language such as Ruby or Python, it is a statically compiled language. So some things that are simple (but also easy to break) in other languages require reflection in Java. If you come from a non-Java background, the way you need to do some things may feel cumbersome.
Add to Fee class:
public Object myMethod(int j) {
switch (j) {
case 0:
return this.getId();
case 1:
return this.getName();
case 2:
return this.getAmount();
case 3:
return this.getDescription();
default:
throw new IllegalArgumentException();
}
}
You should have a list of Fee records:
List<Fee> feeData=new ArrayList<Fee>();
Then call:
for(int i=0; i<feeData.size(); i++){
if(feeData.get(i) instanceof Fee){
for(int j=0; j<table.getColumnCount(); j++){
Fee fee = (Fee)feeData.get(i);
table.setValueAt(fee.myMethod(j),i,j);
}
}
}

Confused about cloning in Java

I have this code in Java.
public class CloneTest implements Cloneable{
String name;
int marks;
public CloneTest(String s, int i) {
name = s;
marks = i;
}
public void setName(String s) {
name = s;
}
public void setMarks(int i) {
marks = i;
}
#Override
public Object clone() {
return new CloneTest(this.name, this.marks);
}
}
I have created one object of this class, and then cloned it. Now, when I change the value of name in one object, the value of name remains unchanged in the other. The strange thing here is in the constructor, I am just using a simple reference for name, not creating a new String for name. Now, since Strings are reference types, I expected the String in the clone to be changed as well. Can anyone tell me what's going on? Thanks in advance!
EDIT
Code Testing
CloneTest real = new CloneTest("Molly", 22);
CloneTest clone = real.clone();
real.setName("Dolly");
I used the "Inspect Variables" feature of BlueJ to check the values.
Assume that original is the name of original CloneTest object, and cloned is the cloned object that you created from original using the clone() method.
This is what happened:
1. Your cloned.name and original.name are pointing at the same object, which in this case was a String.
2. Then you asked your original.name to point to a different String object ("Dolly"). This happens when you assign the new String object ("Dolly") to the reference original.name.
3. But, the cloned.name still points to the first String object ("Dolly").
Hence, cloned.name still prints the 1st String object.
Now, if you are able to change the content of the String object without reassigning the references, then the change in clone.name will reflect in original.name. But for String objects, this is not possible due to the immutability of Strings. However, you can reflect the change from the clone to original with StringBuffers which are mutable strings so to speak. Take a look at this example code for the same: https://gist.github.com/VijayKrishna/5967668
Each instance of your class has different references to an object. You you're just changing reference not modifying object. If you place your string in some holder object, then clone it and set string inside the holder (not a holder reference but string reference inside holder) then you'll have your changes in both of clones
So are you saying you are doing something like:
public void testSomeMethod() {
CloneTest a = new CloneTest("a", 1);
CloneTest b = (CloneTest) a.clone();
a.setName("b");
assertFalse(b.name.equals(a.name));
assertEquals("b", a.name);
assertEquals("a", b.name);
}
?
If so, then all these assertions should pass. Your clone method has reference types in it, and when initially cloned, they refer to the same object. But the setName("...") changes the value that instance points to, not the value of the referred to object.
Get some better clarity along with #vijay answer by looking hash code.
CloneTest real = new CloneTest("Molly", 22);
CloneTest clone = (CloneTest) real.clone();
int h1=real.name.hashCode();
int h2=clone.name.hashCode();
System.out.println("h1 " + h1 + " h2 " + h2); // same
real.setName("sak");
h1=real.name.hashCode();
h2=clone.name.hashCode();
System.out.println("h1 " + h1 + " h2 " + h2); //different
Output :
h1 74525175 h2 74525175
h1 113629 h2 74525175
package com.test;
class Manager implements Cloneable
{
String firstName;
String lastName;
int age;
public Manager(String fname,String lname,int a)
{
this.firstName=fname;
this.lastName=lname;
this.age=a;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class TestCloning {
public static void main(String[] args) throws CloneNotSupportedException {
Manager m1=new Manager("Sadik","Tahir",26);
Manager m_clone=(Manager)m1.clone();
Manager m2=m1;
System.out.println("M1 Details:::");
System.out.println("Fisrt Name:"+m1.getFirstName()+",LastName:"+m1.getLastName()+",Age:"+m1.getAge());
System.out.println("Hashcode:"+m1.hashCode());
System.out.println("M_Clone Details:::");
System.out.println("Fisrt Name:"+m_clone.getFirstName()+",LastName:"+m_clone.getLastName()+",Age:"+m_clone.getAge());
System.out.println("Hashcode:"+m_clone.hashCode());
System.out.println("M2 Details:::");
System.out.println("Fisrt Name:"+m2.getFirstName()+",LastName:"+m2.getLastName()+",Age:"+m2.getAge());
System.out.println("Hashcode:"+m2.hashCode());
m1.setFirstName("Afreen");
m1.setLastName("Khan");
m1.setAge(25);
System.out.println("M1 Details:::");
System.out.println("Fisrt Name:"+m1.getFirstName()+",LastName:"+m1.getLastName()+",Age:"+m1.getAge());
System.out.println("Hashcode:"+m1.hashCode());
System.out.println("M_Clone Details:::");
System.out.println("Fisrt Name:"+m_clone.getFirstName()+",LastName:"+m_clone.getLastName()+",Age:"+m_clone.getAge());
System.out.println("Hashcode:"+m_clone.hashCode());
System.out.println("M2 Details:::");
System.out.println("Fisrt Name:"+m2.getFirstName()+",LastName:"+m2.getLastName()+",Age:"+m2.getAge());
System.out.println("Hashcode:"+m2.hashCode());
}
}

Categories