教學方

Jamila Sam

Jean-Cédric Chappelier

腳本

In the last episode, we considered the fundamental aspects of object-oriented programming (OOP). In this video, we will start to code all this in Java. So we saw that OOP uses the concept of class which is the result of the process of abstraction and encapsulation as we saw in the example, the definition of the class Rectangle that had the data members "largeur" and "hauteur" (TN:"width" and "height") and had a method "surface" to calculate the area (TN: "surface" means "area"). A class, in programming languages, defines a new type that allows for the creation of variables of this type for example three variables rect1, rect2, rect3 that are called in object-oriented language instances or objects. So how do you code this in Java ? To declare a new class, we will use the special keyword "class". For instance, we will write "class Rectangle" to declare a class that we decided to call Rectangle, followed by its definition as we will specify later on. This expression "class Rectangle" defines a new type, that we can use just as we would do with any other type, to declare, for example, variables. We will use the name of the type, that is, the name of the class, followed by the name of the variable, that is, the name of the instance. For example, to declare an instance that we name "rect1", of the class Rectangle, we simply write "Rectangle rect1". In OOP terminology, a variable corresponds to an instance. In Java, the instance's name, corresponding to "rect1" in this case, is actually a reference to a real object in the memory. All this will be explained in more detail in the course. But where do we write these lines? You have two solutions available: You can declare all your classes in one file, or you can declare one class in each file. Let's examine the first case, with all the classes declared in one unique file. Suppose that we want a class "Dessin" (TN: ="Drawing") that uses the class Rectangle. All this is declared in one unique file, that we decided to name "Dessin.java". Thus we have here the entirety of the file "Dessin.java". We can declare a class Rectangle, here, like this, and a class Dessin. Concretely, to compile it, we use the command "javac Dessin.java" that you can directly enter into the command line, or you can have an integrated development environment (IDE) like Eclipse do it for you. This compiling will produce however two new files. A file "Dessin.class" and a file "Rectangle.class", and then to execute all this, the method main being in the class Dessin, we will enter "java Dessin" in the command line, or you can simply execute the class from Eclipse for example. So this is the first solution to declaring your classes. Another solution consist of declaring one class per file. So each time you have a class, you have a separate file, thus you would declare the class Rectangle in, for example, the file "Rectangle.java", the class Dessin in the file"Dessin.java". And in this case, if you are using a command line, you would have to compile each file separately. Of course, in an IDE, these two files would be part of the same project, and would be compiled independently by invoking only once the command "Build". And Eclipse will take care of compiling the two files, and will result in, like in the first solution, two files ".class". To execute this files from the command prompt, we would enter "java Dessin" because it the class Dessin has the function main. This is also what Eclipse would do for you if you did the execution from there. If you wanted to try "java Rectangle", Rectangle doesn't contain a method main, to in this case, you wil get an exception, that says that the class Rectangle doesn't have a method main. Let's see how to fill this part of the program, that is to say, how to include data members and methods in our class. Let's start with data members. The properties of the class Rectangle are width and height. To declare these data members, simply put the type and the name of the different data members. Here, for each variable we declare the variable's type and name followed by a semicolon. In the example of the class Rectangle, this gives double hauteur, double largeur (TN: "hauteur" means "height" and "largeur", "width"). It's as simple as that! Likewise, for using the data members of an instance, we have the name of the instance, followed by a period, followed by the name of the data variable that we want. For example, to use the height of the rectangle rect1, we write rect1.hauteur. Let illustrate this with an example, given here in one file, that contains a class Exemple that has the method main, as well as a class Rectangle, in which we declare a variable "hauteur" of type double, and a variable "largeur" also of type double. The class Exemple will create an instance of the class Rectangle. To this we have to use the following syntax. The declaring-initilalizing an istance is done by using the name of the class followed by the name of the instance, followed by "= new", the name of the class, and parentheses, like this. For example, we saw in the last example, to create an instance "rect" of the class Rectangle, we would write "= new Rectangle( )". Which would generate all the data members and initialize them to the following values. If we had variables of type int, they would be initialized at the int value 0. For doubles, at the double value 0. For booleans, at false. And for objects, at the special value "null", which we will come back to momentarily. In the last example, here, rect1 has a width and height of 0 before modifying them. Now let's examine the declaration of methods. Methods are simply functions, that are embedded in a class. In the case of the class Rectangle, we will add the method "surface". (TN: "surface" means "area") A method is declared just like a function with the return type, the name of the method, then in parentheses, possibly a list of parameters; all this is the method header followed by the actual definition of the method: the method body in braces. The only difference, is that methods are declared inside the class itself. In our example, the class Rectangle, the method "surface" is included here in the class Rectangle with, its return type double because this method returns a double, its name, but no parameters, and returns the product of the height and the width. We could ask ourselves "Don't we need parameters ? " Indeed, if we had written an ordinary function, like we did before, outside the class, we would have had to pass the height and width as arguments to the function, so that their values can be used in the calculation. So why for this method in the class Rectangle, do we not need to pass any parameters ? The answer is that the height and width are data members of this class. Since "surface" is part of the class Rectangle, the method has access to the height and width of the class Rectangle. Technically, this is called "the scope of the class", that is, that all the data members of a class are accessible from any member of the class and in particular from each of its methods. For example, all the methods of the class Rectangle can access the height and length. Therefore it is unnecessary to pass these variables as arguments to the methods. In summary, a method is simply a function that is specific to a class, so is put in that class, but also has access to the data members of the class. This is typically a beginner's problem when writing their first methods. It is very important not to pass attributes as arguments to class methods. In our example we have exactly this, we have a method "surface" that does not take any parameters but can access Rectangle's height and width That were declared previously in the class. That said, it's not because we don't need to pass the data members as arguments to these methods that the methods never have parameters. Of course, if the method needs certain parameters from outside the class to do its work, then parameters would need to be declared. For example, suppose that we have a class "FigureColoree" (= "ColoredShape") and in this class, we would have several data members as well as a method "colorie" that colors the shape (TN: "colorie" means "color") and that would receive a color and would modify the instance of the class FigureColoree to color them with this color, "Couleur" being itself another type that we would have defined with a class or a typedef. We could for example declare a shape, an instance of the class FigureColoree, and rouge (TN: means "red) , an instance of the class Color. And, anticipating on the syntax, color the shape rouge. What I want to show you is that the color rouge comes from outside the class FigureColoree and is not part of the class FigureColoree. That's why here we have to pass it as argument. It is not a data member that we need to pass as parameter to the method colorie. So now you know how to declare and define methods of a class. But how do you use them? Namely, how do you invoke them? To do this we will use a syntax similar to that for data members, and similar to what you have seen in other contexts such as when you called the method "size" of a dynamic array. If you write "tableau.size()" you are indeed calling the method size, of a dynamic array. The usual format is "name of the instance"."name of the method" then in parentheses, the list of arguments that you want to pass to the method. For instance, to invoke the method "surface" on the instance rect1 of the class Rectangle, we will write "rect1.surface". Here, because the method surface doesn't take any arguments, the parentheses are empty. Let's come back to our comprehensive example. We have, like before, the class Exemple that uses in the method main, an instance rect1 of the class Rectangle. In the class Rectangle, we have added a method "surface". To invoke this method surface on the instance rect1 of the class Rectangle, we simply write "rect1.surface", which returns a double, that we could print with a message like "surface :" In this case it would write "surface :" and 12 which is the result of 3 times 4. Each instance has its own set of values for its data members. If, for example, I declare 3 instances rect1, rect2, rect3 of the class Rectangle, and assigned the value 3 to the height of rect1, the value 4 to the width of rect1, and 11.5 and 3.8 for rect2. We would have another memory location for the value 34.3 of the width of rect3, and a value for its height. So we would have 3 different variables existing in the memory, and when we call "rect2.surface", its the general method surface of the class rectangle that will be applied to the instance rect1, which means that in this method surface, when it is called, "largeur" implies "rect1.largeur" and "hauteur" implies "rect2.hauteur". If I call in another place "rect2.surface", then in this call, "rect2.surface", then "hauteur" will designate "rect2.hauteur", and "largeur" will implie "rect2.largeur" Note that strictly speaking, these representations of instances here are not exactly correct, because the variables refers to objects in the memory, but the aim here is to show that when a method is called, it has access to each of these data members. We will consider later in this course how things are stored in the memory. So this concludes this video. We saw how to declare objects in Java, we saw how to declare data members and how to declare methods. That is to say, that we saw this axe of this chart. We still need to see the differences between the user interface and implementation details, that is, this axe, which will be the topic of our next episode.