I have been experimenting with Classes in Java over the last few days, learning about them from "TheNewBoston" on youtube and from the java docs.
I have created the following scenario and seek your guys' (girls too) professional criticism and in depth knowledge regarding a few questions I have.
There are two classes, person and person_financial, a base class and sub class respectively.
person class:
public class person {
private String name;
private String sex;
private int age;
private double height;
private double weight;
private double intelligence;
// person constructor arguments order: name, height, weight, age, sex, intelligence
public person(){
this("noname",0,0,0,"undefined",5);
}
public person(String n){
this(n,0,0,0,"undefined",5);
}
public person(String n, double h){
this(n,h,0,0,"undefined",5);
}
public person(String n, double h, double w){
this(n,h,w,0,"undefined",5);
}
public person(String n, double h, double w, int a){
this(n,h,w,a,"undefined",5);
}
public person(String n, double h, double w, int a, String s){
this(n, h, w, a, filterSex(s), 5);
}
public person(String n, double h, double w, int a, String s, double i){
name = n;
height = h;
weight = w;
age = a;
sex = filterSex(s);
intelligence = i;
}
public void setName(String n){
name = n;
}
public void setHeight(double h){
height = h;
}
public void setWeight(double w){
weight = w;
}
public void setAge(int a){
age = a;
}
public void setSex(String s){
sex = filterSex(s);
}
public void setIntel(double i){
intelligence = i;
}
public String getName(){
return name;
}
public double getHeight(){
return height;
}
public double getWeight(){
return weight;
}
public int getAge(){
return age;
}
public String getSex(){
return sex;
}
public double getIntel(){
return intelligence;
}
public String getInfo(){
return String.format("Name: %s,\nSex: %s,\nAge: %d,\nIntelligence: %.2f,"
+ "\nHeight: %.2f,\nWeight: %.2f\n", name, sex, age,
intelligence, height, weight);
}
private static String filterSex(String s){
return ((s.equalsIgnoreCase("male") ||
s.equalsIgnoreCase("female")) ? s : "undefined");
}
}
person_financial class:
public class person_financial extends person {
private double monies = 0;
public void definePerson(String n, int a, String s, double i, double h, double w){
setName(n);
setAge(a);
setSex(s);
setIntel(i);
setHeight(h);
setWeight(w);
}
public person_financial() {
this(0);
}
public person_financial(double m) {
monies = m;
}
public void depositMonies(double m) {
monies += m;
}
public void withdrawlMonies(double m) {
if (m <= monies) {
monies -= m;
}
}
public double getBalance() {
return monies;
}
}
and then in the main class I have this:
public class Main {
public static void main(String[] args) {
person p1 = new person("I have no Name", 180, 72, 38, "Alien", 7.2);
System.out.println(p1.getName());
person_financial pf1 = new person_financial(100.00);
pf1.depositMonies(50.02);
System.out.printf("%s has %.2f monies.\n", pf1.getName(), pf1.getBalance());
pf1.definePerson("some_name", 42, "male", 10, 180, 72);
System.out.println(pf1.getInfo());
}
}
in the person_financial class, I have made a method called "definePerson()" which I use to define all the characteristics that would otherwise have been defined from the 'person()' constructor from the 'person' class. I'm sure there is a more professional way for assigning values to variables in a base class from a sub class, I just dont know of any...
Also, is there any way to call the constructor from the "person" class to define characteristics for 'pf1'? rather than having to, for example, manually set each attribute, i.e. pf1.setName("something"); , or pf1.setAge(1000000); etc... or have a method do it for me, as in 'definePerson()'.
Any help is much appreciated,
Thanks =).
You use the super() call to call the constructor of the parent class. It has to be the first call in the constructor of the derived class, but you call it (and pass in arguments) like any other function and it will call the constructor that way.
It's common to declare a class 'abstract' to prevent creation of generic objects - based on your usage-code at the bottom you seem not to want that and that's fine. Just remember that you can declare declare a class abstract.
The best way to use class hierarchy is to ensure that (buzzword alert) any class in a useful hierarchy should be declarable as anythin in the hierarchy (i.e. you should be able to access any methods in your concrete object from the base-class (person in this case).
Your financial_person object extends person, but the ideal is to have a class that you can declare at a high level and call methods polymorphically. Consider for a minute that all people are able to draw and deposit money (different from your classes, but bear with me for a minute).
drawMoney method would exist in person, but be marked abstract - forcing the subclasses financial_person and regular_person to implement draw_money, deposit_money etc.
each class would have an implementation that suits their reality (financial person would have access to all kinds of special accounts, discounts etc., and regular_person would have a simpler set of - but still the same external behavior).
Then you could declare like this:
Person finPerson = new FinancialPerson(... etc.);
Person regPerson = new RegularPerson(....etc);
note now that you are able to do this code below:
finPerson.drawCash(12300.0);
regperson.drawCase(100.0);
The identical behavior.
You could have a List of thousands of people, and would not have to do if-then-else or switch statements to execute the finer-tuned behaviors of each.
The acid-test for class-hierarchy is this: "my (sub-class) really 'a kind of' (superclass)?"
In other words, "does my subclass have behaviors of the superclass?"
If not, you should think carefully about class hierarchy. There's a buzzword for this : Liskov Substitution Principle, and I cannot do a better job of this than Robert. C. Martin - one of the software-design gurus:
http://www.objectmentor.com/resources/articles/lsp.pdf
In this article he shows what happens when you have inadvisable hierarchy, using the "a square is a kind-of rectangle" example.
Google "template method pattern" for a summary of another aspect of effectively using inheritance. You will see that it is much more powerful than the simple inheritance that most people dismiss it as being.
Also remember that no single pattern is a silver-bullet for everything. Some people will call class-hierarchy evil and tell you to use interfaces only; others will say the reverse. There are choices to make, and sometimes they will not be obvious.
There are many pitfalls, and missing LSP is just one of them. Others are (examples only) overriding concrete methods, having concrete classes not marked final, enabling mutability of "identifying" fields (eg fields used in equals/hashcode, etc.) Imagine if "customer" objects at bank allowed resetting of first-name, or account-number at runtime, once these fields were already set).
My answer is more generally related to OO design, inheritance etc. than specific coding questions - hope it's of some use to you.
Related
UML Diagram
I am brand new to Java, though I've taken other programming courses. I'm really struggling with the class concept from a UML diagram. I have a parent class and two child classes. My assignment is to create this class structure. I am struggling with the concept of class and relationships in general though.
Example: If my parent class is "Animal" and my child classes are "Monkey" and "Bear" - if the only choices that will be implemented are "Monkey" and "Bear", this makes the class "Animal" an abstract class distinction as there will never be just "Animal", it will always be a "Monkey" or a "Bear".
So, how would I create three files (Animal.java, Monkey.java, Bear.java) if Animal is abstract? I understand that the properties and traits of Animal are inherited by Monkey and Bear. Assuming that I have, for instance, name and age of the animal as attributes and getters and setters for each - if name and age of "Animal" class are private (code below), how does "Bear" class pick up the name and age if it is in its own java file/class? My code is below...
Animal.java
public class Animal {
private String animalName;
private int animalAge;
public void setName (String name) {
animalName = name;
}
public void setAge (int age) {
animalAge = age;
}
public static String getName() {
return animalName;
}
public static String getAge() {
return animalAge;
}
}
Bear.java
public class Bear {
public int weight;
public static int weight() {
return weight;
}
}
// This is where I get stuck & don't know where to go from here.
I understand that I am creating an object "Bear" which is part of the class "Animal", but as Bear is its own class, how does "Bear" get its assigned values from Animal? I can assign "Animal" and "Bear" with default values, but my brain cannot put together how they're talking to one another.
This might be outside the scope of this forum but my professor is unresponsive and I've read through books, ebooks, the course material, and several lectures and this is just not coming to me and I'm two weeks behind at this point trying to understand this concept so I can move forward with the actual code in the program.
Thanks in advance.
You forgot to do this:
public class Bear extends Animal {
// ...
}
I would recommend that you add constructors:
public class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() [ return this.name; }
public int getAge() { return this.age; }
}
public class Bear extends Animal {
private int weight;
public Bear(String name, int age, int weight) {
super(name, age);
this.weight = weight;
}
public int getWeight() { return this.weight; }
}
You can do this, because Bear IS-A Animal:
Animal b = new Bear("Smokey", 10, 300);
System.out.println(b.getName()); // prints "Smokey"
edit: added employee constructors;
my question involves constructor chaining for a subclass (to a super which is itself a subclass). I have written constructors that seem to work, but I feel that they are incorrectly written as I will explain. PTEmployee extends to Employee who is extended to a Person. The code below seems to work in my test class,
public class PartTimeEmployee extends Employee {
public static final int DEFAULT_HOURSPRWK = 0;
private int hoursPerWk;
public PartTimeEmployee() {
this(DEFAULT_HOURSPRWK);
}
public PartTimeEmployee(int hoursPerWk) {
this(DEFAULT_HIRE_DATE, DEFAULT_INCOME, hoursPerWk);
}
public PartTimeEmployee(String hireDate, double incomeWk, int hoursPerWk) {
super(hireDate, incomeWk);
this.hoursPerWk = hoursPerWk; // I dont think I need two this.var?
}
public PartTimeEmployee(String firstName, String surname, int age, Address address, String hireDate, double incomeWk, int hoursPerWk) {
super(firstName, surname, age, address, hireDate, incomeWk);
this.hoursPerWk = hoursPerWk;
}
But I feel that the use of two constructors with (super) and this.hoursPerWk = hoursPerWk is wrong, shouldn't '(super)' and 'this.var = var' only need to be written once? If I adjust the code to remove the PTEmp(hiredate, incomewk, hrswk) constructor than I get a 'no constructor found' error in my second constructor. Other edits have led to recursor errors.
So the supplied code works and calls all details in my test class, but is it correctly written (I need to have a Person class that is extended by Employee which is extended by PTEmp or Boss etc.). Appreciate any feedback (or jsut to know this is correct if it is.
Thanks.
Added Employee constructors here...
public class Employee extends Person {
public static final String DEFAULT_HIRE_DATE = "00/00/00";
public static final double DEFAULT_INCOME = 0;
private String hireDate;
private double incomeWk;
public Employee() {
this(DEFAULT_HIRE_DATE, DEFAULT_INCOME);
}
public Employee(String hireDate, double incomeWk) {
this(DEFAULT_FIRSTNAME, DEFAULT_SURNAME, DEFAULT_AGE, new Address(), hireDate, incomeWk);
}
public Employee(String firstName, String surname, int age, Address address, String hireDate, double incomeWk) {
super(firstName, surname, age, address);
this.hireDate = hireDate;
this.incomeWk = incomeWk;
}
Not sure what super() does if you don't specify names, address, etc, but assuming that you can use some defaults, maybe you can call it like this:
public PartTimeEmployee(String hireDate, double incomeWk, int hoursPerWk) {
this(DEFAULT_FIRST_NAME, DEFAULT_SURNAME, DEFAULT_AGE, DEFAULT_ADDRESS, hireDate, incomeWk, hoursPerWk);
}
Consider using builder patterns, if you think that you have too many overloaded constructors:
When would you use the Builder Pattern?
I want to code a little text adventure/dungeon crawler type of game. At the moment I have the classes Creature, Player, and Enemy. The classes Player and Enemy are subclasses of Creature.
I want to make the level of the enemy dependent on the level of the player. So for example, the enemy's level should always be 1 level above the player's level. So when the player is level 4 you should only be able to face enemies which are level 5.
My idea was to put something like this in the constructor of the Enemy class:
public Enemy(String name, int hp, int atk, int exp) {
super(name, Player.getLevel + 1, hp, atk);
this.exp = exp;
}
But that is clearly not allowed. Now I have no idea how to achieve this result. I lack some basic understanding of Java, but I'm willing to learn.
My code looks like this at the moment. I left the getters and setters out for better readability.
public class Creature {
private String name;
private int level;
private int hp;
private int atk;
public Creature (String name, int level, int hp, int atk){
this.name = name;
this.level = level;
this.hp = hp;
this.atk = atk;
}
}
public class Player extends Creature {
private int currentEXP;
private int expBar;
public Player(String name) {
super(name, 1, 100, 10);
this.currentEXP = 0;
this.expBar = 50;
}
}
public class Enemy extends Creature {
int exp;
public Enemy(String name, int level, int hp, int atk, int exp) {
super(name, level, hp, atk);
this.exp = exp;
}
}
First of all, the private modifier makes level unavailable in the subclasses. To solve that, you can either make change private to protected (or nothing / default), or you can provide an accessible getter method (int getLevel() { return level; }).
Your Enemy constructor takes a level argument, so to implement the player level + 1 feature, you can simply pass player.getLevel() + 1, alternatively pass player.getLevel() and let the constructor take care of adding 1.
The method using these classes (assuming main for now) would look something like this:
public static void main(String[] args) {
Player p = new Player("Player1");
Enemy e = new Enemy("Enemy1", p.getLevel() + 1, 100, 10, 40);
}
To clarify, the reason why Player.getLevel + 1 doesn't work is because Player is a class, but you need a Player object (i.e. the result of calling new Player(...)) to refer to instance fields or methods, such as getLevel.
Just started learning java recently, and in my textbook I came across this which was very confusing at first but now its starting to make sense. Now, in my book we
started basic applications of constructors and as a side note on the page it said this, can also be used to call other constructors. I was a bit confused, then
look at other questions on SO regarding this. I think I get it to an extent now, but WHY would I ever want to do this? Consider the following which I just made up.
private double balance;
private double interest;
public Account(double initialBalance){
balance = initialBalance;
}
public Account(double balance, double interest){
this(0);
balance = initialBalance;
this.interest = interest;
}
Here this(0);, to my understanding looks for another constructor with one parameter, finds Account(double initialBalance), and sets initialBalance to zero.
Great. Erm, but why wouldn't I just do that directly? Just set balance equal to zero! I am sure it is very useful but I can't think of any examples.
Thanks!
It's very practical and avoids code duplication:
public Account(){
this(0);
}
public Account(double initialBalance){
this(initialBalance, DEFAULT_INTEREST_RATE);
}
public Account(double balance, double interest){
balance = initialBalance;
this.interest = interest;
}
The constructors with less arguments delegate to constructors with more arguments, passing defaults for the absent arguments.
If this weren't possible, one would need an artificial init(..) method which accepts the parameters, and is called from all constrcutors. This is less secure, as this method could be called repeatedly.
The example from Java documentation will probably make much more sense than the one you have at your hands:
public class Rectangle {
private int x, y;
private int width, height;
public Rectangle() {
this(0, 0, 1, 1);
}
public Rectangle(int width, int height) {
this(0, 0, width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
...
}
Think about that you could do it the other way: Your "basic" constructor is
public Account(double balance, double interest){
balance = initialBalance;
this.interest = interest;
}
and based on this, you could add some simplifications:
public Account(double initialBalance){
this(initialBalance, DEFAULT_INTEREST);
}
public Account(){
this(DEFAULT_INITIAL_BALANCE, DEFAULT_INTEREST);
}
Calling these constructors simplifies changing the principal behaviour: if I, e. g., want to register the new object somewhere, I can do so at one central place and have the other constructors rely on that.
Here's a good example to use another constructor of the same Object:
public Person(String name, String street, String location) {
(...)
//handle them
}
public Person() {
this("default name", "default street", "default location");
}
It's basically a shortcut (Overloading), so you stay clear of redundant code.
Overloading constructors may come in handy many times.
One example is when you have multiple arguments but not all of the are mandatory.
Using overloading you can do something like:
public Account(string id, double balance, string name, strings address){
this.id = id;
this.balance = balance;
this.name = name;
this.address = address;
}
public Account(string id, double balance, string name){
this(id, balance, name, null);
}
public Account(string id, double balance){
this(id, balance, "Unknown" ,null);
}
public Account(string id){
this(id, 0, "Unknown" ,null);
}
That example does indeed make not much sense.
The following does.
private double balance;
private double interest;
public Account(double initialBalance){
this(initialBalance, 9.99);
}
public Account(double balance, double interest){
this.balance = balance;
this.interest = interest;
}
And indeed one calls another constructor, that typically does some work than just assigning.
For the original example it could be that the simple constructor was made first, and later the constructor with the extra argument was added for an extra field interest.
So one might see this construct often, and it is comparable with calls to super(...)
Also in simple cases, this usage follows the DRY principle: Don't Repeat Yourself. Mind if one of the constructor had just a bit different couple of assignments in time, the program would become constructor case dependent. Now you know, that the same code is walked through, and you do not have to test that functionality N times.
This is called "constructor overloading". Just like method overloading, this is Java's way of allowing you to supply different amounts of parameters for a single method.
It is generally used for methods, or in this case, constructors that have "optional" parameters. Heres an example that should make it more obvious:
class Cat{
private int paws;
private String name;
public Cat(String name){
//Assume that the cat is physically not handicapped, and thus has 4 paws
this(name,4);
}
public Cat(String name, int paws){
this.name = name;
this.paws = paws;
}
}
It would make more sense if you put it the other way around.
public Account(double initialBalance){
this(initialBalance, 2.0); // 2.0 being a default interest (whatever you'd like, could be 0).
}
public Account(double balance, double interest){
this.balance = balance;
this.interest = interest;
// Some more very difficult business logic
}
This way you can prevent duplicate code. A change in the difficult business logic would only have to be changed once (if needed).
I'm making a game in java and consistenetly get the strangest bug. I have a class called weapon. Then I create an instance of it called primary. After I create an instance and call it secondary. for some strange reason, primary gets overwritten with secondary's values. My instructor and I both looked at it and couldn't figure it out. Here's the code:
public class weapon {
static String type;
static String name;
static int weight;
static int damage;
static int dodge;
weapon(String c, String n, int w, int da, int dod) {
type = c;
name = n;
weight = w;
damage = da;
dodge = dod;
}
//getters
String getType(){
return type;
}
String getName(){
return name;
}
Integer getWeight(){
return weight;
}
Integer getDamage(){
return damage;
}
Integer getDodge(){
return dodge;
}
//setters
void setType(String c){
c=type;
}
void setName(String n){
n=name;
}
void setWeight(Integer w){
w=weight;
}
void setDamage(Integer da){
damage=da;
}
void setDodge(Integer dod){
dodge=dod;
}
}
/*At the top of my main class I create both instances like this because the instances are created in if statements and I need to access them.*/
weapon primary;
weapon secondary;
//I create primary like this earlier in the code like this
primary = new weapon("primary","sword", 8, 6, -1);
//and then when I run this I get the output "sword" "Heavy Sword".
System.out.println(primary.getName());
secondary = new weapon("secondary", "huge sword", 9, 7, -2);
System.out.println(primary.getName());
All your member variables are defined as static :
static String type;
static String name;
static int weight;
static int damage;
static int dodge;
That's why the values of the second instance override the first (since static members are class veriables - there is a single copy of them across all instances of the class).
Removing the static keyword would solve the problem.
All the properties of your Weapon class are static, which means they are shared among all instances you create.
Remove static to make them instance variables instead, and you should be fine.
You have created a class with class wide variables rather than variables that are different for each object created.
Instead use:
public class weapon {
private String type;
private String name;
private int weight;
private int damage;
private int dodge;
weapon(String c, String n, int w, int da, int dod) {
I would suggest you use the following pattern when you define classes to help ensure your "class fields" and "object fields" are well described
public class <name-of-class> {
// Class fields
<private|public|protected> [final] static ....
// Object fields
private ...
All the member variables are declared as static. When you declare a member variable as static all the objects of that class shares the same copy of those variables. If one object changes value on a variable, it changes for other objects as well.
Simply remove the static keyword.
Weapon appears to be a bean class, it' better to encapsulate if properly with private member variable and public getter/setters.