Tuesday, October 20, 2009

Subclassing Java Classes




I l@ve RuBoard









Subclassing Java Classes


You can subclass Java classes like Python classes. Here's an example of subclassing the Java class java.util.Date (from MyDate.py):



from java.util import Date

class MyDate(Date):
def __init__(self, num=None):
if num is None:
Date.__init__(self)
else:
Date.__init__(self, num)
def __str__(self):
str = Date.toString(self)
str = "MyDate: " + str
return str

Working with Java Constructors


When you subclass a Java class, you call its superclass's constructor, just as you do in regular Python. As we saw, the MyDate.py example subclassed the Date class from java.lang and defined two constructors that called Date's base class constructors.


As an exercise, look up the constructors of java.lang.Date in the Java API documentation. You'll find them in a section called Constructor Summary.


The constructor of Date is defined in Java as



Date ()

You call it from Python like this:



Date.__init__(self)

The second constructor of Date is defined in Java as



Date (long date)

You call it from Python like this:



Date.__init__(self, num)

Here's how to call both Date constructors:



class MyDate(Date):
def __init__(self, num=None):
if num is None:
Date.__init__(self)
else:
Date.__init__(self, num)

In Java, constructors are special language constructs that always have the same name as that of their class. In Python, the constructor is always a method called __init__. You call Java constructors in Python just as you do Python constructors; however, you can only do so in your subclass's constructor.



Working with Java Methods


When subclassing a Java class, you can call all methods from a Java base class that you can from a Python base class. In our MyDate.py example, we subclass Date and add a __str__ method.



def __str__(self):
str = Date.toString(self)
str = "MyDate: " + str
return str

Unlike Python methods, Java methods can be overloaded, which essentially means that a Java class can have several methods with the same name. An example of this is java.io.OutputStream, which defines three write() methods:



  • abstract void write(int b)


  • void write(byte[] b)


  • void write (byte[] b, int off, int len)



As you can see, these methods can be called with different argument types.


To subclass OutputStream, we need a way to override any or all of the write() methods. The following example shows how to do this. (Before we get started, however, read up on the OutputStream class in the Java API documentation.)



from java.io import OutputStream
import types

class OutputScreen (OutputStream):
def write (self, b=None, off=None, len=None):
if (type(b) is types.IntType):
print b
elif (off is None):
print b
else:
print b[off:off+len]

This code imports OutputStream, a Java class from the java.io package. OutputScreen subclasses OutputStream and overrides its write() methods (all three versions). Thus, each clause of the if statement in write() mimics a different overloaded signature of OutputStream's write()s.



Overloading


Strongly typed languages like Java, C++, and Delphi allow method overloading. In other words, they allow more than one method with the same name but different signatures. The type of the method's arguments defines the signature. With overloaded methods, the signature determines which method is actually being invoked.


Python doesn't allow method overloading based on type signatures because it isn't a strongly typed language. (Some may say it's loosely typed; Pythonians prefer the term "dynamically typed."). To override a method from a subclass in Python, the class must define a method with the same name.



To illustrate, the following code mimics the functionality of void write(int b) by determining that the first argument, b, is of type Integer.



if (type(b) is types.IntType):
print b

This code mimics the functionality of void write(byte[]b) by determining that off wasn't passed (and that the first type was not Integer).



elif (off is None):
print b

This mimics the functionality of void write (byte[]b, int off, int len) by a process of elimination.



else:
print b[off:off+len]

Let's test each of these scenarios. Start the overload.py module from Jython with the �i option and try the following statements in an interactive session.



from jarray import array

screenOut = OutputScreen()

screenOut.write(33)

seq = [0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF]
bytearray = array(seq, 'b')

screenOut.write(bytearray)
screenOut.write(bytearray, 5, 14)

Essentially, we're calling all three write() methods. Here's the code step by step.


Import the array() function from jarray to create Java byte arrays (byte[]).



from jarray import array

Create an OutputScreen instance called ScreenOut.



screenOut = OutputScreen()

Invoke the first form of the write() method, void write(int b).



screenOut.write(33)

Create a byte array for an argument for the second and third forms of write().



seq = [0,1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF]
bytearray = array(seq, 'b')

Invoke the second form of write(), void write(byte[] b).



screenOut.write(bytearray)

Invoke the last form of write(), void write (byte[]b, int off, int len).



screenOut.write(bytearray, 5, 14)

The output should be



33
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], byte)
array([5, 6, 7, 8, 9, 10], byte)








    I l@ve RuBoard



    No comments: