UF 06: JAVA¶

Classes in Pseudo Java™¶

Alta Formazione Professionale - ITT Marconi

February 2021

NOTE: Code in slides sometimes is too long, see all on Github

My mommy always said there were no monsters. No real ones.

But there are.

Ellen Ripley, Alien Resurrection

WARNING: what follows is not proper Java style

  • complex classes are ugly in the short term
  • simple classes are ugly in the long term

Your package¶

package it.yourcompany.adventure;

At the beginning of source files you have to declare the package.

  • Choose your company domain (i.e. yourcompany.it)
  • reverse the parts (it.youtcompany)
  • if you want add further subdomains for your specific project (adventure):

Your files then MUST reside in folders like these:

- it
   - yourcompany
      - adventure
         Monster.java
         Game.java

Most IDE offer some automation to automatically place the files in the folders

Join The Game¶

Create a file called Game.java with a public class Game inside:

  • to be able to run a class, you need main method
package it.yourcompany.adventure;
In [2]:
public class Game {
    
    public static void main(String[] args){
        
        System.out.println("Welcome to my dungeon, stranger....");        
        
       }
}

Running The Game¶

Run Game class in Netbeans:

oop/img/run.png

Monsters: the first encounter¶

Create a file called Monster.java with a public class Monster inside

  • filename must be the same as public class name
package it.yourcompany.adventure;
In [3]:
public class Monster {
    public String name = "";    
    public int lifepoints = 0;                   
}

Java dogma says...

  • NOTE 1: fields should be private, but we're using public ones
  • NOTE 2: we should define a getter/setter for each field, we don't do that
  • NOTE 3: we should also define a constructor, but we're using the implicit default empty constructor which is public

Invoke the Monster¶

In [4]:
public class Game {
    
    public static void main(String[] args){
        
        System.out.println("Welcome to my dungeon, stranger....");        
        
        Monster monster1 = new Monster();
        
        monster1.name = "Cerberus";
        monster1.lifepoints = 7;
                        
        System.out.println();
        System.out.println("monster1.name is       : " + monster1.name);
        System.out.println("monster1.lifepoints are: " + monster1.lifepoints);
                
       }
}

Run the Game.java, you should see some output.

Join the Java Cult¶

join-the-cult.png

toString Ritual¶

This output printing is verbose:

In [6]:
System.out.println("monster1 name is       : " + monster1.name);
System.out.println("monster1 lifepoints are: " + monster1.lifepoints);
monster1 name is       : Cerberus
monster1 lifepoints are: 7

This would be shorter, but....:

System.out.println("monster1.toString() is : " + monster1);
monster1 toString() is : it.yourcompany.adventure.Monster@b44d430f

It shows the physical address, not nice.

After you defined your fields:

  • generate a toString method implementation
  • (if you wonder why, it's because the cult told you to do so)

insert-code.png

to-string-1.png

Select all fields:

to-string-2.png

package it.yourcompany.game;
In [7]:
public class Monster {
    
    public String name = "";
    public int lifepoints = 0;    


    // Java rituals  ......................
    
    @Override
    public String toString() {
        return "Monster{" + "name=" + name + ", lifepoints=" + lifepoints + '}';
    }    
    
}

You should now have a printable monster:

In [8]:
public class Game {
    
    public static void main(String[] args){
        
        System.out.println("Welcome to my dungeon, stranger....");        
        
        Monster monster1 = new Monster();
        
        monster1.name = "Cerberus";
        monster1.lifepoints = 7;
        
        System.out.println();
        System.out.println("monster1.toString() is: " + monster1);
                
    }
}
Welcome to my dungeon, stranger....

monster1.toString() is: Monster{name=Cerberus, lifepoints=7}

All equal monsters should be equal.¶

Are they?

In [9]:
import java.util.List;

public class Game {    
    public static void main(String[] args){
        
        System.out.println("Welcome to my dungeon, stranger....");        
        
        Monster monster1 = new Monster();
        
        monster1.name = "Cerberus";
        monster1.lifepoints = 7;
        
        System.out.println();
        System.out.println("monster1.toString() is: " + monster1);

        Monster monster2 = new Monster();
        
        monster2.name = "Cerberus";
        monster2.lifepoints = 7;
                
        System.out.println();
        System.out.println("monster2.toString() is: " + monster2);

        System.out.println();
        System.out.println("monster1.equals(monster2) : " + monster1.equals(monster2));
        
        System.out.println();
        System.out.println("List.of(monster1).contains(monster2): " + List.of(monster1).contains(monster2));                
    }
}
Welcome to my dungeon, stranger....

monster1.toString() is : Monster{name=Cerberus, lifepoints=7}

monster2.toString() is : Monster{name=Cerberus, lifepoints=7}

monster1.equals(monster2) : false

List.of(monster1).contains(monster2): false

That's not ok.

Both .equals() and in general collections search methods do not work by default with new classes.

Equals and Hashcode Ritual¶

Let's fix the problem.

equals-hash-1.png

equals-hash-2.png

You should now have a ton of more Java bla bla, see all on Github

package it.yourcompany.adventure;
In [10]:
import java.util.Objects;

public class Monster {
    
    // stuff that matters    
    public String name = "";
    public int lifepoints = 0;    
    
    
    // Java rituals  ......................
    
    @Override
    public String toString() {
        return "Monster{" + "name=" + name + ", lifepoints=" + lifepoints + '}';
    }    
    @Override
    public int hashCode() {
        int hash = 3;
        hash = 89 * hash + Objects.hashCode(this.name);
        hash = 89 * hash + this.lifepoints;
        return hash;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Monster other = (Monster) obj;
        if (this.lifepoints != other.lifepoints) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return true;
    }        
}

Show me the equality - same monster¶

Rerun the Game:

Welcome to my dungeon, stranger....

monster1.toString() is : Hero{name=Cerberus, lifepoints=7}

monster2.toString() is : Hero{name=Cerberus, lifepoints=7}

monster1.equals(monster2) : true

List.of(monster1).contains(monster2): true

Show me the equality - many monsters¶

In [12]:
Monster monster3 = new Monster();

monster3.name = "Zombo";
monster3.lifepoints = 4;


System.out.println();
System.out.println("monster1.equals(monster3) : " + monster1.equals(monster3));

System.out.println();
System.out.println("List.of(monster1).contains(monster3): " + List.of(monster1).contains(monster3));

System.out.println();
System.out.println("List.of(monster1, monster3).contains(monster3): "
                    + List.of(monster1, monster3).contains(monster3));
monster1.equals(monster3) : false

List.of(monster1).contains(monster3): false

List.of(monster1, monster3).contains(monster3): true