Question: While assisting a student with a university project, we worked on a Java exercise provided by the university which defined a class for an address with the fields:

```
number
street
city
zipcode

```

And it specified that the equals logic should return true if the number and zip code match.

I was once taught that the equals method should only be doing an exact comparison between the objects (after checking the pointer), which makes some sense to me, but contradicts with the task they were given.

I can see why you would want to override the logic so that you can use things like `list.contains()` with your partial matching but I'm wondering if this is considered kosher, and if not why not?

Answer: 
Although many answers were given, my opinion still isn't present.

> 
> I was once taught that the equals method should only be doing an exact comparison between the objects
> 
> 
> 

Apart from what rules say, this definition is what people assume from their intiution when they talk about **equality**. Some answers say equality depends on context. They are right in a sense that objects can be equal even if not all of their fields match. But the common understanding of "is equal" should not be redefined too much.

Back to the topic, to me an address equal to another if it points to the same location.

In Germany there can be different specifications of a city, for example if a suburb is named. Then the city of an address in suburb SUB can be given as "Main city" only or "Main city, SUB" oder even only "SUB". Because giving the main city name is ok, all street names in a city and all its assigned suburbs must be unique.

Here the zip code is enough to tell the city, even if the city name varies.  

But leaving the street is NOT unique, unless the zip code also points to one well known street, which it usually doesn't.  

So it is not intuitive to consider two addresses equal if they can point to different locations whose difference consists of the ignored fields.

If there is a use case only requiring some but all fields, then the compare method doing so should be named appropriately. There is only one "is equal" method that should not be secretly turned into "is equal for only one special use case - but noone can see that".

That means, for the explained reasons I'd say...

> 
> but I'm wondering if this is considered kosher
> 
> 
> 

Without knowledge if you accidentally are in a location where street names don't matter: no it isn't.  

If you want to program something not only used in such a location: no it isn't.  

If you want to give students a feeling of doing things right and keeping code comprehensible and logical: no it isn't.
As others have mentioned, the exact semantics of object equality are a part of the business domain's definition. In this case, I don't think it's reasonable to have a "general" object like `Address` (containing `number`, `street`, `city`, `zipcode`) to having a very narrow definition of equality (which, as others have mentioned, works in Brazil but not in the US, for example).

Instead, I would have `Address` have value-like semantics for equality (defined by equality of all members). I would then either:

1. Create a `StreeNumberAndZip` class (`# TODO: bad name`), which contains only a `street`, and a `zipCode`, and defines `equals` over those. Whenever you want to compare two `Address` objects in that particular way, you can do `addressA.streetNumberAndZip().equals(addressB.streetNumberAndZip())`, or...
2. Create a `AddressUtils` class with a `bool equalStreeNumberAndZipCode(Address a, Address b)` method, which defines the narrow equality there.

In both cases, you still have access to use `addressA.equals(addressB)` for full equality checking.

For `n` fields of an object, there are `2^n` different definitions of equality (each field can be included or excluded from the check). If you find yourself needing to check equality in many different ways, it might also be useful to have something like an `enum AddressComponent`. You could then have a `bool addressComponentsAreEqual(EnumSet<AddressComponent> equatedComponents, Address a, Address b)`, so you can call something like 

```
bool addressAreKindOfEqual = AddressUtils.addressComponentsAreEqual(
    new EnumSet.of(
        AddressComponent.streetNumber, 
        AddressComponent.zipCode,
    ),
    addressA, addressB
);

```

This is obviously a lot more typing, but it can save you from having an exponential explosion of equality-checking methods.