I want to make the class below immutable. Can anyone provide a simple example of creating an immutable class in java?
class Emp implements Comparable
{
String name,job;
int salary;
public Emp(String n,String j,int sal)
{
name=n;
job=j;
salary=sal;
}
public void display()
{
System.out.println(name+"\t"+job+"\t"+salary);
}
public boolean equals(Object o)
{
// use a shortcut comparison for slightly better performance; not really required
if (this == o)
{
return true;
}
// make sure o can be cast to this class
if (o == null || o.getClass() != getClass())
{
// cannot cast
return false;
}
// can now safely cast
Emp p=(Emp)o;
return this.name.equals(p.name)&&this.job.equals(p.job) &&this.salary==p.salary;
}
public int hashCode()
{
return name.hashCode()+job.hashCode()+salary;
}
public int compareTo(Object o)
{
Emp e=(Emp)o;
return this.name.compareTo(e.name);
//return this.job.compareTo(e.job);
// return this.salary-e.salary;
}
}
Just label all fields of your class as final, and don't assign to them anywhere but the constructor for your class.
Also, it's good to make the class final, or to only provide private constructors, and static factory methods. This means people cannot subclass your class and override you methods.
for example:
public class Immutable {
private final String value;
private Immutable(String value) {
this.value = value;
}
public static Immutable create(String value) { return new Immutable(value); }
public String getValue() { return value; }
}
Related
I am trying to Implement a class named Parade using an ArrayList, which will manage instances of class Clown. Each Clown needs to be identified by all object data String for their name, int id and double size. I join a new Clown to the end of the Parade. Only the Clown at the head of the Parade (i.e., the first one) can leave the Parade. In addition, I write a method called isFront that takes a Clown as parameter and returns true if the passed clown is at the front of the parade otherwise returns false. Create a test application to demonstrate building a parade of three or four clowns and include your own name. Then, remove one or two, and add another one or two. Also, test the isFront method by passing different clowns to the method.
I have a code but it is not returning true for the isFront method, I am trying to use contains method I also tried to use Comparable interface Clown but it did not work that well. Not sure what to do.
import java.util.ArrayList;
public class Main
{
public static void main(String[] args)
{
Parade circus = new Parade();
circus.addClown(new Clown("Bobby",9,12.0));
circus.addClown(new Clown("Clair", 2, 11.0));
circus.addClown(new Clown("Tony",6,10.0));
circus.addClown(new Clown("Sarah",3,5.0));
circus.display();
System.out.println(circus.isFront(new Clown("Bobby", 9, 12.0)));
}
}
import java.util.ArrayList;
public class Parade
{
private static ArrayList<Clown> parade;
private int top;
public Parade()
{
top=0;
parade= new ArrayList<Clown>();
System.out.println(parade);
}
public void addClown(Clown c)
{
parade.add(c);
top++;
}
public void removeClown() //(Clown c)
{
parade.remove(0);
top--;
}
public void display()
{
System.out.println(parade);
}
public void getData()
{
parade.get(0);
}
public void setData()
{
parade.set(1,new Clown("Claire",2,5.0));
System.out.println(parade);
}
public int getTop()
{
return top;
}
public boolean isFront(Clown c)
{
return !parade.isEmpty() && c.equals(parade.get(0));
}
//exceptions
}
public class Clown
{
private String name;
private int id;
private double size;
public Clown(String name, int id, double size)
{
this.name=name;
this.id=id;
this.size=size;
}
public String getName()
{
return name;
}
public int getId()
{
return id;
}
public double getSize()
{
return size;
}
public String toString()
{
return name.toString() + id + size;
}
public boolean equals(Object o) {
if (o instanceof Clown c) {
return this.getName().equals(c.getName()) && this.getId() == c.getId() && this.getSize() == c.getSize();
}
return false;
}
}
their is not much info in our textbook about this stuff Java FOundations 5th e Lewis like working with objects and arraylists it skips it and assumes you already know it lol..
Firstly, objects in Java are, by default, compared by reference. So, even if you create two Clown objects with the exact same properties, Java sees them as different objects because both those object references are not the same, they are both referring to different memory locations. You can override this behavior and ask Java to compare it as you want by overriding the equals() method of the Object class:
public class Clown {
private String name;
private int id;
private double size;
public Clown(String name, int id, double size) {
this.name=name;
this.id=id;
this.size=size;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public double getSize() {
return size;
}
#Override
public boolean equals(Object o) {
if (o instanceof Clown) {
Clown c = (Clown) o;
return this.getName().equals(c.getName());
}
return false;
}
#Override
public int hashCode() {
return this.getId();
}
#Override
public String toString() {
return name.toString() + id + size;
}
}
This will help with contains()(it internally uses equals()).
Secondly, you can just compare your clown with the first clown to see if it is the one at the front:
public boolean isFront(Clown c) {
return !parade.isEmpty() && c.equals(parade.get(0));
}
The isFront() method will return true if the parade is not empty and the clown c is equal to to the first clown in the parade. get(0) retrieves the first clown in the parade.
As per your comment, if you want that two clowns be equal only if all their properties are equal, change your equals method to:
#Override
public boolean equals(Object o) {
if (o instanceof Clown) {
Clown c = (Clown) o;
return this.getName().equals(c.getName()) &&
this.getId() == c.getId() &&
this.getSize() == c.getSize();
}
return false;
}
The equals() method is of the Object class which is the parent class of all Java classes. It defines how to compare two objects.
Its signature is as follows:
public boolean equals(Object obj)
As we're overriding, its signature must be the same in the derived class, in our case in class Clown. Its parameter is of type Object not Clown. Any type can be converted to Object, if I compare an object of Clown to another type, like:
Clown c = new Clown("X", 1, 10);
if ( c.equals(objectOfAnotherType) ) {..}
it will still work.
So we use the instanceof operator to check if that another object is also a Clown. If it is not an instance of Clown, we return false but if it is, we convert/cast that object to Clown, only then we can call getName() and other getter methods:
if (o instanceof Clown) {
Clown c = (Clown) o; //Casting happens here
return this.getName().equals(c.getName()) &&
this.getId() == c.getId() &&
this.getSize() == c.getSize();
}
return false;
Java 14 introduced a shortcut for this, instead of these steps:
if (o instanceof Clown) {
Clown c = (Clown) o;
we can simply write:
if (o instance of Clown c)
which does the casting for us and stores it in c.
Lastly, I have also overriden Object.hashCode() because you have to when you override equals(), here's why.
Here is my code:
class Car {
Piece doors;
Piece window;
String name;
List<Sign> signs; //???
Car() {
}
#Override
public String toString() {
//...
}
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || other.getClass() != this.getClass()) {
return false;
}
if (this.doors == other.doors && this.window == other.window ) {
return true;
}
return false;
}
}
class Piece extends Car {
Piece() {
//...
}
}
class Brand extends Car {
Brand(String name, Sign[] signs) {
this.name = name;
this.signs = signs;
}
List<Sign> signs() {
return this.signs;
}
}
This is my structure of my classes. Now, I would like to find out, whether two compared objects are equal or not. Let's say we have two Piece objects. How can I compare them in method Car.equals()? The problem here is how to find whether that object belongs to Piece or Brand subclass.
Piece should not extend Car, but Car should be composed of Piece objects such as Window, Door, etctera. A Piece should implement equals/hashcode. Although having the interface explicitly define those functions doesn't mean the inherited class requires it, it still hints that it is necessary (refer to Comparator).
The equals contract requires the referenced members to be final for it to meet the contract. Brand overrides equals/hashcode to compare the brand name.
Window and Door need defining final members to make them truly unique but unfortunately none are provided in the question.
static class Car {
private final Piece doors;
private final Piece window;
private final Brand brand;
private final int hashCode;
Car(Piece doors, Piece window, Brand brand) {
this.doors = doors;
this.window = window;
this.brand = brand;
this.hashCode = Objects.hash(doors, window, brand);
}
#Override
public int hashCode() {
return hashCode;
}
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Car) {
Car otherCar = (Car) obj;
return otherCar.doors.equals(doors) && otherCar.window.equals(window) && otherCar.brand.equals(brand);
}
return false;
}
}
static class Window implements Piece {
#Override
public int hashCode() {
return super.hashCode();
}
#Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
static class Door implements Piece {
#Override
public int hashCode() {
return super.hashCode();
}
#Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
interface Piece {
boolean equals(Object other);
int hashCode();
}
static class Brand {
private final String name;
private final int hashCode;
Brand(String name) {
this.name = name;
this.hashCode = Objects.hash(name);
}
#Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (other instanceof Brand) {
Brand otherBrand = (Brand) other;
return otherBrand.name.equals(name);
}
return false;
}
#Override
public int hashCode() {
return hashCode;
}
}
I am overriding equals method of a class to compare two objects since I want to compare all the fields of it. If two objects are unequal, is there a way to find out which of the fields were unequal due to which the objects are unequal?
You could write a method in the class that returns an object of the same type with either the difference or null for each data member. Or you can find a library that does it for you. Try http://javers.org
Create class to strore fields information like this (or use Map):
class FieldsContainer<F,V>{
private F field;
private V value;
public FieldsContainer(F field, V value) {
this.field = field;
this.value = value;
}
public FieldsContainer(){}
public F getField() {
return field;
}
public void setField(F field) {
this.field = field;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
and then in equals():
public boolean equals(Object obj) {
...
} else if (!field1.equals(other.field1)){
fieldsContainer=new FieldsContainer("fieldName1", field1);
return false;
}
if (field2 != other.field2){
fieldsContainer=new FieldsContainer("fieldName2", field2);
return false;
}
fieldsContainer=null;
return true;
}
and in main:
if(!obj1.equals(obj2)){
fieldsContainer.getField();
fieldsContainer.getValue();
//Your stuff
}
public class Car
{
private String name;
public int id;
public Car(String name, int id)
{
this.name = name;
this.id = id;
}
#Override
public boolean equals(Object ob)
{
if (!(ob instanceof Car))
{
return false;
}
Car that = (Car)ob;
return this.id == that.id;
}
#Override
public int hashCode()
{
return id;
}
// this class also got getters and setters
Then I got another class
public class CarList
{
private Collection<Car> cars;
public CarList()
{
cars = new HashSet<>();
}
public boolean insertCar(Car car)
{
return cars.add(car);
}
My question is: How to properly override equals() and hashCode() method, where I consider 'id' and 'name' attribute for object comparsion and hashCode calculation ( so there is no possibility to have 2 objects with the same name and ID - because in this code as it is - it only takes 'id' attribute for object comparsion)?
As of Java 7, there are static methods on Objects that makes implementing hashCode and equals easier. This should work well, assuming you don't want to use getClass() instead of instanceof to determine type compatibility. That depends on how subclasses of Car should compare to Cars.
#Override
public boolean equals(Object ob)
{
if (!(ob instanceof Car))
{
return false;
}
Car that = (Car)ob;
return Objects.equals(this.id, that.id) && Objects.equals(this.name, that.name);
}
#Override
public int hashCode()
{
return Objects.hash(id, name);
}
Instead of using
if (!(ob instanceof Car))
{
return false;
}
You should think about using
if (getClass() != obj.getClass())
return false;
Lets assume you have ForWdCar extends Car and TwoWdCar extends Car with equal name and id.
Do you want them to be equal? 1st solution,
Do you want them to be unequal? 2nd solution
You don't care, such cases don't happen? Second solution, it's faster.
I have a subclass called "worker" extending the "Person" class. I am trying to override the equals() method from "Person" within the subclass of "Worker". Can anyone explain if my attempt is correct in terms of a basic override?
public class Person {
private String name;
public Person(String n) {
name = n;
}
public Person() {
this("");
}
public String getName() {
return name;
}
public String toString() {
return getName() + " ";
}
public boolean equals(Object rhs) {
if (!(rhs instanceof Person)) {
return false;
}
Person other = (Person) rhs;
return this.getName().equals(other.getName());
}
class Employee extends Person {
double salary;
public Employee(double b) {
salary = b;
}
Employee() {
salary = 150000;
}
public double getSalary() {
return salary;
}
#Override
public String toString() {
return super.toString();
}
// my attempt
#Override
public boolean equals(Object rhs) {
if (rhs == null) {
return false;
}
if (getClass() != rhs.getClass()) {
return false;
}
if (!super.equals(rhs))
return false;
else {
}
return false;
}
}
}
You've sort of mechanically handled the override part correctly, but the equals method of your Employee class will never return true.
First because of this:
if (!super.equals(rhs)) return false; else { }
You'll always fall through to the final return false, even if the result of super.equals is true.
Once you fix that, you still have a problem with the equals method of Person. If you pass in an instance of Worker, that equals method will always return false.
There may yet be other things, but those two are show stoppers.
The NetBeans using the shortcut alt + insert, you can automatically generate the equals method, constructors, getters, setters, delegate method, and others. If you want to use the collection using encoding mixing(Hashtable, HashMap, HashSet) it with redefining equals you must also redefine the hashCode().