Generics comparing objects in an ArrayList - java

I'm trying to create a generic class that compares objects in an array list and returns the largest. My issue is that I'm not quite sure I understand completely how generics work.
Measurable:
import java.util.ArrayList;
/**
Describes any class whose objects can be measured.
*/
public abstract class Measurable<T>{
abstract double getMeasure();
public static <T extends Measurable<T>> T getLargest(ArrayList<T> objects){
T largest = objects.get(0);
for(int i = 0; i < objects.size(); i ++){
if(largest.getMeasure() == objects.get(i).getMeasure()){
largest = objects.get(i);
}
}
return largest;
}
}
Box:
import java.awt.Rectangle;
import java.util.ArrayList;
public class Box extends Measurable {
private Rectangle box;
private static ArrayList<Rectangle> rectangles;
public Box(){
box = new Rectangle();
rectangles = new ArrayList<Rectangle>();
}
public ArrayList<Rectangle> create(){
for(int i = 0; i < 10; i++){
box = new Rectangle((int) Math.random(), (int) Math.random());
rectangles.add(box);
}
return rectangles;
}
#Override
public double getMeasure() {
double area = 0;
for(int i = 0; i < rectangles.size(); i++){
area = rectangles.get(i).getWidth()*rectangles.get(i).getHeight();
}
return area;
}
public static void main(String[] args){
Box b = new Box();
b.getLargest(b.create());
}
}
I'm coming across an issue where it says "The method getLargest(ArrayList) in the type Measurable is not applicable for the arguments (ArrayList)" but shouldn't I be able to use any object for the getLargest class?

As you wrote it, getLargest expects the objects passed to it in the List to implement Measurable, but java.awt.Rectangle does not.
When you write
public static <T extends Measurable<T>> T getLargest(ArrayList<T> objects){
that declares a T that is different, but named the same, as the T in the Measurable class as a whole, which is likely to lead to total confusion.
If you actually replace T with Rectangle in your code, you can see that you're trying to call Rectangle.getMeasure(), which is a method that does not exist.

I am not really sure where generics come into play here. It seems like you want to make a bunch of shapes that are derived from a base class Measurable. You also want the abstract class to hold some code for working with Measurable subclasses. Basically you need to make a subclass that implements Measurable. I think what you want a Box class like the one below.
public class Box extends Measurable {
private double width;
private double height;
public Box(double width, double height){
this.width = width;
this.height = height;
}
public double getMeasure() {
double area = width*height;
return area;
}
}

Related

How I can implements method from one class in another class

I have class Shape2D, in that class I have method that calculate circle area circleArea, also I have class CircleArea where I store all atributes that I need for my method. Also, my class CircleArea extends class Shape2D. So, How I can implement my method from class Shape2D into class CircleArea.
This is my Shape2D class:
public class Shape2D {
public static void areaCircle(Circle c) {
double circleArea = Math.pow(c.getR(), 2) * Math.PI;
}
}
And this is my Circle class:
public class Circle extends Shape2D {
private double r;
public Circle() {
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
}
To implement one of the methods from the Shape2D class in the Circle class, you could do:
Shape2D.areaCircle(circleObject);
The above line can be called in the Circle class. Don't forget to pass in an actual circle object into the function.
You have a static method inside of 2D shape, meaning you can use it in any class without having 2DShape instantiated. This also means that you do not need the circle class to extend 2DShape to use this method, but I imagine you are going for that parent child relationship for the OO paradigm. If you don't want the method to be called from any class, remove static from the method. If you wish to call it statically inside of your Circle class constructor, first instantiate r to something, and then pass it into the static method call.
public class Circle extends Shape2D {
private double r;
public Circle() {
r=1;
Shape2D.areaCircle(this);
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
}
Note that your static function doesn't actually return anything, so it calculates the area and the value is lost. You can fix this inside of shape2D by changing the return type of circleArea to double in stead of void, and returning the result appropriately.
public static double areaCircle(Circle c) {
double circleArea = Math.pow(c.getR(), 2) * Math.PI;
return circleArea;
}
or non-statically, and protected in stead of public (either will work)
protected double areaCircle(Circle c) {
double circleArea = Math.pow(c.getR(), 2) * Math.PI;
return cricleArea;
}
If you wanted to do the same thing, but removed the static flag from the method, then you can use super to call parent methods.
public class Circle extends Shape2D {
private double r;
public Circle() {
r=1;
super.areaCircle(this);
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
}
Now if you wanted to actually store the area inside of this circleObject, I would create another attribute for the Circle class, and modify your constructor as such. Perhaps even adding a constructor that takes an int argument for radius (or in the future, an area with some way to differentiate the two that can get the radius value).
public class Circle extends Shape2D {
private double r;
private double area;
//Default Constructor
public Circle() {
r=1;
this.area = super.areaCircle(this);
}
//Radius constructor
public Circle(double rad) {
this.r = rad;
this.area = super.areaCircle(this);
}
public double getR() {
return r;
}
public void setR(double r) {
this.r = r;
}
}
It's also worth mentioning that you should look at the scope of these methods you create, and what you are trying to accomplish with them. For instance, you have your circleArea method defined as public, when it could be defined as protected and function similarly for this case. Protected means that the method can be used inside of the class, as well as all subclasses (children of the parent class, like circle). You can read information about these closures here. Also, when working with object inheritance, you should get into the habit of using the this keyword to reference which methods/attributes you actually wish to retrieve. Info on this keyword.
I realize this is a lot to take in, but if you have any questions feel free to comment!

Inheritance in Java with array

I have a problem when I use inheritance and define an object of parent class then call the constructor from the child class which has its own properties. When i want to assign values to the child class using sets methods its gives me an error (cannot find symbol)
this is my code
public class Shape {
private final double PI =3.14;
public Shape() {
}
public double getPI() {
return PI;
}
}
public class Rectangle extends Shape {
private double length;
private double width;
public Rectangle() {
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
}
public class Circle extends Shape{
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
}
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
Shape s[] = new Shape[3];
int type;
for (int i = 0; i < s.length; i++) {
System.out.println("Enter the Shape:\n 1.Rectangle \n 2.Circle");
type = in.nextInt();
if(type==1){
s[i] = new Rectangle();
s[i].setLength(5.5);
}
}
}
Your problem lies here:
s[i] = new Rectangle();
s[i].setLength(5.5);
Yes. You know that this form is an instance of Rectangle, all the JVM knows is that it's a Shape. If you want to use it as a Rectangle, you have to declare it as one:
Rectangle r = new Rectangle();
r.setLength(5.5);
s[i] = r;
EDIT: The reason for this is, when you declare an instance as a Shape (parent class), the JVM will consider it to be this, even if your code suggests (to a human reader) that a specific type will be used, the JVM will not make any assumptions on which sub class will be instantiated.
You are limited to the possibilities of the class you declared it to be.
Since you now again save it as a Shape, in your array, if later on you'll want to get that value, you'll need to cast it.
Rectangle rNew = (Rectangle)s[index]; // of course after checking whether it is in fact a Rectangle
you setLength() method is present in your sub class Rectangle while s[i] points to an instance of type Shape which is a super class. thus, it doesn't recognize the instance method due to implicit upcasting.
you will have to explicitly downcast you object s[i] from shape to Rectangle.
This is how you can do it:
Rectangle r = (Rectangle)s[i];
r.setLength(5.5);
NOTE: Ofcourse the above statements gos after s[i] = new Rectangle();
an ideal way though (as explained by #Stultuske):
Rectangle r = new Rectangle();
r.setLength(5.5);
s[i] = r;

Error compiling interface implementation

I get an error for: a.getLargest(a.create());
in the main method. It says that
I have to implement the method in Geo
public abstract class Measurable<T> {
abstract double getMeasure();
public static <T extends Measurable<T>> T getLargest(ArrayList<T> objects){
T largest = objects.get(0);
for(int i = 0; i < objects.size(); i ++){
if(largest.getMeasure() == objects.get(i).getMeasure()){
largest = objects.get(i);
}
}
return largest;
}
}
And in a separate file:
import java.util.ArrayList;
import java.util.Collection;
public class Test extends Measurable {
private Geo test;
private static ArrayList<Geo> object;
public Test(){
test = new Geo();
object = new ArrayList<Geo>();
}
public double getMeasure() {
double size = 0;
for(int i = 0; i < object.size(); i++){
size = object.get(i).getArea()*object.get(i).getPerimeter();
}
return size;
}
public ArrayList<Geo> create(){
for(int i = 0; i < 10; i++){
test = new Geo(i, i);
object.add(test);
}
return object;
}
public static void main(String[] args){
Test a = new Test();
a.getLargest(a.create());
}
}
And thats the GeoClass
public class GeometricObject extends Measurable<GeometricObject>{
It seems that you don't understand what is meant by "implementing" an interface. Your Test class implements Measurable in a non-generic way. So actually you are implementing Measurable<Object>. So far so good, but then you created a Geo object. In your question, you did not show that Geo implements Measurable<Geo>, so I assume it is not. If Geo did not implement Measurable<Geo>, then the call to getLargest would fail because getLargest calls getMeasure which most likely does not exist in Geo. Instead, you should implement Measurable<Geo> in Geo class.
public class Geo implements Measurable<Geo> {
public double getMeasure () {
//some code
}
//other code
}
I guess your confusion here is might be that you think when Test implements an interface, all its members implement it. But that is not true, ok?
And another thing to remember is that when you don't specify a generic type argument, it defaults to Object not the type implementing the interface!

Why does this list have an error?

I am following a tutorial on YouTube, making a Java game.
And I'm getting this error while following it, and I have no idea as to why.
The type List is not generic; it cannot be parameterized with arguments <Enemy>
Here's the list:
private List<Enemy> enemies = new ArrayList<Enemy>();
I have imported java.util.*; and java.awt.*; for List to, theoretically, work.
Here is my Enemy class
import java.awt.*;
public class Enemy extends Entity {
private Rectangle hitbox;
private int movementX, movementY;
private boolean dead = false;
private Main instance;
public Enemy(Main instance, int x, int y) {
super(x, y);
this.instance = instance;
hitbox = new Rectangle(x,y,32,32);
movementX = 0;
movementY = 1;
}
private void move(){
if(instance.getStage().isCollided(hitbox)){
movementY = 0;
dead = true;
}
hitbox.x += movementX;
hitbox.y += movementY;
}
public boolean isDead() { return dead; }
public void draw(Graphics g){
move();
g.setColor(Color.RED);
g.fillRect(hitbox.x, hitbox.y, hitbox.width, hitbox.height);
}
}
You have only imported java.awt.*, which has a different non-generic List. You must fully-qualify your reference to java.util.List because java.awt.List is imported.
private java.util.List<Enemy> enemies = new ArrayList<Enemy>();
Ensure that you have java.util.* imported so ArrayList is resolved also.
By importing java.awt.*, you are also importing java.awt.List. You probably wanted to use java.util.List instead of java.awt.List.
Replace the wildcard import from java.awt with separate import statements for all the classes you need from java.awt, and import java.util.List.
The problem is compiler is trying to treat this List object as java.awt.List not java.util.List. Replace the code with
private java.util.List<Enemy> enemies = new ArrayList<Enemy>();

Should I be using Inner Classes? Example Code inside

I like consolidating my code/classes as much as possible without each class itself getting messy. So I looked into using NestedClasses, though InnerClasses in this case because the InnerClass needs access the OuterClass's members.
Example
Lets say I have a program that calculates various shape attributes to shapes. So given a Rectangle Shape, it would find the Area/Perimeter from inputs of length and width.
I would first create an abstract class Shape, which has abstract methods getArea() and getPerimeter(). I would then create my subclass RectangleShape, extend the shape class, #Override those methods with the necessary logic.
Now there's a shape Rectangular Prism (Cube). It has the same variables/methods as RectangleShape does, but with one extra, height. In the past I would create another subclass of RectangleShape and go from there.
Is it better/not worse to use an InnerClass instead and have an abstract class PrismShape? I ask this because Prisms share the same methods, no matter the shape. If you're at all confused by the above I'm posting code below of what I'm saying.
Example Code
Shape Class
public abstract class Shape {
public abstract double getArea();
public abstract double getPerimeter();
}
PrismShape Class
public abstract class PrismShape{
public abstract double getVolume();
public abstract double getSurfaceArea();
public abstract double getLateralArea();
}
RectangleShape Class
import Abstract.Shape;
import Abstract.ShapePrism;
public class RectangleShape extends Shape{
//Variables Declared
private double _length, _width;
//Constructor
public RectangleShape(double _length, double _width) {
setLength(_length);
setWidth(_width);
}
//Getters and Setters
#Override
public double getArea() {
return getLength() * getWidth();
}
#Override
public double getPerimeter() {
return (2 * getLength())+ (2 * getWidth());
}
public double getLength() {
return _length;
}
private void setLength(double _length) {
this._length = _length;
}
public double getWidth() {
return _width;
}
private void setWidth(double _width) {
this._width = _width;
}
//Inner Class Prism
public class RecPrismShape extends PrismShape{
//Variables Declared
private double _height;
//Constructor
public RecPrismShape(double _height) {
setHeight(_height);
}
//Getters and Setters
#Override
public double getSurfaceArea(){
return (getLateralArea() + (2 * getArea()));
}
#Override
public double getVolume(){
return getArea() * getHeight();
}
#Override
public double getLateralArea(){
return getPerimeter() * getHeight();
}
public double getHeight() {
return _height;
}
private void setHeight(double _height) {
this._height = _height;
}
}
}
I'm open to criticism, still fairly new to Java. My thought process during this was I have 2d Shape attributes and 3d (Prism) shape attributes. The 3d Shapes derive their attributes from 2d shapes, but not visa versa. So for me at least having InnerClasses makes sense.
My own take on this: A public inner class seems most useful when the rest of the program has an object of the outer class, and it wants to create an object of the inner class that "belongs" to the outer class object in some way; that is, it's tightly associated with it.
The way you've arranged things, however, it means that if the client wants to create a RecPrismShape object, it has to first create a RectangleShape object that the prism object will belong to. Most likely, this is not going to be useful. That is, the client creates a RectangleShape rect just because it has to, in order to create a RecPrismShape, and the rect object wouldn't be useful to it in any other way.
I think a better idea would be to have a RecPrismShape object have a private RectangleShape object as one of its fields, but this would be an "implementation detail". That way, you'd get to reuse the RectangleShape code, which it seems like you're trying to do.
public class RecPrismShape extends RectangleShape {
private RectangleShape rect;
private double height;
public RecPrismShape(double length, double width, double height) {
rect = new RectangleShape(length, width);
this.height = height;
}
// and just one example of how you could use it
public double getVolume() {
return rect.getArea() * getHeight();
}
}

Categories