In Java, can 1 instance variable have 2 potential values? - java

I have been instructed to "Write a class, Triangle, with one instance variable that takes two string values, (filled or not filled)".
I'm new to Java, and still haven't come across a situation where you could have two potential values for one instance variable.
How would I do this?
main method was given:
public static void main(String[] args)
{
TwoDPolygon polygons[] = new TwoDPolygon[3];
polygons[0] = new Triangle("filled", 8.5, 12.0);
polygons[1] = new Triangle("not Filled", 6.5, 7.5);
polygons[2] = new Triangle(7.0);
for (int i=0; i<polygons.length; i++)
{
System.out.println("Object is " + polygons[i].getName());
System.out.println("Triangle " + polygons[i].getStatus());
System.out.println("Area is " + polygons[i].area());
}
}

Ok I have redesigned the code based on your updated question.
First of all, you need an abstract class called TwoDPolygon. This class is an abstract representation of all your polygons. It contains the constructors and the methods you need.
abstract class TwoDPolygon {
protected String filled;
protected double x;
protected double y;
protected TwoDPolygon(String filled, double x, double y){
this.filled=filled;
this.x=x;
this.y=y;
}
protected TwoDPolygon(double x, double y){
this.x=x;
this.y=y;
}
protected TwoDPolygon(double y){
this.y=y;
}
abstract String getName();
abstract String getStatus();
abstract Double area();
}
Then the next step is to create the Triangle class. You will have to extend the abstract TwoDPolygon. This is the code:
public class Triangle extends TwoDPolygon {
//the first constructor
public Triangle(String filled, double x, double y) {
super(filled, x, y);
}
//the second one
public Triangle(double x, double y){
super(x,y);
}
//the third one
public Triangle(double y){
super(y);
}
public String getName() {
return "Triangle";
}
public String getStatus() {
return filled;
}
public Double area() {
//Insert code here which calculates the area
return 0.0;
}
}
This is all. Every time when you instantiate a Triangle polygon it will chose the right constructor based on the parameters you supply. Now when you run your main you will have the following output:
Object is Triangle
Triangle filled
Area is 0.0
Object is Triangle
Triangle not Filled
Area is 0.0
Object is Triangle
Triangle null
Area is 0.0
Note: The area's code is not done. You will have to do that but I guess that shouldn't be a problem.
Also I have created three constructors as you said, but I don't know the parameters of the third one. I just guessed that it has only the x and y value.
I hope this is what you're looking for!! It shouldn't be that hard to adapt to your specific requirements, as I think it looks almost done.

It is most likely meant that it takes one argument with 2 valid values:
class Triangle {
Triangle(String val) {
if (!"filled".equals(val) || !"not filled".equals(val))
throw ...;
}
}
or enum type
public enum Type {
FILLED,
NOT)FILLED
}

I think what is meant is you have one boolean instance variable named isFilled.
then you could have something like this:
boolean isFilled;
public triangle(String filled, int x, int y) {
if (filled == "filled") {
isFilled = true;
} else if (filled == "notFilled") {
isFilled = false;
} else {
//handle exception or whatever
}
}
That way you can have one instance variable but still use a string in the constructor. I don't think this is a very practical thing to do but if that is what your assignment said then that is a good way to do it. I hope I helped!

Related

Having trouble with passing user defined parameters inside my object

I'm being asked to pass more arguments to match my constructor but I have no idea what to pass into them.
I have multiple instance variables but only a few of them will be defined by the user (the vertices) and the others are going to defined with their respective methods. If I take everything except my vertices outside of my constructor to solve the error I am left with my final output being left as 0 for most of my reports.
Is my constructor the problem or the parameters in my object at fault?
import java.lang.Math;
public class Triangle {
//instance variables
private double VertAx, VertAy, VertBx, VertBy, VertCx, VertCy;
private double lengthAB, lengthBC, lengthCA;
private double Perimeter, Area;
private double H = Perimeter/2;
//Triangle Constructor
public Triangle(double userVertAx, double userVertAy, double userVertBx, double userVertBy, double userVertCx, double userVertCy, double userlengthAB, double userlengthBC, double userlengthCA, double userPerimeter, double userArea, double userH) {
userVertAx = this.VertAx;
userVertAy = this.VertAy;
userVertBx = this.VertBx;
userVertBy = this.VertBy;
userVertCx = this.VertCx;
userVertCy = this.VertCy;
userlengthAB = this.lengthAB;
userlengthBC = this.lengthBC;
userlengthCA = this.lengthCA;
userPerimeter = this.Perimeter;
userArea = this.Area;
userH = this.H;
}
public double lengthAB(double userVertAx, double userVertAy, double userVertBx, double userVertBy) {
return lengthAB = Math.sqrt( (Math.pow((userVertBx - userVertAx), 2)) + (Math.pow((userVertBy - userVertAy), 2)));
}
public double lengthBC(double userVertBx, double userVertBy, double userVertCx, double userVertCy) {
return lengthBC = Math.sqrt( (Math.pow((userVertCx - userVertBx), 2)) + (Math.pow((userVertCy - userVertBy), 2)));
}
public double lengthCA(double userVertCx, double userVertCy, double userVertAx, double userVertAy) {
return lengthCA = Math.sqrt( (Math.pow((userVertAx - userVertCx), 2)) + (Math.pow((userVertAy - userVertCy), 2)));
}
public void setPerimeter(double userlengthAB, double userlengthBC, double userlengthCA) {
Perimeter = userlengthAB + userlengthBC + userlengthCA;
}
public double getPerimeter() {
return Perimeter;
}
public void setArea(double userlengthAB, double userlengthBC, double userlengthCA, double userH) {
Area = Math.sqrt(userH*(userH-userlengthAB)*(userH-userlengthBC)*(userH-userlengthCA));
}
public double getArea() {
double Area = getArea();
return Area;
}
public String toString() {
return String.format("Vertices: A(%f, %f) B(%f, %f) C(%f, %f)\nSide Lengths: AB=%f BC=%f CA=%f\nPerimeter: %f\nArea: %f", VertAx, VertAy, VertBx, VertBy, VertCx, VertCy, lengthAB, lengthBC, lengthCA, Perimeter, Area);
}
}
public class TriangleTest {
public static void main(String[] args) {
#SuppressWarnings("resource")
Scanner Vertices = new Scanner(System.in);
System.out.println("Welcome to the Triangle Test enter each coordinate of your three vertices SEPERATELY");
System.out.println("Enter Vertex A X");
Double VAX = Vertices.nextDouble();
System.out.println("Enter Vertex A Y");
Double VAY = Vertices.nextDouble();
System.out.println("Enter Vertex B X");
Double VBX = Vertices.nextDouble();
System.out.println("Enter Vertex B Y");
Double VBY = Vertices.nextDouble();
System.out.println("Enter Vertex C X");
Double VCX = Vertices.nextDouble();
System.out.println("Enter Vertex C Y");
Double VCY = Vertices.nextDouble();
//ERROR
Triangle UserTriangle = new Triangle(VAX, VAY, VBX, VBY, VCX, VCY);
//ERROR ^
UserTriangle.lengthAB(VAX, VAY, VBX, VBY);
UserTriangle.lengthBC(VBX, VBY, VCX, VCY);
UserTriangle.lengthCA(VCX, VCY, VAX, VAY);
UserTriangle.getPerimeter();
UserTriangle.getArea();
System.out.println(UserTriangle.toString());
}
}
I am expecting some way to pass the right parameters into my UserTriangle but I am confused as to how. Thank you for any help anyone can provide. My understanding with classes and objects were good with implementing user input but this one seems so tricky to me considering some of the variables are defined in methods and some are defined by the user.
Constructor called with a mismatched number of arguments
You defined your constructor as accepting 12 arguments, but then you called it with only 6 arguments. This is the error you're referring to. To solve this you have 3 options
Provide all the 12 arguments the constructor needs
Define your constructor as receiving 6 arguments
Refactor (see below for instructions), which is the way to go in my opinion
Reverse the initialization statements in your constructor
To initialize your attributes write this.VertAx = userVertAx instead of userVertAx = this.VertAx; (reverse the statement basically)
This goes for all the other attributes too (userlengthAB, userPerimeter, etc...)
Note
It's better to use the Java naming conventions so you can make the difference say between attributes and classes. Attributes and variables should start with a lowercase and classes with an uppercase.
Edit: Refactoring suggestion
An even better writing is to use less arguments in your constructor. Having too many arguments is considered a code smell and will make your code less readable/maintainable, etc...
To handle that you can encapsulate some concepts in classes. For example you can have
public class Vertex {
private double x;
private double y;
public Vertex(double x, double y) {
this.x = x;
this.y = y;
}
public class TriangleVertices {
private vertexA;
private vertexB;
private vertexC;
public TriangleVertices (Vertex a, Vertex b, Vertex c) {
vertexA = a;
vertexB = b;
vertexC = c;
}
}
public class Triangle {
private TriangleVertices vertices;
// other attributes
// You have now 5 arguments less!
public Triangle(TriangleVertices vertices, // other attributes) {
this.vertices = vertices;
// Initialize other attributes
}
}
Here "this" is a keyword which points the constructor to the variables that are declared in the created class (in your case created class is Triangle). we use "this" keyword when
the variable of parameter has the same name as the variable declared in the created class.For example;
class A {
int NewVar;
A (double NewVar){
this.NewVar = NewVar; //here this.NewVar is pointing to NewVar of type int
}
}
Change this in your code. This might solve your problem.
public Triangle(double userVertAx, double userVertAy, double userVertBx, double userVertBy, double userVertCx, double userVertCy, double userlengthAB, double userlengthBC, double userlengthCA, double userPerimeter, double userArea, double userH) {
this.VertAx = userVertAx;
this.VertAy = userVertAy;
this.VertBx = userVertBx;
this.VertBy = userVertBy;
this.VertCx = userVertCx;
this.VertCy = userVertCy;
this.lengthAB = userlengthAB;
this.lengthBC = userlengthBC;
this.lengthCA = userlengthCA ;
this.Perimeter = userPerimeter ;
this.Area = userArea;
this.H = userH ;
}

Parameters and arguments from one class to another in java

I'm half way through an assignment in java where I have two classes and need to calculate a x- and y-position. I get half of the tests correct but can't seem to get the two last ones correct. Could you perhaps guide my in the right direction?
I have one class calle Point and one PointMain. I get the arguments in PointMain and need to create the right methods in Point. I can't make any changes in the class PointMain as I got that from the assignment.
Class Point:
public class Point {
private int x = 0;
private int y = 0;
public Point() {
}
public Point(int xPoint, int yPoint) {
x = xPoint;
y = yPoint;
}
public String toString() {
return x + "," + y;
}
public double distanceTo(Point p2) {
double avstand = Math.sqrt(((p2.x*1 - p2.x*2) * (p2.x*1 - p2.x*2)) + ((p2.y*1 - p2.y*2) * (p2.y*1 - p2.y*2)));
return avstand;
}
public void move(int iPoint, int jPoint) {
x = x + iPoint; // I have a problem with this that it doesn't add
y = y + jPoint; // the 3,4 that I got from p2 with the 5,-2.
}
public void moveToXY(int xTag, int yTag) {
}
public boolean isEqualTo(Point p2) { //And I'm not really sure on how to
return false; //construct this method either...
}
}
Class PointMain:
public class PointMain {
public static void main(String[] args) {
Point p1 = new Point();
Point p2 = new Point(3,4);
System.out.println(p1.toString()); // ==> (0,0)
System.out.println(p2.toString()); // ==> (3,4)
if (p1.isEqualTo(p2)) // False!
System.out.println("The two points are equal");
double dist = p1.distanceTo(p2);
System.out.println("Point Distance: "+dist);
p2.move(5,-2); // ==> (8,2)
p1.moveToXY(8,2); // ==> (8,2)
System.out.println(p1);
System.out.println(p2);
if (p1.isEqualTo(p2)) // True!
System.out.println("The two points are equal");
}
}
First of all you should add getters
public int getX()
{
return x;
}
public int getY()
{
return y;
}
Than implement isEqual
public boolean isEqualTo(Point p2) {
return x == p2.getX() && y == p2.getY();
}
you can also declare x and y public and then there is no need for getters and code is simpler as you can see in implementation of java.awt.Point.
I don't see problem with "move" function.
And last
public void moveToXY(int xTag, int yTag) {
x = xTag;
y = yTag;
}
For additional info you can lookup how java.awt.Point implemented, and work on your function parameters naming iPoint/jPoint is horrible names
For the equality method, think that in which condition the two points are equal. Consider using if for validating the condition and getters for getting the points x and y.
And I don't see any problem with the move method.
And as #Juniar said in the comments, there's another problem in your distanceTo method. You want to get x and y of p2 but they are private variables so you can't have them by this way. In this case your are having the x and y of the object which the method is called on. So the output won't be desirable. (see getters again)

Comparing and validating objects

I have a setter that has two parameters like so
public void setStuff(OBJECT x, OBJECT, y)
If the value of the x is greater than the y I want to set the value of x to BLAH_BLAH and y to FINAL_THING. How would I do this since they are objects and all I know is to check if they are equal. with the equals method.
For comparing objects I would suggest you to override equals method and in equals compare on the variable
This is a simple class CompareObject
public class CompareObjects {
public int age;
public static void main(String args[])
{
CompareObjects co=new CompareObjects();
co.age=10;
CompareObjects co1=new CompareObjects();
co1.age=100;
System.out.println(co.equals(co1));
}
public boolean equals(CompareObjects co)
{
if(this.age>co.age)
return true;
else return false;
}
}
output false
Now you know which object is greater than which object.
Now you use this method in your public void setStuff(OBJECT x, OBJECT, y)
For example
public void setStuff(OBJECT x, OBJECT, y)
{
if(x.equals(y)
{
//do something
}
else
{
//do something
}
}
If you know how to get the values of x and the value of y, then do this:
pseudo java:
if (getValue of x > getValue of y),
x.setValue = xyz,
y.setValue = abc.

Java generics - accept float and int

How can I program my class to accept both Integers and Floats, I suppose I'll need to use generics, am I correct?
public class Vec2 {
private int x, y;
public Vec2(int xa, int ya) {
this.x = xa;
this.y = ya;
}
public Vec2() {
this(0, 0);
}
public Vec2(Vec2 vec) {
this(vec.x, vec.y);
}
public void addX(int xa) {
x+=xa; // I get an exception here when I try to use generics.
}
public void addY(int ya) {
y+=ya; // I get an exception here when I try to use generics.
}
Any ideas how to program my class to accept floats, integers and doubles altogether?
For the time being, we cannot have generics over primitives like int or double, so you will be forced to use boxed representations. It really is easier to just make a separate class for int and double. But if you want to use generics, here's how you can do it in a type-safe way (using java8):
public class Vec2<T> {
private final BinaryOperator<T> adder;
private T x, y;
private Vec2(BinaryOperator<T> adder, T x, T y) {
this.adder = adder;
this.x = x;
this.y = y;
}
public void addX(T xa) {
x = adder.apply(x, xa);
}
public void addY(T ya) {
y = adder.apply(y, ya);
}
public static Vec2<Integer> ofInt(Integer x, Integer y) {
return new Vec2<>(Integer::sum, x, y);
}
public static Vec2<Double> ofDouble(Double x, Double y) {
return new Vec2<>(Double::sum, x, y);
}
}
Vec2<Integer> intvec = Vec2.ofInt(5, 3);
intvec.addX(8);
Vec2<Double> dblvec = Vec2.ofDouble(5.2, 8.9);
dblvec.addY(-.9);
You could use BigDecimal to back your Vec2 and then you could use create addX and addY method(s) for long and double fairly easily. Something like,
public class Vec2 {
private BigDecimal x, y;
public Vec2(double xa, double ya) {
this.x = BigDecimal.valueOf(xa);
this.y = BigDecimal.valueOf(ya);
}
public Vec2(long xa, long ya) {
this.x = BigDecimal.valueOf(xa);
this.y = BigDecimal.valueOf(ya);
}
public Vec2(Vec2 vec) {
this.x = vec.x;
this.y = vec.y;
}
public void addX(double xa) {
x = x.add(BigDecimal.valueOf(xa));
}
public void addX(long xa) {
x = x.add(BigDecimal.valueOf(xa));
}
public void addY(double ya) {
y = y.add(BigDecimal.valueOf(ya));
}
public void addY(long ya) {
y = y.add(BigDecimal.valueOf(ya));
}
#Override
public String toString() {
return String.format("x = %s, y = %s", x.toString(), y.toString());
}
}
No, you don't, merely have your class inherit from Number and use type checking to ensure that values are of the appropriate class, if necessary, e.g.
Class IsraelG99sClass {
Number n;
public Number add(Number n2) {
if (n instanceof Integer && n2 instanceof Integer) {
return new Integer(n.intValue() + n2.intValue());
} else {
return new Double(n.doubleValue() + n2.doubleValue());
}
}
public Number getValue() {
if ((n instanceof Integer) || (n instanceof Float)) {
return n;
} // handle the other case as appropriate
}
}
Floats and ints are very different values with vastly different mins and maxes. I would try using doubles as the data member with overloaded constructors for different variable types instead of generics unless generics are really needed.
Yes, you can use generics and make your x and y attributes of type T.
But you won't be able to just implement the addX and addY in they way you want.
Check these other answers on how to implement a generic number addition, it's not as simple but you should be able to do it that way.
Java Generics and adding numbers together
how to write a generic method for adding numbers
First of all, I'm operating under the assumption that you want x and y to be of varying (generic) type.
For this, you would want:
public class Vec2<E extends Number> {
private E x, y;
public Vec2(E xa, E ya) {
this.x = xa;
this.y = ya;
}
//Not _easily_ possible with generics, as the compiler has no guarantee that
//zero is an acceptable value. Consider some variation of a Factory pattern,
//but this will work. Note that there is an "officially"-unchecked cast warning.
public Vec2() {
super();
final Number zero = 0.0;
this.x = (E)zero;
this.y = (E)zero;
}
public Vec2(Vec2<E> vec) {
this(vec.x, vec.y);
}
public void addX(E xa) {
Number c = x.doubleValue() + xa.doubleValue();
x = (E)c;
}
public void addY(E ya) {
Number c = y.doubleValue() + ya.doubleValue();
x = (E)c;
}
This should work well. While I encourage you to use generics, note that keeping a numeric type (like int, float, or double) as a generic is often not advisable, as they're only similar on the surface. When you dig into the operations of, say, "+", they are radically different dependent on type. You will also have an assortment of unchecked-cast warnings in this code; perhaps I could have rooted them out properly had I the time, but this just goes back to my warning about generic numbers.
You will also notice a few flukes of the language doing this, such as the way that (E)zero works, but (E)(0.0) does not.
By and large, though, generics are a much easier and cleaner way to go about things than inheritance, when it is possible.

HashMap adding all items even when duplicate

I have been trying without any luck to make a list of all points in a model. When i execute this
HashList<Point> points=new HashList<Point>(16);
//add +y side
points.add(new Point(-5.0,5.0,-5.0));
points.add(new Point(-5.0,5.0,5.0));
points.add(new Point(5.0,5.0,5.0));
points.add(new Point(-5.0,5.0,-5.0));
points.add(new Point(5.0,5.0,5.0));
points.add(new Point(5.0,5.0,-5.0));
//add -x side
points.add(new Point(-5.0,5.0,-5.0));
points.add(new Point(-5.0,-5.0,-5.0));
points.add(new Point(-5.0,-5.0,5.0));
points.add(new Point(-5.0,5.0,-5.0));
points.add(new Point(-5.0,-5.0,5.0));
points.add(new Point(-5.0,5.0,5.0));
int length=points.length(); //equals 12, 6 expected
Point a=new Point(-5.0,5.0,-5.0);
Point b=new Point(-5.0,5.0,-5.0);
int aHashCode=a.hashCode(); //-737148544
int bHashCode=b.hashCode(); //-737148544
boolean equals=a.equals(b); //true
points containts 12 points which is the number I started with. I want all duplicates found which should result in only 6 points in table.
if (map.containsKey(e)) {
in HashList for some reason never gets executed. Any ideas?
HashList:
package dataTypes;
import java.util.ArrayList;
import java.util.HashMap;
public class HashList<E> {
private HashMap<E,Integer> map;
private ArrayList<E> data;
private int count=0;
public HashList() {
map=new HashMap<E,Integer>();
data=new ArrayList<E>();
}
public HashList(int size) {
map=new HashMap<E,Integer>(size);
data=new ArrayList<E>(size);
}
public int add(E e) { //returns key
if (map.containsKey(e)) {
return map.get(e);
} else {
map.put(e, count);
data.add(count,e);
return count++;
}
}
public int getKey(E e) {
return map.get(e);
}
public E get(int key) {
return data.get(key);
}
public int length() {
return count;
}
}
Point:
package geometry3D;
/**
* 3D point location or vector
*
* #author Matthew Cornelisse
* #version 2014-09-02-004500
*/
public class Point
{
// instance variables - replace the example below with your own
public double x;
public double y;
public double z;
/**
* Constructor for objects of class Point
*/
public Point()
{
// initialise instance variables
x = 0;
y = 0;
z = 0;
}
public Point(double x, double y, double z)
{
this.x=x;
this.y=y;
this.z=z;
}
public Point(Point a) {
x=a.x;
y=a.y;
z=a.z;
}
/**
* Normailizes the point to have distance from center of 1
*
*/
public void normalize()
{
// put your code here
double length=Math.sqrt(x*x+y*y+z*z);
x/=length;
y/=length;
z/=length;
}
//implements Shape
public void rotateX(double angle){
double newY=Math.cos(angle)*y-Math.sin(angle)*z;
double newZ=Math.sin(angle)*y+Math.cos(angle)*z;
y=newY;
z=newZ;
}
public void rotateY(double angle){
double newX=Math.cos(angle)*x-Math.sin(angle)*z;
double newZ=Math.sin(angle)*x+Math.cos(angle)*z;
x=newX;
z=newZ;
}
public void rotateZ(double angle){
double newX=Math.cos(angle)*x-Math.sin(angle)*y;
double newY=Math.sin(angle)*x+Math.cos(angle)*y;
x=newX;
y=newY;
}
public void rotate(Vector axis, double angle){
//source: http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation/
double oldX=x;
double oldY=y;
double oldZ=z;
double sinA=Math.sin(angle);
double cosA=Math.cos(angle);
Point offset=axis.offset();
Point vector=axis.vector();
double u=vector.x;
double v=vector.y;
double w=vector.z;
double a=offset.x;
double b=offset.y;
double c=offset.z;
x=(a*(v*v+w*w)-u*(b*v+c*w-u*oldX-v*oldY-w*oldZ))*(1-cosA)+oldX*cosA+(-c*v+b*w-w*oldY+v*oldZ)*sinA;
y=(b*(u*u+w*w)-v*(a*u+c*w-u*oldX-v*oldY-w*oldZ))*(1-cosA)+oldY*cosA+(c*u-a*w+w*oldX-u*oldZ)*sinA;
z=(c*(u*u+v*v)-w*(a*u+b*v-u*oldX-v*oldY-w*oldZ))*(1-cosA)+oldZ*cosA+(-b*u+a*v-v*oldX+u*oldY)*sinA;
}
public void move(double x, double y, double z){
this.x+=x;
this.y+=y;
this.z+=z;
}
public void move(Vector direction,double magnitude){
this.x+=(direction.vector().x*magnitude);
this.y+=(direction.vector().y*magnitude);
this.z+=(direction.vector().z*magnitude);
}
public boolean equals(Point compare) {
if (Math.abs(compare.x-x)>5*Math.ulp(compare.x)) return false;
if (Math.abs(compare.y-y)>5*Math.ulp(compare.y)) return false;
if (Math.abs(compare.z-z)>5*Math.ulp(compare.z)) return false;
return true;
}
public boolean equals(Point compare, double error) {
if (Math.abs(compare.x-x)>error) return false;
if (Math.abs(compare.y-y)>error) return false;
if (Math.abs(compare.z-z)>error) return false;
return true;
}
public int hashCode(){
Double a=(Double)x;
Double b=(Double)y;
Double c=(Double)z;
return a.hashCode()^Integer.rotateRight(b.hashCode(),12)^Integer.rotateRight(c.hashCode(),24);
}
public boolean equals(Object compare) {
try {
Point temp=(Point)compare;
if (temp.x!=x) return false;
if (temp.y!=y) return false;
if (temp.z!=z) return false;
return true;
} finally {
return false;
}
}
}
As noticed by rolfl, it is no use to try to use java equals method to compare Points with an acceptable error (see TL/DR section below if you are in doubt).
So, you have to do it the hard way. Do not even imagine to use map.containsKey(e), but create an explicit method in HashList. I would begin by that interface :
public interface DistEquality<E> {
boolean distEquals(E compare);
}
Then declare Point to implement it :
public class Point implements DistEquality<Point> {
...
public static double defaultError = 10E-3;
#Override
public boolean distEquals(Point compare) {
return equals(compare, defaultError);
}
}
And modify HashList that way
public class HashList<E extends DistEquality<E>> {
...
public int distValue(E e) {
for (Entry<E, Integer> entry: map.entrySet()) {
if (e.distEquals(entry.getKey())) {
return entry.getValue();
}
}
return -1;
}
public int add(E e) { //returns key
int pos = distValue(e);
if (pos != -1) {
return pos;
} else {
map.put(e, count);
data.add(count,e);
return count++;
}
}
...
}
I have not tested anything, but I think the general idea should be Ok.
TL/DR
Below solution is plain wrong - (thanks to rolfl to noticing)
The equals method in class Point requires exact equality of doubles. You should instead have a static double defaultError in Point class, initialized at an appropriate value and then do :
public boolean equals(Object compare) {
return ((compare instanceof Point) ? equals(compare, defaultError) : false);
}
But as noticed by rolfl, this is not enough, because javadoc for Object.hashCode() states If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It would be very hard to imagine an intelligent hash compatible with the above equality method. Worse, once one point gets a hashCode value, any other point is at a finite number of defaultError and you can imagine a finished suite of Points that are all 2 per 2 equals and so hashCode should be a constant.
Worse, as equals is required to be reflexive, symetric and transitive, all Points should be equal.
It looks that the idea of using equal that way is really a bad idea :-(
The problem is your finally block in equals(Object). It's always returning false, even if you're returning true from the try block.
You're getting confused because of this:
boolean equals=a.equals(b); //true
... but that's not calling the same equals method - it's calling equals(Point).
Your equals(Object) method should be written as:
#Override public boolean equals(Object compare) {
if (compare == this) {
return true;
}
if (compare == null || compare.getClass() != getClass()) {
return false;
}
Point temp = (Point) compare; // Guaranteed to work now
return temp.x == x && temp.y == y && temp.z == z;
}
Note that:
As noted elsewhere, you can't come up with an equality/hash which handles tolerance... if you do any significant arithmetic with these points, you're unlikely to have exact equality any more
Your class has public fields, which is pretty much always a bad idea
Your class is mutable, which is a bad idea from the point of view of code using the hash code - collections are much easier to use correctly when the element type is immutable
If you make your class final, you can use instanceof instead of the getClass() check - and again, that would help prevent someone introducing a mutable subclass. (Equality relationships across an inheritance hierarchy are generally painful anyway.)
The HashList implementation is incorrect if you want it to be able to contain duplicates. On your add, if the map already has the key, you just return the value..., so your duplicates will never get inserted.
If you are getting duplicates, that means that your Equals/HashCode for Point is likely screwed up.
Right now, your HashList doesnt actually allow duplicates, so you might as well just get rid of it and use a HashSet from java collections. Also, get a decent java IDE like netbeans, eclipse, IntellIJ and have it generate the equals/hashcode for you on your point class.

Categories