Skip to content

ObjectsAndClasses

Chris Ward edited this page Oct 8, 2022 · 1 revision

Finally, we are going to talk about Classes and Objects. You don't have much choice but to use them in Java. Python has the ability to use them, but you don't have to. Because we don't have much choice, we have actually learned a fair bit about them already.

  • We learned that most files are Classes and we need to use the class keyword when we define one. We need to talk more about them though.
  • We talked about public already, as a way for other classes to be able to see inside our class. We will expand on that.
  • static was used, and we said that was to make just one of something.
  • We even brought up final to say that a variable won't change.
  • System, Arrays, and Strings are types of Classes and Objects we have said a little about already. We learned that they can have methods and even contain other objects inside them.

You down with OPP?

Object Oriented Programming (OOP) started when people wanted to be able to hold data, and the methods that would work with them together. A Class is a structure that determines how that data is stored, and contains the methods that will be used on the data. An Object is a specific instance of a Class. We use new to create a new instance. Remember, we used new with Arrays.

Think about an Apple. A computer would want a Class that defines what an apple is, it's color, how it tastes, how it grows, etc. But if the computer was to have 4 apples, it would take the Class and instantiate it with new 4 times, to create 4 apples, or objects.

Sound crazy? It is a way of modeling the physical items around us. Think of the robot. Normally the robot needs motors to move. There are classes for the motors. We can call methods to start and stop them on it. But we need 4 usually to make it move. So we use new to create 4 motor objects. Each motor has individual start and stop methods, and each separate motor stores data like how many rotations or its temperature.

Lets step back a bit. Lets look at a super simple example of a Class.

package examples.f_objects;

public class SimpleObject {

    public int add(int one, int two) {
        return one + two;       
    }
}

This looks either surprisingly, or unsurprisingly similar to what we have done depending on how much you remember. What do you notice that is different here? How would you run this example? What is it going to add?

There is no main method, is there? You can't run it, because there is no main method. Most Java classes don't have a main method and you can't run them. Most classes are something that other classes use. So lets use it.

package examples.f_objects;

public class UseSimpleObject {
    public static void main(String[] args) throws Exception {
        SimpleObject myThing = new SimpleObject();
        int value = myThing.add(55, 27);
        System.out.println("value is:" + value);
    }
}

Now we have a main method. We have something to run. But this time we didn't create the method in this file. We created the method on the SimpleObject instead. Look for the new. See that? We need to use new to get our object we can use from the SimpleObject class. And look to the left of the assignment: SimpleObject myThing. SimpleObject is our type. myThing is the name of the variable. This is just like with Strings. String name = "Chris";. Java gives us a shortcut. The full line could be String name = new String("Chris");

Hmmm. Just thought of something. Check out the SimpleObject class. Our method says public at the front, and there is no static. Remember when we said in earlier examples we needed to say public so that other classes could see it? Try this. Change the public on the add method to private. Now what happens when you try to use the method from the UseSimpleObject file? The compiler tells you that it is not visible. Sometimes that is what you want. We will come back to that. Remember we also used static because it was called from the static main method. That was because the function was defined inside the example, and we never used new.

To see how this works, try to combine the two. Take the UseSimpleObject and create a different add function in this file. Call it AddObject. Don't use static, and create a new instance of it. See, you can use it in the static main method if you create a new object first. There are some fun applications of static which we will see, but first, aren't we supposed to have data and methods in the same class?

DataObject

package examples.f_objects;

public class DataObject {

    private int data;

    public DataObject() {
        data = 42;
    }

    public DataObject(int value) {
        data = value;
    }

    public int getData() {
        return data;
    }

    public void setData(int value) {
        data = value;
    }

    public void squareData() {
        data = data * data;
    }
}

Ok. This was the big reveal. This is an example of a real world Java class. There are many many Java classes that look similar to this. There is a variable, or data being held by the class. There is a set method used to pass in a value to store. There is a get method to retrieve the data, and maybe another method or two that does something with the data, like the squareData method. Once this makes sense, you are sell on the way to understanding this common type of object.

Now, observant students, what did you see that is new, that we haven't talked much about?

How about private. We have talked about public, so I bet you can guess what private does. It hides the variable, or data from the outside. We will test this in a minute. How about the constructor? The what you ask? How about this bit here:

Constructors

public DataObject() {
    data = 42;
}

It looks like a method signature, but it is missing something. Can you see what it is? It is the return type. We said earlier that all methods needed to say they returned void or specify what type they returned, but this method is not. This method is called a constructor. It is run when you use new. It is not allowed to return anything, so Java doesn't let you put a return type. What about the name of the constructor. It is the same as the name of the class, and it must be to be a constructor. It is also not camel case, it has the same capitalization as the class name.

Ok, lets use this class and create some objects now.

package examples.f_objects;

public class UseDataObject {
    public static void main(String[] args) throws Exception {

       DataObject one = new DataObject();
       System.out.println("one: " + one.getData());

       DataObject two = new DataObject(22);
       two.setData(8);
       System.out.println("two: " + two.getData());
       System.out.println("one: " + one.getData());

       two.squareData();
       System.out.println("two: " + two.getData());
       System.out.println("one: " + one.getData());
    }
}

What is the value of data inside one when we create our first instance of the DataObject class? What is in the constructor? When you create an instance with no parameters, the default constructor is called, so it gets the value of 42.

What is the value of data inside two when we create our second instance of the DataObject class? What is the constructor called. We skipped over the other constructor when we talked about DataObject!

public DataObject(int value) {
    data = value;
}

This looks a lot like the setter. If you want to be able to set data in the constructor, you will need to make a constructor that takes data. You could just use the default constructor and then call the setter, but if it would be common to create with data, then it makes sense to create one. So, in this case, the value of data in two is 22 before it is changed to 8.

If you run this example you can see that each object has a different value in it. This was the whole point of putting the data in the class. It can keep track of its own data and doesn't get them mixed up with other objects.

Actually, lets look at the constructors again to make sure we get the idea. In the DataObject class delete the constructor with no parameters. What happens? Does the compiler tell you of any issues? Put it back and take out the other constructor that took one parameter. Now where is the issue?

Public Private Static

Lets take a closer look at the differences between private, public, and static data in a class.

package examples.f_objects;

public class PrivatePublicStatic {
    private int hiddenInt;
    public int visibleInt;
    private static int counter = 0;
    public static final int MAX_VALUE = 100;

    public void setHiddenInt(int value) {
        hiddenInt = value;
    }

    public int getHiddenInt() {
        return hiddenInt;
    }

    public void increment() {
        counter++;
    }

    public int getCounter() {
        return counter;
    }
}

First look at hiddenInt. If there was only the code for hiddenInt this would look pretty much the same as the DataObject, wouldn't it. Yup, it is there to show the differences with the other two. Check out the public value of visibleInt. Are there any methods that use it? Hmm... if there are no set and get methods, how can we do something with it? Well, its public. So you can just access it like we did in Python with the cp.pixels[0]. We will see in the example of using it.

Now static is the fun one, and it breaks some rules. We have talked about how when we have two objects, the data is different and separate. Static if you recall, was used to say "there can be only one". So for the counter, if you increment it on object one, and on object two, they are both incrementing the same value.

package examples.f_objects;

public class UsePrivatePublicStatic {
    public static void main(String[] args) {
        PrivatePublicStatic one = new PrivatePublicStatic();
        one.setHiddenInt(10);
        one.visibleInt = 20;
        
        PrivatePublicStatic two = new PrivatePublicStatic();
        two.setHiddenInt(100);
        two.visibleInt = 200;

        System.out.println("one hidden: " + one.getHiddenInt());
        System.out.println("one visible: " + one.visibleInt);
        System.out.println("two hidden: " + two.getHiddenInt());
        System.out.println("two visible: " + two.visibleInt);

        one.increment();
        two.increment();

        System.out.println("one counter: " + one.getCounter());
        System.out.println("two counter: " + two.getCounter());
    }   
}

Try to figure out what each of the println statements would show before running the example. Do they make sense? Do you see how you access the hiddenInt with the set and get methods? Do you see how you access the visibleInt directly? Why are the counter variables the same in one and two?

  • Remove the static from the counter in PrivatePublicStatic. How does that change the behaviour of the counter. Can you think of ways that static and non static behaviour might we beneficial?
  • Change the public on visibleInt to private. What does the compiler say about that?
  • Change the private to public? Are there any issues with the compiler or running the code? Why might you want to have something private and use the get and set methods instead of just making a variable public?
Clone this wiki locally