Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the .equals() method not overriden for arrays of primitives in Java?

I am currently working on a project where I want to implement a login mechanism using a username and a password that gets compared against a database.

I had something like this in mind:

public boolean verifyUser( String username, char[] password ) 
{
  List<char[]> dbpass = getPasswords( username );
  if ( dbpass.contains( password ) )
  {
    overwriteWithNonsense( password );
    return true;
  }
  overwriteWithNonsense( password );
  return false;
}

when I noticed that my unit tests were failing. So I took a deeper look at it an noticed that the Object::equals method is not overriden for arrays of primitives which explained why List::contains would always evaluate to false.

I know there is a possible workaround using:

if ( dbpass.stream().anyMatch( pw -> Arrays.equals( pw, password ) ) )
{
  overwriteWithNonsense( password );
  return true;
}

My question is why the designer chose to keep the 'default implementation' of Object::equals? Wouldn't it be way more convenient than implementing a framework with static utility methods like Arrays.equals(array1,array2)?

like image 971
L.Spillner Avatar asked Jun 01 '18 13:06

L.Spillner


2 Answers

Any Collections of arrays is mostly bad design. They should not be used together. You're probably better of by introducing a trivial, but needed class:

public class Password{
     private final char[] password;

     public Password(char[] password){
         this.password = password;
     }

     @Override
     public boolean equals(Object obj){
         // equals logic
     }

     @Override
     public int hashCode(){
         // hashCode logic
     }
}

And then having a List<Password>. (I also shortened your verifyUser method because it seemed a bit redundant):

public boolean verifyUser( String username, char[] password ){
    List<Password> dbpass = getPasswords(username);
    boolean contained = dbpass.contains(new Password(password));
    overwriteWithNonsense(password);
    return contained;
}

(Your other question regarding the why it is not overriden is mostly off-topic, because only the java-devs could really answer that.)

like image 68
Lino Avatar answered Oct 05 '22 01:10

Lino


In Java array is not a class but from Java Doc section 4.3.1 it is treated as an object. Now as this is not a class there's no code for equals/hashCode.

Now, for your solution to compare arrays you can use Arrays.equals method to compare two arrays:

public boolean verifyUser( String username, char[] password ) 
{
    List<char[]> dbpass = getPasswords( username );
    for(char[] arr : dbpass)
    {
        if ( Arrays.equals(arr,password) )
        {
            overwriteWithNonsense( password );
            return true;
        }
    }

    overwriteWithNonsense( password );
    return false;
}
like image 30
Shubhendu Pramanik Avatar answered Oct 05 '22 00:10

Shubhendu Pramanik