• Non ci sono risultati.

Transition to Java

19.4 Object-oriented programming in Java

}

Though working with OCaml and the functional style are a good way to broaden your mental toolbox, it is also essential to be able to work fluently in other programming paradigms. Just as the program above can be written very cleanly in the functional style, there are Java programs that would be difficult to express cleanly in OCaml.

19.4 Object-oriented programming in Java

The fundamental difference between OCaml and Java is Java’s pervasive use of objects as the means of structuring data and code. Java syntax provides a conve-nient way to encapsulate some state along with operations on that state. To see what this means, consider this variant of thecounterprogram that we saw earlier when discussing local state (see §17):

(* The type of a counter's local state. *) type counter_state = {mutable cnt : int}

(* Methods for interacting with a counter object. *) type counter = {

inc: unit -> int;

dec: unit -> int;

}

(* Constructs a fresh counter object with its own local state. *) let new_counter () : counter =

let s : counter_state = {cnt = 0} in {

inc = (fun () -> s.cnt <- s.cnt+1; s.cnt) ; dec = (fun () -> s.cnt <- s.cnt-1; s.cnt) ; }

(* Create a new counter and then use it. *) let c : counter = new_counter () in

;; print_int (c.inc ())

;; print_int (c.dec ())

This OCaml program illustrates the three key features of an object:

• An object encapsulates some local, often mutable state. That local state is visi-ble only to the methods of the object.

• An object is defined by the set of methods it provides—the only way to interact with an object is by invoking (i.e. calling) these methods. Moreover, the type of the encapsulated state does not appear in the object’s type.

• There is a way to construct multiple instances—new object values—that be-have similarly (and therefore share implementation details).

In the OCaml example above, the first feature is embodied by the use of the typecounter_state, which describes that local state associated with each counter object. The second feature is realized by the type counter, which exposes only the two methods available for working with counter objects. Finally, the function

new_counter provides a way to create newcounter instances (i.e. values of type

counter). The use of local scoping ensures that the statesis only available to the code of theincanddecmethods, and therefore cannot be touched elsewhere in the program—the statesis encapsulated properly.

Java’s notation and programming model make it easier to work with data and functions in this style. A Java class combines all three features—local state, method definitions, and instantiation—into one construct. Think of a class as a template for constructing instances of objects—classes are not values, they describe how to create object values. The Java code below shows how to define the class of counter objects that is analogous to the OCaml definitions above:

Here the notation public class Counter \{ ... \} defines a new type, i.e.

class, of counter objects calledCounter. Here, and elsewhere, the keywordpublic means that the definition is globally visible and available for other parts of the program to use. A class consists of three types of declarations: fields, constructors, and methods.

A field (also sometimes called an instance variable) is one component of the ob-ject’s local state. In theCounterclass, there is only one field, calledcnt. The key-wordprivatemeans that this field can only be accessed by code defined inside the enclosing class—it is used to ensure that the state is encapsulated by the object.

A constructor always has the same name as its enclosing class—it describes how to build an object instance by initializing the local state. Here, the constructor

Countersimply setscntto0.

A method like incor dec defines an operation that is available on objects that are instances of this class. In Java, a method is declared like this:

public T method(T1 arg1, T2 arg2, ..., TN argN) { ...

public class Counter { private int cnt;

// constructs a new Counter object public Counter () {

cnt = 0;

}

// the inc method public int inc () {

cnt = cnt + 1;

return r;

}

// the dec method public int dec () {

cnt = cnt - 1;

return cnt;

} }

return e;

}

Here, Tis the method’s return type—it says what type of data the method pro-duces. T1 arg1throughTN argNare the method’s parameters, whereT1is the type ofarg1, etc. The return estatement can be used within the body of a method to yield the value computed by e to the caller. Here again, the keyword public in-dicates that this method is globally visible. Note that the fieldcntis available for manipulation within the body of these methods. As we will see, methods can also define local variables to name the intermediate results needed when performing some computation.

Unlike in OCaml, in which code can appear “at the top level”, in Java all code lives inside of some class. A Java program starts executing at a specially designated

mainmethod. For example, a program that creates some counter objects and uses their functionality might be created in a class calledMainlike this:

public class Main {

public static void main(String[] args) { Counter c = new Counter();

System.out.println(c.inc());

system.out.println(c.dec());

} }

The type ofmainmust always be declared as shown above—we’ll see the mean-ing of thestatickeyword in §??. The keywordvoidindicates that themainmethod does not return a useful value—it is analogous to OCaml’sunittype. To create an instance of theCounterclass, the code in themaininvokes theCounterconstructor using thenewkeyword. The expressionsc.inc()andc.dec()then invoke theinc anddecmethods of the resulting object, which is stored in the local variablec.