0

I just want to create a simple program to teach me how properly pass objects from different classes to a function. I have 2 classes, Player and Enemy and each have 1 variable "speed" I then have a battle class that takes in these two objects, and then finds out if payer is faster or not, but I'm not sure how to access the variables of the objects that I passed

PLAYER CLASS

public class Player {

   int speed = 0;

   public Player(){
       setSpeed(5);
   }

   public void setSpeed(int speed) {
       this.speed = speed;
       }
   }

ENEMY CLASS

public class Enemy {

   int speed = 0;

   public Enemy(){
       setSpeed(3);
   }

   public void setSpeed(int speed) {
       this.speed = speed;
       }
   }

BATTLE CLASS

public class Battle {

public Battle(Object a, Object b){
    if (faster(a.speed, b.speed)){    //This is where the problem is
        System.out.println("Faster");
    }
    else{
        System.out.println("Slower");
    }

}

Boolean faster(int speed1, int speed2){
    if (speed1 > speed2){
        return true;
    }
    else{
        return false;
    }
}

}

MAIN CLASS

public class Main {
   public static void main(String[] args) {
       Player player = new Player();
       Enemy enemy = new Enemy();
       Battle battle = new Battle(player, enemy);

   }

}

  • The general idea is: you make a class and then you make instances of those classes. You can work on these instances by calling their methods: instanceOfClass.method() – Rob Jul 19 '18 at 16:27
  • If I were you I would make make an overarching player class with a constructor which initializes player objects. In this case, both players have speed so speed would go into your constructor. Then make an enemy and a good guy class which inherent from the player class. Then you could make a battle class which takes in two player objects as arguments and your command would be: battle.playerBattle(p1, p2) or something like that. – Rob Jul 19 '18 at 16:32
  • But wouldn't the same problem occur in that I can't access the speed of either object. I am more looking at how I can pass an entire object and access it's variables – esc aautomation Jul 19 '18 at 16:45
  • 1
    Oh I see what your saying now. The overarching class would be able to deal with the objects as good and enemy class both inherit it – esc aautomation Jul 19 '18 at 16:55
  • The general idea is why repeat yourself if both good and bad players have similar characteristics? On top of that, learning how a constructor works will eliminate the problem your having with accessing an objects variables. Let your program do the work of creating the objects and instantiating their variables. Also, let the battle do the work of accessing those objects attributes all you want to do is say something like: letsFight(p1, p2). – Rob Jul 19 '18 at 17:00
  • I just want to say. I am not sure if there is a specific reason your learning Java but if your aim is not to learn a particular language but you want to learn how coding works and good coding practices then may I suggest you start with Python? – Rob Jul 19 '18 at 17:17

2 Answers2

0

below is a brief version of your code,but this should get going and you can do this with two different classes as well.

public class Player {
    private int speed;

       public Player(int speed){
           this.speed=speed;
       }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }      
}




public class Battle {

    Player player;

    static void battle(Player obj1, Player obj2){
        if (obj1.getSpeed() > obj2.getSpeed()){
            System.out.println("Faster");
        }
        else{
            System.out.println("Slower");
        }
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Player player1 =new Player(5);

        Player player2 = new Player(3);

        battle(player1,player2);


    }

}
kryger
  • 12,906
  • 8
  • 44
  • 65
ritpd113
  • 24
  • 3
0

The Problem's solution

To make your program compile, you need to declare the arguments to Battle's constructor as Player or Enemy for Java to find the speed field:

public class Battle {
    public Battle(Player a, Player b) {
        if (faster(a.speed, b.speed)) {
            System.out.println("Faster");
        } else {
            System.out.println("Slower");
        }

    }
    // ...
}

This does, however, prevent passing in Enemy instances. You could provide overloaded methods, however the better solution here is to use either a (probably abstract) base class for Player and Enemy to inherit from or an interface for them to implement.

Using an Abstract Base Class

Making the base class abstract isn't strictly necessary, however it does prevent it from being instantiated, which we only want to allow for the subclasses Player and Enemy. It also highlights that the class is intended to be subclassed rather than to be used by itself.

// Character.java
public abstract class Character {
    private int speed;

    public Character(int speed) {
        this.speed = speed;
    }

    public int getSpeed() {
        return speed;
    }
}

// Player.java
public class Player extends Character {
    public Player() {
        super(5);
    }
}

// Enemy.java
public class Enemy extends Character {
    public Enemy() {
        super(3);
    }
}

With this, the constructor of the Battle could be modified to fit:

// ...
    public Battle(Character a, Character b) {
        if (faster(a.getSpeed(), b.getSpeed())) {
            System.out.println("Faster");
        } else {
            System.out.println("Slower");
        }
    }
// ...

Using an Interface

In contrast to (abstract) classes, interfaces usually describe some action which an object implementing the interface supports.

// HasSpeed.java
public interface HasSpeed {
    int getSpeed();  // interface methods are public and abstract by default
}

// Player.java
public class Player implements HasSpeed {
    @Override
    public int getSpeed() {
        return 5;
    }
}

// Enemy.java
public class Enemy implements HasSpeed {
    @Override
    public int getSpeed() {
        return 3;
    }
}

Here, Battle's constructor would be modified as follows:

// ...
    public Battle(HasSpeed a, HasSpeed b) {
        if (faster(a.getSpeed(), b.getSpeed())) {
            System.out.println("Faster");
        } else {
            System.out.println("Slower");
        }
    }
// ...

Why it needs to be this way

The issue you are having is that you are trying to access fields of the Player and Enemy classes on variables declared as Object. This would work in most dynamically typed languages such as Python or JavaScript, however not in a statically typed language such as Java.

Dynamic Typing

In dynamically typed languages, the type of any variable and / or field is determined and checked at runtime. This means that any object can be passed for any argument, in most of these languages anyways. Whether the object possesses a certain field is checked when the value of that field is retrieved.

This way of doing things makes initially writing code somewhat easier, however it also increases the likelyhood of missing errors, because they will only be reported at runtime, when they come up.

As an example, if Java were dynamically typed, your program would run fine until the point where something other than a Player or Enemy is passed to Battle's constructor and the speed field is not found.

Static Typing

In a statically typed language, types and their field as well as methods are checked at compile-time, so the type of arguments and variables needs to be provided in their declaration. Only these types and their subtypes can then be assigned to them. This makes sure that the object has all the fields and methods you expect of it, although, in the case of subtypes, it may have more.

As you've already figured out, when something other then the declared type is assigned, an error is raised during compilation of the program. It is possible to suppress these errors, e.g. through casts, but a warning will still be given.

This, while being somewhat restrictive, ensures that, unless special action is taken, there will never be a runtime error due to missing fields or methods. Such errors will always be caught during compilation.

Further Reading

This article seems to provide a nice overview of the differences between statically and dynamically typed languages.

In my examples above there is a glimpse of this, but you may want to look into encapsulation to write code that better fits Java conventions. I won't go into this here, as it breaks this answer's scope, however here is some further information.

I have also found that, for learning new programming languages, frameworks or principles, books are an excellent source. Especially if you have a daily commute by public transport, these are an excellent way to kill some time and learn something while doing it. The book which tought me Java is 'Java in a Nutshell' by O'Reilly. I find it well-written, however there are many other options.