Abstract Class and toString() method - java

I am a little confused on how to set up the TestHomework method so that it prints properly when using the toString() method. Right now when I run the main method it prints "null - 0" but what I would like it to say is "Math - 6". This program is supposed to extend an abstract class. It is supposed to say how many pages there are for homework and for what subject.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
{
// initialise instance variables
pagesToRead = 0;
typeHomework = "none";
}
public Homework(int pages, String hw) {
this.pagesToRead = pages;
this.typeHomework = hw;
}
public abstract void createAssignment(int p);
public int getPages() {
return pagesToRead;
}
public void setPagesToRead(int p) {
pagesToRead = p;
}
public String getTypeHomework() {
return typeHomework;
}
public void setTypeHomework(String hw) {
typeHomework = hw;
}
}
public class MyMath extends Homework {
private int pagesRead;
private String typeHomework;
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
public String toString() {
return typeHomework + " - " + pagesRead;
}
}
public class TestHomework {
public static void main(String[] args) {
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
System.out.println(one);
}
}

That's because you are defining the 2 properties (that one of them happen to have the same name as one of the abstract class's) but you are not initializing them, you are initializing those of the abstract class. (So their values is always set to their type's default)
You need to drop those from the MyMath class, & define the toString method in your abstract class: it's the one to be used by default by its inheriting classes.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
// Same code
// Define the toString here
#Override
public String toString() {
return typeHomework + " - " + pagesToRead;
}
}
public class MyMath extends Homework {
// You don't need to define any extra attributes
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
}
public static void main(String[] args) {
// Calls the constructor of the MyMath class, which in turn
// invokes the constructor of its superclass, the 'Homework' class
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
// Invokes the toString of the MyMath class. Since it does not have one,
// The toString method of its superclass (Homework) is called.
System.out.println(one);
}

Your derived class has its own typeHomework and pagesRead fields, which are never set (even though the base class happens to have fields with the same names). Therefore, they stay null and 0.
You should delete those fields and use the data from the base class, via the public getter methods.

Why it doesn't work:
Be careful you redeclared the attribute typeHomework of you parent class. Attributes are automatically added to your extending class so you don't have to write them again.
By redeclaring it you confused the compiler, viewing your code in debug shows, that your one object contains your typeHomework twice:
typeHomework = null // The one from the super class
typeHomework = "Math" // The one from your child class
Your method now uses the typeHomework from your super-class therefor the output is null!
pagesRead is 0 because you are setting the pagesToRead of your super-class to 6(not pagesRead!) when calling setPagesToRead(p);.
Some style tips
Use the #Override annotation when overriding methods like this:
#Override
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
It's not really needed but it's good practice (readers of your code know that it overrides something).
When referring to attributes of your class it's also good practice to use the this statement so it's clear, that you're referring to an attribute and not a local variable:
#Override
public String toString() {
return this.typeHomework + " - " + this.pagesRead;
}

Related

Class that is extended from an abstract class toString method doesn't work :/

This is the main demo class
public class Ongoing{
public static void main(String[] args){
ExtendsAbstract josh = new ExtendsAbstract(5, "donkey");
System.out.println(josh.toString());
}
}
this is the class extended from the abstract class, the one who's tostring method won't work.
public class ExtendsAbstract extends Abstract{
private String t;
public ExtendsAbstract(int y, String t){
super(y);
this.t = t;
}
public String getString(){
return this.t;
}
public int getInt(){
return super.getInt();
}
public String toString(int y){
return(/*super.toString(y)+*/"The integer is "+ y) ;
}
}
This is the abstract class
public abstract class Abstract{
private int y;
public Abstract(int y){
this.y = y;
}
public int getInt(){
return y;
}
public String toString(int y){
return("The integer is :"+y);
}
}
Every time i try and access the toString method from the extended class it just prints out what i think is a memory address. I even didn't mess with the abstract class and it still did that, does anyone know why? Also another question about abstract classes, what advantages do they bring, is it just memory? Because you can't access private members from it so isn't it the same as a normal class, just more restrictions?
Say that you have classes Dad and Son which are defined like this
public class OverLoadedToString {
public static void main(String[] args) {
Son son = new Son();
son.test();
son.test(90);
}
}
class Dad {
void test() {
System.out.println("Dad - test");
}
}
class Son extends Dad {
void test(int testTime) {
System.out.println("Son - test1" + testTime);
}
}
The Son class is extending Dad so the test() with no arguments is inheriting to Son, just like your ExtendsAbstract class is having toString() with no arguments inheriting from Object class (every class in Java inherits Object class).
Then in Son class I added new method test(int testTime), which has got an argument, that makes test() and test(int testTime) different which is called method overloading. In you ExtendsAbstract class there are two toString methods one is the no-arg inherited and the other you defined.
Now let me show you the inheritance flow
Object--->Abstract--->ExtendsAbstract
Object class toString() methods prints the memory address, we can override it in our classes to change its definition, you can return any string that you want. But you haven't overridden it anywhere in either Abstract class or ExtendsAbstract class, so in both classes it will print the memory address.
Now in your Ongoing class you are calling that Object class toString() method which always prints memory address. Your confusion is that you think you have overridden the toString() method but actually you have just overloaded it and you are calling the wrong method for your expected output.
Reference : Java overloading and overriding
Currently, what happens is toString() of object is getting called which goes like this: ClassName#HashCode.
You can do this to print: (Add an #Override at toString()). Also, no need to call josh.toString(). You can simply call System.out.println(josh); (magic will happen and it will call toString)..
public class ExtendsAbstract extends Abstract{
private String t;
public ExtendsAbstract(int y, String t){
super(y);
this.t = t;
}
public String getString(){
return this.t;
}
public int getInt(){
return super.getInt();
}
#Override
public String toString(int y){
return(/*super.toString(y)+*/"The integer is "+ y) ;
}
}
The "toString()" method must be like this:
#Override
public String toString(){
return("The integer is "+ y) ;
}
The "#Override" annotations is used for compiler checking, is not mandatory.
More info about the annotation here: https://docs.oracle.com/javase/7/docs/api/java/lang/Override.html

Set methods in a subclass

I need to set values from the subclass by invoking the set method from the super class. I need to set monster name and health from the subclass
Alien class
public class Alien {
//Instance variables
public String monsterName;
public int HP;
//A method that sets monster properties
public void setValues(String monsterN, int health) {
monsterName = monsterN;
HP = health;
}
//A method that returns the monster name
public String getName() {
return monsterName;
}
//A method that returns monster's health
public int getHP() {
return HP;
}
//ToString method that prints out the info
public String toString() {
return("Monster name: " + getName() + "Monster's current health point: " + getHP());
}
}
Snake class
public class SnakeAlien extends Alien {
//Instance variable
//Set the snake values
Alien aObject = new Alien();
aObject.setvalues("Snake\n" 55));
}
The main class
public class Main {
public static void main(String[] args) {
Alien object = new Alien();
object.toString();
System.out.println(object);
}
}
I know how would I set these values through the main class, but I need to do it from the sub class SnakeAlien which inherets from the Alien class.
Because everything is public (which is terrible BTW) you can simply call the superclass' methods frimbthe subclasses. Not even super is needed.
Though, you should change members you don't want to reach from the outside to at least protected, and if you never want to make a pure Alien object, you should make that an avstract class.

How to call a method in an abstract class properly

public abstract class Human{
public String name;
public int number
public void getInfo(){
Name = JOptionPane.showInputDialog("Please enter your name: ");
money = Double.parseDouble(JOptionPane.showInputDialog("Please enter amount of money .00: "));
}
public void displayInfo(){
JOptionPane.showMessageDialog(null,"Name: "+name+"\n"+
"Number: "+number);
}
}
public class Student extends Human {
}
public class Teacher extends Human{
}
public class Janitor extends Human{
{
I need help if calling the methods getInfo() and displayInfo() in all 3 classes below. I have tried:
public class Student extends Human{
public Student(){
getInfo();
displayInfo();
}
it works, but it generates a warning saying "problematic call in constructor" I guess it is not the best way to do it.
I also tried:
#Override
public void getInfo() {
}
but if I leave it empty nothing happens. Basically I am trying to call the method in the abstract class in a simple way without needing to type it up in every class.
As already mentioned, you shouldn't call overridable methods in constructors, because if another class overrides this method and invokes the constructor of the superclass, it may try to use values that are not initialized yet, since the overriden method will be invoked. Example:
public class Superclass {
protected int id;
protected void foo() {
System.out.println("Foo in superclass");
}
public Superclass() {
foo();
}
}
public class Subclass extends Superclass {
public Subclass(int id) {
super();
this.id = id;
}
#Override
protected void foo() {
System.out.println("Id is " + id);
}
}
This will print the unitialized value of id, since you first call the constructor of the superclass which invokes the foo method of the subclass.
You can fix this by making your methods final if this suits your case.
You get the warning because it's a good practice not to call overridables in the constructor; since these overridables could try to access member variables that are not initialized yet (== null) .
You shouldn't call overridable functions inside a constructor. check this link

Accessing subclass method from arraylist of superclass

For an assignment, I have an ArrayList of type "Reference". Reference is a parent class to the "Book" class and "Journal" class. If I am allowed to add objects of type "Book" and "Journal" to the Arraylist, why would I be getting an error if I want to access methods of Book and Journal via the following code?
ArrayList.get([someindex]).someBookorJournalMethod()
The arraylist itself is of the parent class, and the methods I want to access are only defined for either book or either journal.
EDIT: Here is some code
public class Books extends Reference{
private String Authors;
private String Publishers;
public Books(String CallNum, String Author, String Title, String Publisher, int year,String type)
{
super(CallNum,Title,year,type);
Authors= Author;
Publishers=Publisher;
}
public String getAuthor()
{
return Authors;
}
public class LibrarySearch {
private ArrayList<Reference> Library;
public LibrarySearch()
{
Library = new ArrayList<Reference>(100);
}
public outputLibrary(){
for (int i = 0 ; i < Library.size(); i+++)
{
if (Library.get(i).getType().equals("Book"))
{
System.out.println("Type:book\n" + "Call Number:" + Library.get(i).getCallNumber() +"\n" + "Authors:" + Library.get(i).getAuthors();)
}
}
}
IntelliJ is having issues with the line Library.get(i).getAuthors() because it is a method specific to Books. How would I resolve this?
Because when you specify the type of a variable, you can only invoke methods that are defined for this type. For example, if you have
public class A {
public void methodA() {
System.out.println("A");
}
}
public class B extends A {
public void methodB() {
System.out.println("B");
}
}
public class Main {
public static void main(String[] args) {
A ab = new B();
ab.methodB();
}
}
This will not compile, since the type defined for the variable ab is A and the only visible methods are those that are defined in A.
In your case you can simply add a blank method in Reference(if you don't want to make the class abstract):
public void someBookorJournalMethod() {}
Or you can explicitly cast the object you're trying to invoke the method for.
However, it is important to note that both approaches are usually bad practices and should be avoided. If it does not make sense to instantiate Reference objects, than make the class abstract and define someBookorJournalMethod as an abstract method. In your code you're most probably using inheritance in a wrong way.
You can't access the method of a subclass from the superclass. So you'll need to cast to a Book or a Journal.
Reference r =ArrayList.get([someindex]);
if (r instanceof Book) {
((Book) r).someBookMethod();
} else if (r instanceof Journal) {
((Journal) r).someJournalMethod();
}

Is there a way to override class variables in Java?

class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String me = "son";
}
public void doIt()
{
new Son().printMe();
}
The function doIt will print "dad". Is there a way to make it print "son"?
In short, no, there is no way to override a class variable.
You do not override class variables in Java you hide them. Overriding is for instance methods. Hiding is different from overriding.
In the example you've given, by declaring the class variable with the name 'me' in class Son you hide the class variable it would have inherited from its superclass Dad with the same name 'me'. Hiding a variable in this way does not affect the value of the class variable 'me' in the superclass Dad.
For the second part of your question, of how to make it print "son", I'd set the value via the constructor. Although the code below departs from your original question quite a lot, I would write it something like this;
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void printName() {
System.out.println(name);
}
}
The JLS gives a lot more detail on hiding in section 8.3 - Field Declarations
Yes. But as the variable is concerned it is overwrite (Giving new value to variable. Giving new definition to the function is Override). Just don't declare the variable but initialize (change) in the constructor or static block.
The value will get reflected when using in the blocks of parent class
if the variable is static then change the value during initialization itself with static block,
class Son extends Dad {
static {
me = "son";
}
}
or else change in constructor.
You can also change the value later in any blocks. It will get reflected in super class
Yes, just override the printMe() method:
class Son extends Dad {
public static final String me = "son";
#Override
public void printMe() {
System.out.println(me);
}
}
You can create a getter and then override that getter. It's particularly useful if the variable you are overriding is a sub-class of itself. Imagine your super class has an Object member but in your sub-class this is now more defined to be an Integer.
class Dad
{
private static final String me = "dad";
protected String getMe() {
return me;
}
public void printMe()
{
System.out.println(getMe());
}
}
class Son extends Dad
{
private static final String me = "son";
#Override
protected String getMe() {
return me;
}
}
public void doIt()
{
new Son().printMe(); //Prints "son"
}
If you are going to override it I don't see a valid reason to keep this static. I would suggest the use of abstraction (see example code). :
public interface Person {
public abstract String getName();
//this will be different for each person, so no need to make it concrete
public abstract void setName(String name);
}
Now we can add the Dad:
public class Dad implements Person {
private String name;
public Dad(String name) {
setName(name);
}
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
the son:
public class Son implements Person {
private String name;
public Son(String name) {
setName(name);
}
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
and Dad met a nice lady:
public class StepMom implements Person {
private String name;
public StepMom(String name) {
setName(name);
}
#Override
public final String getName() {
return name;
}
#Override
public final void setName(String name) {
this.name = name;
}
}
Looks like we have a family, lets tell the world their names:
public class ConsoleGUI {
public static void main(String[] args) {
List<Person> family = new ArrayList<Person>();
family.add(new Son("Tommy"));
family.add(new StepMom("Nancy"));
family.add(new Dad("Dad"));
for (Person person : family) {
//using the getName vs printName lets the caller, in this case the
//ConsoleGUI determine versus being forced to output through the console.
System.out.print(person.getName() + " ");
System.err.print(person.getName() + " ");
JOptionPane.showMessageDialog(null, person.getName());
}
}
}
System.out Output : Tommy Nancy Dad
System.err is the same as above(just has red font)
JOption Output: Tommy then Nancy then Dad
This looks like a design flaw.
Remove the static keyword and set the variable for example in the constructor. This way Son just sets the variable to a different value in his constructor.
Though it is true that class variables may only be hidden in subclasses, and not overridden, it is still possible to do what you want without overriding printMe () in subclasses, and reflection is your friend. In the code below I omit exception handling for clarity. Please note that declaring me as protected does not seem to have much sense in this context, as it is going to be hidden in subclasses...
class Dad
{
static String me = "dad";
public void printMe ()
{
java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
System.out.println (field.get (null));
}
}
https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
It's called Hiding Fields
From the link above
Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String _me = me = "son";
}
public void doIt()
{
new Son().printMe();
}
... will print "son".
It indeed prints 'dad', since the field is not overridden but hidden. There are three approaches to make it print 'son':
Approach 1: override printMe
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String me = "son";
#override
public void printMe()
{
System.out.println(me);
}
}
public void doIt()
{
new Son().printMe();
}
Approach 2: don't hide the field and initialize it in the constructor
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
public Son()
{
me = "son";
}
}
public void doIt()
{
new Son().printMe();
}
Approach 3: use the static value to initialize a field in the constructor
class Dad
{
private static String meInit = "Dad";
protected String me;
public Dad()
{
me = meInit;
}
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
private static String meInit = "son";
public Son()
{
me = meInit;
}
}
public void doIt()
{
new Son().printMe();
}
Variables don't take part in overrinding. Only methods do. A method call is resolved at runtime, that is, the decision to call a method is taken at runtime, but the variables are decided at compile time only. Hence that variable is called whose reference is used for calling and not of the runtime object.
Take a look at following snippet:
package com.demo;
class Bike {
int max_speed = 90;
public void disp_speed() {
System.out.println("Inside bike");
}
}
public class Honda_bikes extends Bike {
int max_speed = 150;
public void disp_speed() {
System.out.println("Inside Honda");
}
public static void main(String[] args) {
Honda_bikes obj1 = new Honda_bikes();
Bike obj2 = new Honda_bikes();
Bike obj3 = new Bike();
obj1.disp_speed();
obj2.disp_speed();
obj3.disp_speed();
System.out.println("Max_Speed = " + obj1.max_speed);
System.out.println("Max_Speed = " + obj2.max_speed);
System.out.println("Max_Speed = " + obj3.max_speed);
}
}
When you run the code, console will show:
Inside Honda
Inside Honda
Inside bike
Max_Speed = 150
Max_Speed = 90
Max_Speed = 90
only by overriding printMe():
class Son extends Dad
{
public void printMe()
{
System.out.println("son");
}
}
the reference to me in the Dad.printMe method implicitly points to the static field Dad.me, so one way or another you're changing what printMe does in Son...
You cannot override variables in a class. You can override only methods. You should keep the variables private otherwise you can get a lot of problems.
No. Class variables(Also applicable to instance variables) don't exhibit overriding feature in Java as class variables are invoked on the basis of the type of calling object. Added one more class(Human) in the hierarchy to make it more clear. So now we have
Son extends Dad extends Human
In the below code, we try to iterate over an array of Human, Dad and Son objects, but it prints Human Class’s values in all cases as the type of calling object was Human.
class Human
{
static String me = "human";
public void printMe()
{
System.out.println(me);
}
}
class Dad extends Human
{
static String me = "dad";
}
class Son extends Dad
{
static String me = "son";
}
public class ClassVariables {
public static void main(String[] abc) {
Human[] humans = new Human[3];
humans[0] = new Human();
humans[1] = new Dad();
humans[2] = new Son();
for(Human human: humans) {
System.out.println(human.me); // prints human for all objects
}
}
}
Will print
human
human
human
So no overriding of Class variables.
If we want to access the class variable of actual object from a reference variable of its parent class, we need to explicitly tell this to compiler by casting parent reference (Human object) to its type.
System.out.println(((Dad)humans[1]).me); // prints dad
System.out.println(((Son)humans[2]).me); // prints son
Will print
dad
son
On how part of this question:- As already suggested override the printMe() method in Son class, then on calling
Son().printMe();
Dad's Class variable "me" will be hidden because the nearest declaration(from Son class printme() method) of the "me"(in Son class) will get the precedence.
Just Call super.variable in sub class constructor
public abstract class Beverage {
int cost;
int getCost() {
return cost;
}
}`
public class Coffee extends Beverage {
int cost = 10;
Coffee(){
super.cost = cost;
}
}`
public class Driver {
public static void main(String[] args) {
Beverage coffee = new Coffee();
System.out.println(coffee.getCost());
}
}
Output is 10.
Of course using private attributes, and getters and setters would be the recommended thing to do, but I tested the following, and it works... See the comment in the code
class Dad
{
protected static String me = "dad";
public void printMe()
{
System.out.println(me);
}
}
class Son extends Dad
{
protected static String me = "son";
/*
Adding Method printMe() to this class, outputs son
even though Attribute me from class Dad can apparently not be overridden
*/
public void printMe()
{
System.out.println(me);
}
}
class Tester
{
public static void main(String[] arg)
{
new Son().printMe();
}
}
Sooo ... did I just redefine the rules of inheritance or did I put Oracle into a tricky situation ?
To me, protected static String me is clearly overridden, as you can see when you execute this program. Also, it does not make any sense to me why attributes should not be overridable.
Why would you want to override variables when you could easily reassign them in the subClasses.
I follow this pattern to work around the language design. Assume a case where you have a weighty service class in your framework which needs be used in different flavours in multiple derived applications.In that case , the best way to configure the super class logic is by reassigning its 'defining' variables.
public interface ExtensibleService{
void init();
}
public class WeightyLogicService implements ExtensibleService{
private String directoryPath="c:\hello";
public void doLogic(){
//never forget to call init() before invocation or build safeguards
init();
//some logic goes here
}
public void init(){}
}
public class WeightyLogicService_myAdaptation extends WeightyLogicService {
#Override
public void init(){
directoryPath="c:\my_hello";
}
}

Categories