1) In general it's a good idea not to allow null values unless they have a special meaning. In this case, it doesn't make sense for a dog not to have a name, so we don't allow null. It's best to throw exceptions as soon as possible, so in this case we throw NullPointerException in the constructor. Now we don't have to worry in other methods that name could be null, so we don't have to check every time we use name.
2) Your version of the equals method was good, except for using == instead of equals. I'm just used to writing it this way. The only real difference is that I check first whether o == this. The method should work fine without it, but this is a small optimization, so the method returns quickly if the object is being compared to itself.
3) Yes, you are correct. Here is a small example that shows how
you should implement hashCode and equals methods for a class that holds different kinds of member fields: