Turning a method implemented in superclass into abstract - java

I have a Java program with the following classes in it
public class A{
protected String name;
...
#Override
public boolean equals(Object obj){
if(!(obj instanceof A)){
return false;
}
A a = (A)(obj);
return a.name.equals(this.name);
}
}
public abstract class B extends A{
#Override
public boolean equals(Object obj){
return equals2(obj);
}
public abstract boolean equals2(Object obj);
}
public class C extends B{
private String data;
...
#Override
public boolean equals2(Object obj){
if(!(obj instanceof C)){
return false;
}
C c = (C)(obj);
if(c.data.equals(this.data)){
return c.name.equals(this.name);
}else{
return false;
}
}
}
Is there a way to force all classes extending class B to implement their own equals methods without having to use equals2 like the example?
Thanks

The only way I can think of is to throw an exception in Bs equals:
public abstract class B extends A {
#Override
public boolean equals(Object obj) {
throw new UnsupportedOperationException();
}
}
This will ensure that sub-classes of B that fail to override equals will not fallback to A's implementation of equals.
Unfortunately, this will result in run-time exceptions, as opposed to compile time errors, which are preferable.

Off the top of my head, you could have the abstract class B throw an exception in its equal() method:
public abstract class B extends A{
#Override
public boolean equals(Object obj){
throw new UnsupportedOperationException("add your own implementation");
}
public abstract boolean equals2(Object obj);
}
Then, anyone subclass of B which attempted to default to the inherited equals method would not work, forcing them to implement their own version.

Related

Java generic method Cannot resolve method 'getX()' in 'T'

Say I have a couple of Objects (=classes) which each has a method getX():
public class A{
/* some code */
public float getX(){}
}
public class B{
/* some code */
public float getX(){}
}
Now I want to write a generic static method as the following:
public static <T> boolean isOverlaps(T obj) {
if (obj == null || (!obj.getClass().isInstance(A.class) && !obj.getClass().isInstance(B.class)))
return false;
return obj.getX() >= 0 && /*some logic*/; // here it falls
}
IDE says:
Cannot resolve method 'getX()' in 'T'
How can I resolve the method properly without casting (since it is a generic method)? Is it even possible?
You need an interface to let Java know that T has the desired function:
public interface I {
float getX();
}
public class A implements I {
/* some code */
public float getX(){
return 1.0f;
}
}
public class B implements I {
/* some code */
public float getX(){
return 2.0f;
}
}
public static <T extends I> boolean isOverlaps(T obj) {
return obj.getX() >= 0 && /*some logic*/;
}
Or, a bit simpler without the unnecessary type variable:
public static boolean isOverlaps(I obj) {
return obj.getX() >= 0 && /*some logic*/;
}
Using an interface is the preferred way to solve this, but the statement "you need an interface" is incorrect.
You can achieve this without an interface too. In some situations (i.e. where you can't modify A or B), this may be the best you can do.
public static boolean isOverlaps(Object obj) {
float x = -1;
if (obj instanceof A) {
x = ((A) obj).getX();
}
else if (obj instanceof B) {
x = ((B) obj).getX();
}
return x >= 0 && /*some logic*/;
}
public static <T> boolean isOverlaps(T obj) {
This isn't really a generic method. OK, it is a generic method, because it has a type variable; it's just not a usefully generic method. You can pass anything to it: it's essentially equivalent to:
public static boolean isOverlaps(Object obj) {
That is, you can't access anything inside that method which isn't a method on Object.
If you want to use this, and you can't use the common interface approach, you could do an instanceof chain:
public static boolean isOverlaps(Object obj) {
if (obj instanceof A) {
return /* logic */;
} else if (obj instanceof B) {
// Do something.
return /* logic */;
}
return false;
}
The problem with this is that you're losing the compile-time safety of not being allowed to pass things other than As and Bs to it (e.g. you could call isOverlaps("Hello world!"), which is presumably nonsensical).
It's actually better to define two overloads:
public static boolean isOverlaps(A obj) { return /* logic */; }
public static boolean isOverlaps(B obj) { return /* logic */; }
because now trying to pass in anything other than an A or a B results in a compile-time error; but it's a compile-time error at the call site, not in these methods.
If /* logic */ depends on some property which can be derived from A and B, e.g. a getter, you can consolidate the repeated logic into a helper:
public static boolean isOverlaps(A obj) { return helper(obj.getX()); }
public static boolean isOverlaps(B obj) { return helper(obj.getX()); }
private static boolean helper(SomeType value) {
return /* logic */
}

Can a method calls it own class?

I'm working on a project where I use Foo which is class that's implemented with an interface, FooExpression, and a separate concrete class called Replacement.
Replacement class uses hashmap:
private Map<Foo, FooExpression> replacementMap;
Replacement class uses put method:
public Expression put(Foo foo, FooExpression exp) {
return replacementMap.put(foo, exp);
}
The Replacement class has a method called get:
public FooExpression get(Foo foo) {
return replacementMap.get(foo);
}
The Foo class has a method, applyReplacement:
#Override
public FooExpression applyReplacement(Replacement r) {
Foo foo = new Foo(name);
FooExpression e = r.get(foo);
return e;
}
The Foo class uses an instance variable:
private String name;
The Foo class uses an equal and hashCode():
#Override
public boolean equals(Object o) {
if (!(o instanceof Foo)) {
return false;
} else {
return name.equals(o);
}
}
#Override
public int hashCode() {
return name.hashCode() + 41;
}
The FooExpression interface uses the applyReplacement method:
FooExpression applyReplacement(Replacement r);
Everytime I used applyReplacement method it returns null, simply because of the "new" instantiation.
I'm just wondering if there's a way to implement the Foo without erasing the existing value from the Replacement class? And I can't use generics for this one.
Your equals() method is wrongly implemented, currently it checks:
if o instanceof Foo
and if name.equals(o)
But o is in this case an instance of Foo. Your name though is an instance of String. This will never return true as a String will never be equal to a Foo.
You have to change your equals method accordingly:
#Override
public boolean equals(Object o) {
if (!(o instanceof Foo)) {
return false;
}
Foo foo = (Foo) o;
return name.equals(foo.name);
}
Which can also be simplified to:
#Override
public boolean equals(Object o) {
return o instanceof Foo && name.equals(((Foo) o).name);
}

Interface segregation principle application

I'm wondering if the Interface segregation principle applys to my codebase.
Here's some example code:
First Class:
public class EntityGroup {
public List<Entity> tests;
//returns true if the EntityGroup is valid
public boolean validate() {
for (Entity test : tests) {
if (!test.validateFieldA() || !test.validateFieldB()) {
return false;
}
}
return true;
}
}
Second Class:
public abstract class Entity {
protected String fieldA;
public abstract boolean validateFieldA();
public abstract boolean validateFieldB();
}
Third Class:
public class EntityChild extends Entity {
private String fieldB;
#Override
public boolean validateFieldA() {
if (fieldA.equals("valid")) {
return true;
} else {
return false;
}
}
#Override
public boolean validateFieldB() {
if (fieldB.equals("valid")) {
return true;
} else {
return false;
}
}
}
Fourth Class:
public class EntityChild2 extends Entity {
#Override
public boolean validateFieldA() {
if (fieldA.equals("valid")) {
return true;
} else {
return false;
}
}
#Override
public boolean validateFieldB() {
return true;
}
}
This is a greatly simplified example from my real codebase but I think it illustrates the problem well. My EntityChild2 class is forced to implement a method it does not need or want to know about.
I know that it would be more correct to have a Interface that would contain the validateFieldB() method and only have EntityChild implement that interface.
With the understanding that this would take a significant amount of effort to refactor into this solution, I'm having a hard time justifying the time it would take to implement this solution in my real code base.
What potential problems will I run into down the line by leaving my code this way?
What benefits will I gain from refactoring my code to have a separate interface for validateFieldB()?
tldr: Why is the Interface Segregation Principle so important?
Wrong Abstraction
You make use of the interface segregation principle but with wrong abstractions.. Your different Entity-types differ only in they behavior.
Because of the shared behavior you have duplicate code in the methods validateFieldA of EntityChild and EntityChild2 . The method validateFieldB looks very similar to validateFieldA just the filed for checking the equality is an other.
You only need one Entity
Strategy Pattern
With the Strategy-Pattern you will have no duplicate code:
class EqualValidationStategy() implements ValidationStategy<T> {
#Override
public boolean check(T a, T b) {
return a.equals(b)
}
}
class TrueValidationStategy() implements ValidationStategy<T> {
#Override
public boolean check(T a, T b) {
return true;
}
}
Entity
public class Entity {
private String fieldA;
private String fieldB;
private ValidationStategy<String> validationForA;
private ValidationStategy<String> validationForB;
// all-args consturctor
#Override
public boolean validateFieldA() {
return validationForA.check(fieldA, "valid");
}
#Override
public boolean validateFieldB() {
return validationForB.check(fieldB, "valid");
}
}
// Validates fieldA and "ignores" fieldB
Entity example = new Entity(fieldA,
fieldB,
new EqualValidationStategy(),
new TrueValidationStategy());

How can I make gson exclude my object's superclass?

Im trying to serialize/deserialize using Gson. I don't want the super class (which is abstract) to be considered, the problem is that I don't have access to the super class code.
I've tried with an ExclusionStrategy but it didn't work.
private class SuperClassExclusionStrategy implements ExclusionStrategy {
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return clazz.equals(SuperClass.class);
}
#Override
public boolean shouldSkipField(FieldAttributes field) {
return false;
}
}
How can I solve this?
Edit:
I need the fields in the superclass to be ignored, this is because I am getting this error: MyClass declares multiple JSON fields named.
I can not change the conflicting fields name.
Solution:
Solved with the following strategy:
private static class SuperClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
public boolean shouldSkipField(FieldAttributes field) {
return field.getDeclaringClass().equals(MySuperClass.class) && field.getName()
.equals("id");
}
}
From the Gson documentation
Exclude fields and objects based on a particular class type:
private static class SpecificClassExclusionStrategy implements ExclusionStrategy {
private final Class<?> excludedThisClass;
public SpecificClassExclusionStrategy(Class<?> excludedThisClass) {
this.excludedThisClass = excludedThisClass;
}
public boolean shouldSkipClass(Class<?> clazz) {
return excludedThisClass.equals(clazz);
}
public boolean shouldSkipField(FieldAttributes f) {
return excludedThisClass.equals(f.getDeclaringClass()());
}
}
Another way to do this is:
builder.excludeFieldsWithoutExposeAnnotation();
Then explicitly expose only the fields you want exposed.

Does the equals method work with objects? If so, how?

I have a program that is zoo and in the zoo there are branched subgroups of animals that are reptiles. When I do an equals method the main program compiles and it runs. I'm confused how does java know to use the equals method if I'm comparing objects and not specifically int or String?
public class Zoo {
public static void main(String[]args) {
Animal a=new Animal("Bob");
Reptile komodo= new Reptile("Snakey");
komodo.bask();
a.size=3;
komodo.size=5;
System.out.println(a);
System.out.println(komodo);
Turtle t= new Turtle("Slowy");
t.hide();
t.size=6;
t.numlegs=4;
System.out.println(t);
System.out.println(t.equals(komodo));
}
}
public class Animal {
public String name;
public boolean equals(Animal other) {
return other.size==this.size;
}
public Animal(String s) {
name=s;
}
public void setName(String n) {
this.name=n;
}
public void eat(String meal) {
System.out.println("chump chump yummy "+meal);
}
public int size;
public String toString() {
return "I am "+name+" and I'm "+size+" cm long";
}
}
public class Reptile extends Animal {
public Reptile(String n) {
super(n);
numlegs=0;
}
public Reptile(String n, int l) {
super(n);
numlegs=l;
}
public void bask() {
System.out.println("basking...");
}
public String toString() {
return super.toString()+numlegs+" legs";
}
public int numlegs;
}
public class Turtle extends Reptile {
public Turtle(String n) {
super (n,4);
shellColor="Brown";
}
public void hide() {
System.out.println("you cant see me");
}
public String toString() {
return super.toString()+" and my shell is"+ shellColor;
}
public String shellColor;
public void bask() {
super.bask();
System.out.println("turtle is basking...");
}
}
You're not overriding the Object#equals method, but overloading it. In your method declaration you use Animal type instead of Object:
public boolean equals(Animal other)
A good overriding of the method would be using the instanceof operator. Showing an example:
#Override
public boolean equals(Object other) {
if(other instanceof Animal) {
Animal otherAnimal = (Animal)other;
//comparison logic...
}
return false;
}
More info on the subject:
Best practices regarding equals: to overload or not to overload?
Overriding Object.equals VS Overloading it
For your question on how java knows how to compare objects,
you need to override the equals method
public boolean equals(Object other){
// return true or false based on your logic
}
While comparing, equals method is used.
You can have a look at this good tutorial which explains the significance of the equals method.
http://www.thejavageek.com/2013/06/26/what-is-the-significance-of-equals-method-in-java/
Also, only overriding equals is not enough if you are using objects into collections those use hashing. You will find a good tutorial at
http://www.thejavageek.com/2013/06/28/significance-of-equals-and-hashcode/
Every class inherits the Object class silently. And the Object class has a equals method. So if any class doesn't override the equals method then it will use the default implementation of Object.equals.
From the doc
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
From the source code of Object.equals
public boolean equals(Object obj) {
return (this == obj);
}
So If any object doesn't have it's own implementation of equals then the equals method will simply check if the object reference is same or not.
So get a desired result from equals you need to implement by your own as alread suggested in other answer

Categories

Resources