Polymorphic Subclass Object method in Array not working - java

first off I tried researching my problem but I have no idea how to word my question ... so I am not sure if there is a question out there that solves my problem and also not sure if this is the best wording for my question either.
So, I have a Superclass Shape
public abstract class Shape {
protected String name;
protected String type;
public Shape(){
name = "";
type = "";
}
public void print (){
System.out.printf("Name = %s, Type = %s", name, type);
}
}
and a Subclass 2D
public abstract class TwoDimensionalShape extends Shape{
protected double length;
protected double area;
public TwoDimensionalShape(double length){
if (length<0.0)
throw new IllegalArgumentException("ERROR: POSITIVE NUMBER REQUIRED");
this.length = length;
type = "Two Dimensional Shape";
}
public abstract void getArea();
#Override
public void print(){
System.out.printf("Name = %s, Type = %s, Length of side = %d, Area = %d",
name, type, length, area);
}
}
along with several smaller subclasses that extend off 2D (and another almost identical class 3D). My problem is with the test code, it doesn't calculate area. Class Test code
Circle S1 = new Circle(2.5);
etc.
shapesArray[0] = S1;
etc.
for(Shape CS : shapesArray){
CS.getArea();
if(CS.Type == "Three Dimensional Shape"){
CS.getVolume();
}
CS.print();
System.out.println(" ");
}
}
I removed the getArea and getVolume methods and the print statement worked fine. Which lead me to think there is a problem with the way each subclass interacts with the superclass, however, the subclass print methods override and return the correct values (except for area :( )
With the area and volume commands, the code doesn't compile and I get this error
ShapeTest.java:25: error: cannot find symbol
CS.getArea();
three times.
Here is one of the subclasses, in case it holds important info needed for a solution.
public class Circle extends TwoDimensionalShape {
public Circle(double length){
super(length);
name = "Circle";
}
#Override
public void getArea(){
area = Math.PI * length * length;
}
#Override
public void print(){
System.out.printf("Name = %s, Type = %s, Radius = %f, Area = %f",
name, type, length, area);
}
}
I am not experienced enough to understand the problem entirely and I have been changing loops, location of variables and methods in the classes but I have not made progress. I thank you for reading this long question and id appreciate any help you can offer.

Your type Shape doesn't declare that method.
The compiler doesn't know that you intend to put TwoDimensionalShape objects into that array. It only see that you said: this array contains Shapes; and shapes do no have those other two methods!
So you could do:
declare that array to contain only TwoDimensionalShape objects. Of course, then you can't add 3D
use if (thing is instanceof TwoDimensionalShape) { and then cast to that type
And then: you dont need a string type. All objects have a class; and that class already defines its exact type. That is why you use instanceof to determine types; not by adding a string field and comparing that string (the wrong way with ==) to other strings!

Your super most class Shape should have all the methods you want to access through polymorphic feature of java.
One would assign a sub-type instance of to a supertype variable to handle all possible subtype classes in a uniform fashion, e.g. using methods declared (but possibly overriden) by the supertype class.
I have made minor changes to your classes.
abstract class Shape {
protected String name;
protected String type;
public Shape() {
name = "";
type = "";
}
public void print() {
System.out.printf("Name = %s, Type = %s", name, type);
}
public abstract void getArea();
public abstract void getVolume();
}
// ----------------
abstract class TwoDimensionalShape extends Shape {
protected double length;
protected double area;
public TwoDimensionalShape(double length) {
if (length < 0.0)
throw new IllegalArgumentException(
"ERROR: POSITIVE NUMBER REQUIRED");
this.length = length;
type = "Two Dimensional Shape";
}
#Override
public void print() {
System.out.printf(
"Name = %s, Type = %s, Length of side = %d, Area = %d", name,
type, length, area);
}
}
//------------------
class Circle extends TwoDimensionalShape {
public Circle(double length) {
super(length);
name = "Circle";
}
#Override
public void getArea() {
area = Math.PI * length * length;
}
#Override
public void print() {
System.out.printf("Name = %s, Type = %s, Radius = %f, Area = %f", name,
type, length, area);
}
#Override
public void getVolume() {
System.out.println("Vaolume method invoked");
}
}
//------------------
public class Dim {
public static void main(String[] args) {
Shape[] shapesArray = new Shape[10];
Circle S1 = new Circle(2.5);
shapesArray[0] = S1;
for (Shape CS : shapesArray) {
if (CS != null) {
CS.getArea();
if (CS.type.equals("Three Dimensional Shape")) {
CS.getVolume();
}
CS.print();
System.out.println(" ");
}
}
}
}

Related

How to make a Constructor without parameters?

I have to write a program that has a constructor without parameters. I created another short program as an example to show what I do not understand.
So I have a class with the main-method:
public class Dog {
public static void main(String[] args) {
CharacteristicsOfTheDog Dog1 = new CharacteristicsOfTheDog(20, 40);
System.out.println(Dog1.toString());
}
}
Now implemented another class:
public class CharacteristicsOfTheDog {
int size = 0;
int kilogram = 0;
public CharacteristicsOfTheDog(/*int size, int kilogram*/) {
// this.size = size;
// this.kilogram = kilogram;
}
public double getSize() {
return size;
}
public double getKilogram() {
return kilogram;
}
public String toString() {
return "The Dog is " + getSize() + " cm and " + getKilogram() + " kg";
}
}
In the class "CharacteristicsOfTheDog" in "public CharacteristicsOfTheDog()" I removed the parameters by commenting them out. So the Problem is: if I remove the parameters the program does not work:/ but my task is to do this without the parameters (as far as I understood). Can someone help me please?
Keep your no-arg constructor and then add setters for your properties:
public class CharacteristicsOfTheDog {
int size = 0;
int kilogram = 0;
public CharacteristicsOfTheDog() {
}
public void setSize(int size){
this.size = size;
}
public void setKilogram(int kilogram){
this.kilogram = kilogram;
}
}
In your other class, call:
CharacteristicsOfTheDog dog1 = new CharacteristicsOfTheDog();
dog.setSize(20);
dog.setKilogram(40);
As a suggestion, the naming of your class as CharacteristicsOfTheDog is rather literal and stating the obvious. Properties and methods of a class are what describes the characteristics of a class in terms of it's properties and behavior. If you just name your class Dog, that would be perfect. No need to state the obvious.
Unless CharacteristicsOfTheDog is a subclass or you have a constructor with parameters, you don't need an empty constructor. Just omit it. The following works just fine.
If the parent class has a constructor with arguments, then the parent class will need an explicit empty constructor, but the following should still work.
CharacteristicsOfTheDog cotd = new CharacteristicsOfTheDog();
cotd.setKilogram(100);
}
class CharacteristicsOfTheDog {
int size = 0;
int kilogram = 0;
public void setSize(int size){
this.size = size;
}
public void setKilogram(int kilogram){
this.kilogram = kilogram;
}
}
Depending on your use case, you might want to make the Characteristics class an interface and implement it.

choosing specific object in an array of objects

public abstract class ShapeClass {
private double area;
CONSTRUCTORS
MUTATORS, ACCESSORS
public abstract double calcArea();
}
public class CircleClass extends ShapeClass {
private int diameter;
private double area;
public CircleClass() {
super();
diameter = 10;
}
public CircleClass(CircleClass inCircle) {
super(inCircle);
diameter = inCircle.getDiameter();
}
public CircleClass(int inDiameter) {
setDiameter(inDiameter);
area = calcArea();
super.setArea(area);
}
public void setDiameter(int inDiameter) {
if(validateInt(inDiameter)) {
diameter = inDiameter;
} else {
throw new IllegalArgumentException("invalid diameter");
}
}
public int getDiameter() {
return diameter;
}
public boolean equals(int inDiameter) {
return(diameter == inDiameter);
}
public boolean equals(Object inObj) {
boolean same = false;
if(inObj instanceof CircleClass) {
CircleClass inCircle = (CircleClass)inObj;
if(super.equals(inCircle)) {
if(diameter == inCircle.getDiameter()) {
same = true;
}
}
}
return same;
}
public String toString() {
return (" area of circle is: " + super.toString());
}
private boolean validateInt(int inDiameter) {
boolean valid = false;
if (inDiameter>0) {
valid = true;
}
return valid;
}
private boolean validateReal(double inArea) {
boolean valid = false;
if(inArea>0.0) {
valid = true;
}
return valid;
}
#Override
public double calcArea() {
double radius;
radius = ((double) diameter) / 2.0;
area = Math.PI * radius * radius;
return area;
}
}
This is my code for a ShapeClass. I have two other classes Rectangle and Triangle, they're pretty much the same as the CircleClass.
In another class i'm assigning the ShapeClass objects in an array.
if I do that it'll be something like shape[3] = {Shape Object,Shape Object,Shape Object}. I don't know if that's right, I'm new to java. Sorry if there's any confusion.
My question is if I do that how do I distinguish what object is Circle, Rectangle or Triangle? When I want to print out a circle object only?
Thanks for the help.
You can check by using instanceof :
if(shape[0] instanceof Circle){
// do something
}
So there is an operator in java - instance of:
if(shapeObject instanceof Circle){
//print
}
so you can use it to distinguish objects by type. Also as for your question whether it's correct: You can use this approach with creating array of parent object type and putting children in it. After that, if you call toString method on each object from that array specific implementation of that method will be invoked. For example if there is Circle object in this array and there is overridden toString method in it then after calling toString on object from array of ShapeObject specific implementations will be invoked.
Try like this,
for(int i = 0; i < shapeArray.length; i++){
if(shapeArray[i] instanceof CircleClass){
// print circle here
}
}
You have 2 options:
// Solution 1: prits out all instances of Circle, basically also all subclasses of Circle
for (ShapeClass shape : shapes) {
if (shape instanceof CircleClass)
System.out.println(shape.toString());
}
// Solution 2: Matches exact class
for (ShapeClass shape : shapes) {
if (shape.getClass().equals(CircleClass.class))
System.out.println(shape.toString());
}
The above solutions will solve the task you asked about. But maybe the information below will be userful for you:
What if you want to print out the names of each shape, how to distingush them in this case?
Let's say we have 3 shapes:
public class Shape {
public void print() {
System.out.println("Shape is printed");
}
}
public class Triangle extends Shape {
#Override
public void print() {
System.out.println("Triangle is printed");
}
}
public class Circle extends Shape {
#Override
public void print() {
System.out.println("Circle is printed");
}
}
This code will print exactly what you need, because you defined the same function for all of the shapes, overriding it in child classes, and the appropriate function will be called based on object type determined at the runtime:
for (Shape shape : shapes) {
shape.print();
}

Java: How to I get values inside ArrayList when there's parent/child involved?

So I have an ArrayList of objects. Inside those objects are various attributes and their values.
The code is pretty simple. GBox and GCircle are childs of GHP. The ArrayList is in World.
What I want to do is print the HP and volume of the box and the HP and diameter of the circle. I understand I could override toString() but I actually want to get the values. What's the correct syntax to do so?
//Main.java
public class Main {
public static void main(String[] args) {
Ini i = new Ini();
}
}
//Ini.java
public class Ini {
private static World w;
public Ini() {
w = new World;
w.makeGBox();
w.makeGCircle();
System.out.println("Box: HP: " +
w.getList().get(0).getHP() +
"Volume: " +
w.getList().get(0).GBox.getVolume());
//compile error no variable GBox in GHP
System.out.println("Circle: HP: " +
w.getList().get(1).getHP() +
"Radius: " +
w.getList().get(1).GCircle.getRadius());
//compile error no variable GCircle in GHP
}
}
//World.java
import java.util.ArrayList;
public class World {
private ArrayList<GHP> list = new ArrayList<>();
public void makeGBox() {
list.add(new GBox());
}
public void makeGCircle() {
list.add(new GCircle());
}
public ArrayList<GHP> getList() {
return list;
}
}
//GHP.java
public class GHP {
private int HP;
public GHP() {
setHP(5);
}
public int getHP() {
return HP;
}
public void setHP(int HP) {
this.HP = HP;
}
}
//GBox.java
public class GBox extends GHP{
private int volume;
public GBox() {
setVolume(10);
}
public int getVolume() {
return volume;
}
public void setVolume(int volume) {
this.volume = volume;
}
}
//GCircle.java
public class GCircle extends GHP{
private int radius;
public GCircle {
setRadius(7);
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
}
Apart from the many compilation problems, you need these changes to achieve what you want.
for (GHP ghp : w.getList()) { // Avoid using get(index) without a forloop, as such
if (ghp instanceof GBox) { // Using the instanceof operator, you can differentiate the 2 class types
System.out.println("Box: HP: " + ghp.getHP() + "Volume: "
+ ((GBox) ghp).getVolume()); // Cast it to GBox to be able to call getVolume
}
if (ghp instanceof GCircle) {
System.out.println("Circle: HP: " + ghp.getHP() + "Radius: "
+ ((GCircle) ghp).getRadius());// Cast it to GCircle to be able to call getRadius
}
}
You would need to cast the generic GHP reference to the specific type like:
((GCircle) ghp).getRadius()
You might also want to have a look on instanceof operator.
The idea being:
for output you override the toString() method because you don't need any class specific information, just print out object details
for class-specific operations you downcast to he specific type
When you read the list values, the only thing the compiler knows, is that the list contains GHP instances.
First check the type and then cast it to the subclass.
GHP ghp = w.getList().get(0);
if(ghp instanceof GBox) {
GBox gbox = (GBox) ghp;
// Here you can access the method getVolume()
/* ... */ gbox.getVolume();
}
A cleaner, more OOP alternative to adding methods to the base class and/or instanceof checks is to use the Visitor pattern that allows you to separate your object structure from any algorithms that operate on them. The algorithm in this case is simply a "display" algorithm.
That said, for most simple cases (like this one) adding methods to the base class and overriding or using instanceof is fine.
List<Shape> shapes = new ArrayList<Shape>();
....
...
for (Shape shape : shapes) {
System.out.println(shape.getHp());
if(shape instanceof Circle){
System.out.println(((Circle) shape).getValuem());
}else if(shape instanceof Box){
System.out.println(((Box) shape).getHieght());
}
try this way..

How to write a method that returns an instance of an abstract class?

I am a beginner in Java and i trying to understand the abstract classes.
Below is the code that I've written; the question is: how do i write a method that will return an instance of that class.
public abstract class VehicleEngine
{
protected String name;
protected double fabricationCons;
protected double consum;
protected int mileage;
public VehicleEngine(String n, double fC)
{
name = n;
fabricationCons = fC;
mileage = 0;
consum = 0;
}
private void setFabricationCons(double fC)
{
fabricationCons = fC;
}
public abstract double currentConsum();
public String toString()
{
return name + " : " + fabricationCons + " : " + currentConsum();
}
public void addMileage(int km)
{
mileage += km;
}
public double getFabricationConsum()
{
return fabricationCons;
}
public String getName()
{
return name;
}
public int getMileage()
{
return mileage;
}
//public VehicleEngine get(String name){
//if(getName().equals(name)){
//return VehicleEngine;
//}
//return null;
//}
}
public class BenzinVehicle extends VehicleEngine
{
public BenzinVehicle(String n, double fC)
{
super(n, fC);
}
#Override
public double currentConsum()
{
if (getMileage() >= 75000) {
consum = getFabricationConsum() + 0.4;
} else {
consum = getFabricationConsum();
}
return consum;
}
}
public class DieselVehicle extends VehicleEngine
{
public DieselVehicle(String n, double fC)
{
super(n, fC);
}
#Override
public double currentConsum()
{
int cons = 0;
if (getMileage() < 5000) {
consum = getFabricationConsum();
} else {
consum = getFabricationConsum() + (getFabricationConsum() * (0.01 * (getMileage() / 5000)));
}
return consum;
}
}
This is the main.
public class Subject2
{
public static void main(String[] args)
{
VehicleEngine c1 = new BenzinVehicle("Ford Focus 1.9", 5.0);
DieselVehicle c2 = new DieselVehicle("Toyota Yaris 1.4D", 4.0);
BenzinVehicle c3 = new BenzinVehicle("Citroen C3 1.6",5.2);
c1.addMileage(30000);
c1.addMileage(55700);
c2.addMileage(49500);
c3.addMileage(35400);
System.out.println(c1);
System.out.println(c2);
System.out.println(VehicleEngine.get("Citroen C3 1.6")); //this is the line with problems
System.out.println(VehicleEngine.get("Ford Focus "));
}
}
And the output should be:
Ford Focus 1.9 : 5.0 : 5.4
Toyota Yaris 1.4D : 4.0 : 4.36
Citroen C3 1.6 : 5.2 : 5.2
null
You can not return an instance of an abstract class, by definition. What you can do, is return an instance of one of the concrete (non-abstract) subclasses that extend it. For example, inside the VehicleEngine you can create a factory that returns instances given the type of the instance and the expected parameters, but those instances will necessarily have to be concrete subclasses of VehicleEngine
Have a look at the Factory Method pattern. Your concrete classes will implement an abstract method that returns a class instance.
Abstract classes do not keep a list of their instances. Actually no Java class does that. If you really want to do that, you could add a static map to VehicleEngine like this:
private static Map<String, VehicleEngine> instanceMap = new HashMap<String, VehicleEngine>();
and change your get method to a static one like this:
public static VehicleEngine get(String name) {
return instanceMap.get(name);
}
and add this line to the end of the constructor of VehicleEngine:
VehicleEngine.instanceMap.put(n, this);
this way every new instance created puts itself into the static map. However this actually is not a good way to implement such a functionality. You could try to use a factory to create instances, or you could consider converting this class into an enum if you will have a limited predefined number of instances.

Java: Extending inner classes

I am trying to understand extending inner classes in Java. I have read around but nothing I found quite answers my question. So here goes...
I have...
public class Pie{
protected Slice[] slices;
// Pie constructor
public Pie(int n){
sliceGenerator(n)
}
private void sliceGenerator(int n){
slices = new Slice[n];
final float sweepAngle = 360.0f/(float)n;
float startAngle = 0;
for (int i=0;i<n;i++){
slices[i] = new Slice(startAngle);
startAngle += sweepAngle;
}
}
#Override
public String toString(){
for (Slice s:slices){
s.toString();
}
}
// Inner class...
public class Slice{
public Slice(float startAngle){
//set some private fields based on startAngle and generic pie
}
#Override
public String toString(){
return **string based on private fields**
}
}
}
Then I extend this...
public class ApplePie extends Pie{
protected Slice[] slices;
// Apple Pie constructor
public ApplePie(int n){
super(n);
}
// Inner class...
public class Slice extends Pie.Slice{
public Slice(float startAngle){
super(startAngle);
//set some **additional** private fields based on startAngle **specific to apple pie** appleness or something
}
#Override
public String toString(){
return **string based on apple pie specific private fields**
}
}
}
Now, when I make an Apple pie and call its toString method, like so...
ApplePie ap = new ApplePie(8);
System.out.println(ap.toString());
I do not get information about the apple pie slices, but information about the pie slices. It ignores my toString override, or more likely ignores my apple pie Slice. How can I arrange it such that apple pie slices refer to ApplePie?
Any help much appreciated! Sorry for pie references - it is the actual class I am working with...
I've changed your code to meet your requirements.
Your super class Pie is about to create a new instance of Slice, but the child class ApplePie's Slice does not override the Slice method of its super class'.
I added the functions below to enable the child class to create its own Slice.
protected void newSliceArray(int n) {
slices = new Slice[n];
}
protected Slice newSlice(float startAngle) {
return new Slice(startAngle);
}
Pie.java:
public class Pie {
private int a = 1;
protected Slice[] slices;
// Pie constructor
public Pie(int n) {
sliceGenerator(n);
}
private void sliceGenerator(int n) {
newSliceArray(n);
final float sweepAngle = 360.0f / n;
float startAngle = 0;
for (int i = 0; i < n; i++) {
slices[i] = newSlice(startAngle);
startAngle += sweepAngle;
}
}
protected void newSliceArray(int n) {
slices = new Slice[n];
}
protected Slice newSlice(float startAngle) {
return new Slice(startAngle);
}
#Override
public String toString() {
String t = "";
for (Slice s : slices) {
t += s.toString();
}
return t;
}
// Inner class...
public class Slice {
public Slice(float startAngle) {
// set some private fields based on startAngle and generic pie
}
#Override
public String toString() {
return "" + a;
}
}
}
ApplePie.java:
public class ApplePie extends Pie {
private int b = 2;
// protected Slice[] slices;
// Apple Pie constructor
public ApplePie(int n) {
super(n);
}
protected void newSliceArray(int n) {
slices = new Slice[n];
}
protected Slice newSlice(float startAngle) {
return new Slice(startAngle);
}
// Inner class...
public class Slice extends Pie.Slice {
public Slice(float startAngle) {
super(startAngle);
// set some **additional** private fields based on startAngle **specific to apple pie**
// appleness or something
}
#Override
public String toString() {
return b + "";
}
}
}
Test:
public static void main(String[] args) {
ApplePie ap = new ApplePie(8);
System.out.println(ap.toString());
}
The code will print 22222222
In your superclass, you are creating and storing Pie.Slice objects:
private void sliceGenerator(int n){
slices = new Slice[n];
final float sweepAngle = 360.0f/(float)n;
float startAngle = 0;
for (int i=0;i<n;i++){
slices[i] = new Slice(startAngle);
startAngle += sweepAngle;
}
}
These are the same objects being used by Pie.toString (which ApplePie doesn't override by the way).
Extending Pie with ApplePie and extending Pie.Slice with ApplePie.Slice doesn't change this. The new Slice(startAngle) in the above code does not magically switch to instantiating something different.
Aside from that, your Pie.toString() isn't returning anything - it shouldn't even compile:
#Override
public String toString(){
for (Slice s:slices){
s.toString();
}
}
I'm guessing you want to return a String representing all the slices. This would be a quick solution for example:
#Override
public String toString() {
return Arrays.toString(slices);
}
(Arrays.toString is just a utility method to get a String representing of an array.)
The answer lies within your program. When you instantiate Slice class, it gives call to the super class and invokes sliceGenerator. This method internally creates instances of Pie.Slice and not ApplePie.Slice. To get around this, make sliceGenerator method protected and override it in Apple.Slice class. Create the instances of Apple.Slice and it should work.

Categories