The Artima Developer Community
Sponsored Link

Java Answers Forum
How is this executed?

6 replies on 1 page. Most recent reply: Apr 25, 2002 8:17 AM by Lynn Hollerman

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 6 replies on 1 page
Lynn Hollerman

Posts: 67
Nickname: gmholler
Registered: Mar, 2002

How is this executed? Posted: Apr 23, 2002 8:14 AM
Reply to this message Reply
Advertisement
I came across this after being asked a question, and I have to admit, I must've missed something because I thought I understood how a Java program flowed! I don't understand this - how some of these methods are getting called, why they're there in the first place. Can anyone shed some light on this, or tell me what I should be looking at?

Here's the code:
import java.util.*;
 
class AltDate extends Date {
  static final String dayAsWord[] = {
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
    "Friday", "Saturday"};
  static final String monthAsWord[] = {
    "January", "February", "March", "April", "May", "June", "July",
    "August", "September", "October", "November", "December"};
 
  AltDate() {
    super();
  }
 
  /*
  getTimeDateString() builds a time and date string of the form
  "10:07 - Thursday - 6 February 1997":
  */
 
  String getTimeDateString() {
    Calendar c = Calendar.getInstance();
    int hour = c.get(Calendar.HOUR_OF_DAY);
    int min = c.get(Calendar.MINUTE);
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);
    int dayOfWeek =
      c.get(Calendar.DAY_OF_WEEK) - c.getFirstDayOfWeek();
    String minutes = (min < 10) ? "0" + min : String.valueOf(min);
    String tds = hour + ":" + minutes + " - " +
      dayAsWord[dayOfWeek] + " - " +
      day + " " +
      monthAsWord[month] + " " + year;
    return tds;
  }
 
  int getHourInt() {
    Calendar c = Calendar.getInstance();
    return c.get(Calendar.HOUR_OF_DAY);
  }
 
  int getMinuteInt() {
    Calendar c = Calendar.getInstance();
    return c.get(Calendar.MINUTE);
  }
 
  int getYearInt() {
    Calendar c = Calendar.getInstance();
    return c.get(Calendar.YEAR);
  }
}


This is strictly a copy-and-paste; I was intending to use this as an example of how program flow went in Java, only to be stumped in the midst of it. There's more to it, like the main() method, but some of these methods stopped me in my tracks.

For instance, the methods getHourInt(), getMinuteInt(), and getYearInt() - how and where do they get called? Why are they needed at all? I'd think that the plain old "get()" method in getTimeDateString() would be enough. And what's the point of instantiating that Calendar object in each method, as well as in the getTimeDateString() method? It doesn't appear both are needed.

Please let me know what I'm missing here!

Thanks!

Lynn.


Jay Kandy

Posts: 77
Nickname: jay
Registered: Mar, 2002

Re: How is this executed? Posted: Apr 23, 2002 2:19 PM
Reply to this message Reply
For instance, the methods getHourInt(),
getMinuteInt(), and getYearInt() - how and where do
they get called?


Since the method getTimeDateString() returns a formatted date string instead of allowing the user of the class to format in a custom manner, I assume the author hoped that the getter methods would help in formatting, without changing the code:
return getMinuteInt() + " past " + getHourInt(); 


Why are they needed at all? I'd
think that the plain old "get()" method in
getTimeDateString() would be enough.


Same reason mentioned above. Actually, it doesnt matter how many getters are in a class. What matters is how easy it is to use.

And what's the point of instantiating that Calendar object in each method, as well as in the getTimeDateString() method? It doesn't appear both are needed.
Firstly, Calendar is an abstract class. getInstance() method internally creates a GregorianCalendar with default settings-time zone and region. Now, if you were to use a class variable or instance variable, they would get initalized once. Changes to the settings while the class is running wouldnt reflect on the object. That is the most probable reason for the local variables.

Your comments?

Lynn Hollerman

Posts: 67
Nickname: gmholler
Registered: Mar, 2002

Re: How is this executed? Posted: Apr 24, 2002 7:37 AM
Reply to this message Reply
> Since the method getTimeDateString() returns a
> formatted date string instead of allowing the user of
> the class to format in a custom manner, I assume the
> author hoped that the getter methods would help in
> formatting, without changing the code:
>
> return getMinuteInt() + " past " + getHourInt();
> 


Well, just because they're there doesn't mean they have to be used. I can understand that. But there is something I don't understand that I've seen in Java, and that's when a method is executed "automatically". This came up in a course I was taking - a program had a method defined, but I couldn't find that method anywhere else in the program or any related programs to figure out just where and when it was executed. I asked my instructor, and he told me that since the method was a toString() method, it was overriding the toString() method from the Object class, and it was called "automatically", when it was needed. Fine, but when is that, in terms of before this line or after that line? If I'm going to debug the program by following the flow of it, how can I figure when(and if) something is executed? I guess what I'm asking is, are there situations in Java where a method does not have to explictly be called, and if so, when?

Thanks!

Lynn.

Matt Gerrans

Posts: 1153
Nickname: matt
Registered: Feb, 2002

Re: How is this executed? Posted: Apr 24, 2002 1:06 PM
Reply to this message Reply
Generally, GUI programs don't run sequentially, like console apps. Even console apps can be made to be event-driven and have multiple threads, in fact.

Here is a (very) partial list of some methods in Java that run "automatically" or at least seem to:

public static void main( String args ) - for applications, this method is the entry point, so you don't explicitly call it. Instead it is called on startup.

public String toString() - You can explicitly call this method or not. That is, you can do either of these things successfully:
System.out.println( someObject );
System.out.println( someObject.toString() );


init(), start(), stop(), destroy() - In an applet, these methods are called by the browser, or at least they are called as a result of browser events.

paint() - In an applet or graphical application, this method will be called when a frame needs to be redrawn.

finalize() - May or may not be called when an object is no longer referenced.

Of course there are many, many situations in Java where you create a class and never explicitly call a method in it. This is very common with listeners; you implement an interface, pass an instance of your implementation to an addListener method and it will call the method(s) you implemented at its leisure.
Another example is when you create a thread; you implement Runnable, which means writing a run method, but then you call start(), on the thread and never call run(). Of course, what happens is the Thread object does some nifty high-tech stuff to create a thread in whatever OS you are using and then calls run() in this thread.

Lynn Hollerman

Posts: 67
Nickname: gmholler
Registered: Mar, 2002

Re: How is this executed? Posted: Apr 24, 2002 1:41 PM
Reply to this message Reply
Thank you! This is what I was looking for and gives me some answers!

I understand the notion of event-driven programming, but what I was trying to get at was, what causes a particular method to be called when it's not explicitly specified? Is it the occurance of a particular event, the grace of God, the OS feels like it, it's the next line in the program, what? Like a paint() method, for instance - I have seen many programs that just include a paint method, it's not called anywhere, it's just there. Let's say I'm trying to explain the execution of this program - before or after what event do I say the paint() method is called, if it's not explictly called - or do I just say something is painted or repainted as the program sees fit?

I must be missing something crucial. If I'm the programmer, I'm the one that tells the program what to do, not the other way around! Could/Would a Java program "know" that it needs to execute a certain method?

Thanks again!

Lynn.

Matt Gerrans

Posts: 1153
Nickname: matt
Registered: Feb, 2002

Re: How is this executed? Posted: Apr 24, 2002 5:00 PM
Reply to this message Reply
It is a funny thing -- programming in languages like Java remove you from a lot of the "bare metal" stuff that goes on below, but you have to kind of accept these kind of mysteries. Even in C++, using MFC or Borland's C++ Builder, you are kind of removed from the lower-level things (unless you choose to seek them out).

Even though writing a Windows program in the old-fashioned bare-bones C API is a lot more painful than using any of the modern tools and techniques, it does allow you to better understand what is going on. What you do is this: you write a main function (called WinMain()). In this, you set up some data structures and whatnot and register a callback function (pointer to a function in C, analogous to passing an implementation of some interface in Java or a delegate in C#). Then you start a (kind of) infinite loop where you call GetMessage() and DispatchMessage(), like this:
// The event handler callback.
WindowEventHandler( HWND windowHandle, Event event... )
{
   switch( event )
   {
      case WM_RESIZE:
         recalcControPositions();
         break;
      //...
   }
}
 
// The main entry point.
WinMain()
{
   WNDCLASS windowClass;
   windowClass.lpfnWndProc = WindowEventHandler;
   HWND windowHandle = CreateWindow( &windowClass, ... );
 
   while( GetMessage( &msg, ... ) )
   {
      DispatchMessage( &msg );
   }
}
 

(for those old Windows programmers, yes I know there is a TranslateMessage() in there, but I've omitted it for simplicity. You'll also notice that this is very much pseudo code and paraphrased.)

Since you've already registered your callback, you can imagine that it works kind of like this:
- GetMessage() looks at the various input (mouse, keyboard, modem, etc.) devices and the system for messages and puts them in a queue. If the next message is anything other than "quit" it will return "true" (meaning "keep on running") and put the message in the msg parameter.
- Inside the loop, you call DispatchMessage(), which among other things, will call into your callback function with the message.

This is probably clear as mud, but the idea is that you can see how the thread of execution goes back and forth between your code and the Windows code. If you never called DispatchMessage(), your callback would never get called.

Similar things happen in a Java program, it is just that you are more insulated from it. I don't know for sure about the Java internals, but I'd guess that when you create an Applet or JFrame, it starts up all this stuff in a new Thread in its constructor and that Thread's run() contains some sort of message loop. Instead of calling registered callbacks, it just calls its own methods (like paint()), which can be overridden by classes which extend it.

Here is the source of a raw Windows program, for complete accuracy:
//--------------------------------------------------------------------
// Matt Gerrans
// December 1997
//
// Skeleton app with Tray Icon capability.
//--------------------------------------------------------------------
 
#include <shlobj.h>
#include "Skeleton.h"
#include <windowsx.h>
#include "resource.h"
 
//--------------------------------------------------------------------
//                         Local functions:
//--------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    LPSTR lpszCmdLine, int nCmdShow);
long FAR PASCAL MainWindowMessageHandler( HWND, UINT, UINT, LONG );
#define MYWM_NOTIFYICON         (WM_APP+100)
 
//--------------------------------------------------------------------
//                         Globals (ugh!):
//--------------------------------------------------------------------
HINSTANCE _hinst;
static char _pszIniFile[MAXLEN+1];
static UINT _nOptions;
static char _pszAppName[MAXLEN+1];
 
//--------------------------------------------------------------------
//                            WinMain()
//--------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,    //)
                    LPSTR lpszCmdLine, int nCmdShow)
{
   MSG         msg;
   HWND        hwnd;
   WNDCLASS    wndclass;
   _hinst = hInstance;
 
   ProcessCommandLine( lpszCmdLine );
 
   _hinst = hInstance;  // Is there a better way???
   // Yes there is a better way: pack in in the window extra data!
 
   LoadString( _hinst, IDS_APPNAME, _pszAppName, MAXLEN );
 
   // Prevent multiple instances:
   HANDLE hMutex = CreateMutex( NULL, TRUE, _pszAppName );
   if( GetLastError() == ERROR_ALREADY_EXISTS )
   {
      // Could show an "I'm already running" message here.
      return 0;
   }
 
   if (!hPrevInstance) 
   {
      wndclass.style         = CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc   = MainWindowMessageHandler;
      wndclass.cbClsExtra    = 0;
      wndclass.cbWndExtra    = 0;
      wndclass.hInstance     = _hinst;
      wndclass.hIcon         = LoadIcon(_hinst, _pszAppName);
      wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
      wndclass.lpszMenuName  = _pszAppName;
      wndclass.lpszClassName = _pszAppName;
 
      RegisterClass(&wndclass) ;
   }
 
   hwnd = CreateWindow( _pszAppName, _pszAppName,
                        WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        CW_USEDEFAULT, CW_USEDEFAULT,
                        NULL, NULL, _hinst, NULL) ;
 
//   ShowWindow(hwnd, SW_HIDE ) ; // mfg: Invisible app!
   UpdateWindow(hwnd); 
 
   while( GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg) ;
      DispatchMessage(&msg) ;
   }
 
   ReleaseMutex( hMutex ); // Important!
   CloseHandle( hMutex );  // This one is not strictly necessary as the mutex
                           // will be automatically closed upon the app's
                           // termination.
 
   return msg.wParam;
}
 
//--------------------------------------------------------------------
//                    MainWindowMessageHandler()
//
// A well-designed message-handler function is lean and mean; it
// calls other functions and procedures to do most work.   This way,
// it doesn't become too large and cluttered.
//--------------------------------------------------------------------
long FAR PASCAL MainWindowMessageHandler( HWND hwnd, UINT wMessage,   //)
                                          UINT wParam, LONG lParam )
{
#ifdef _DEBUG
   char sMsg[256];
#endif
 
   switch(wMessage)
   {
      case WM_CREATE:
         //_nOptions = GetOptions( _hinst );
         //SetupTrayIcon( hwnd, _hinst );
         /*
         char sMsg[256];
         wsprintf( sMsg, "sizeof(WPARAM) is %d, sizeof(LPARAM) is %d", 
                   (int)sizeof(WPARAM), (int)sizeof(LPARAM) );
         MessageBox( NULL, sMsg, "Info", MB_OK|MB_SYSTEMMODAL);
         // ...Both are 4 bytes!!!
         */
         return 0;
 
      case WM_COMMAND:
         switch(wParam)
         {
            default:
               break;
         }
         break;
 
      case MYWM_NOTIFYICON:
         switch (lParam)
         {
            case WM_LBUTTONDBLCLK:
               break;
 
            case WM_LBUTTONDOWN:               
               break;
 
            case WM_RBUTTONDOWN:
               // *** Show the menu! ***
               break;
 
            case WM_RBUTTONDBLCLK:
               break;
 
            default:
               break;
         }
         break;
 
      case WM_CLOSE:
         if( CloseConfirmed(_hinst) )
         {
            DestroyWindow(hwnd);
            return 0;
         }
         else
            return 0;
 
      case WM_DESTROY:
         //RemoveIconFromTray( hwnd );
         PostQuitMessage(0);
         return 0;
   }
   return DefWindowProc( hwnd, wMessage, wParam, lParam );
}
 
//--------------------------------------------------------------------
//                         SetupTrayIcon()
//--------------------------------------------------------------------
void SetupTrayIcon( HWND hwnd, HINSTANCE hinst )
{
   NOTIFYICONDATA icondata;
 
   icondata.cbSize              = sizeof(NOTIFYICONDATA);
   icondata.hWnd                = hwnd;
   icondata.uID                 = IDI_SKELETON; 
   icondata.uFlags              = NIF_MESSAGE | NIF_ICON | NIF_TIP;
   icondata.uCallbackMessage    = MYWM_NOTIFYICON;
   icondata.hIcon               = LoadIcon( hinst, _pszAppName );
 
   LoadString( hinst, IDS_TOOLTIP, icondata.szTip, MAXLEN );
 
   Shell_NotifyIcon( NIM_ADD, &icondata );
 
   // What's this?
   if( icondata.hIcon )
      DestroyIcon( icondata.hIcon );
}
 
//--------------------------------------------------------------------
//                        RemoveIconFromTray()
//--------------------------------------------------------------------
void RemoveIconFromTray( HWND hwnd )
{
   NOTIFYICONDATA icondata;
   
   // Delete the icon from the tray!
   icondata.cbSize              = sizeof(NOTIFYICONDATA);
   icondata.hWnd                = hwnd;
   icondata.uID                 = IDI_SKELETON; 
   Shell_NotifyIcon( NIM_DELETE, &icondata) ;
}
 
//--------------------------------------------------------------------
//                           GetOptions()
//--------------------------------------------------------------------
UINT GetOptions( HINSTANCE hinst, SAppOptions & sAppOptions )
{
   char  pszSection[MAXLEN+1],
//         pszItem[MAXLEN+1],
         pszIniFile[MAXLEN+1];
   
   GetIniFile( hinst, pszIniFile );
   LoadString( hinst, IDS_APPINFO_SECTION, pszSection, MAXLEN );
 
   // for each option...
   //LoadString( hinst, IDS_OPTION, pszItem, MAXLEN );
   //GetPrivateProfileInt( pszSection, pszItem, 0, pszIniFile );
 
   return 0;
}
 
//--------------------------------------------------------------------
//                           SetOptions()
//--------------------------------------------------------------------
void SetOptions( HINSTANCE hinst, SAppOptions sAppOptions )
{
   char  pszSection[MAXLEN+1],
//         pszItem[MAXLEN+1],
//         pszOptions[20],
         pszIniFile[MAXLEN+1];
   
   GetIniFile( hinst, pszIniFile );
   LoadString( hinst, IDS_APPINFO_SECTION, pszSection, MAXLEN );
 
   // for each option...
   //LoadString( hinst, IDS_TRAY, pszItem, MAXLEN );
   //WritePrivateProfileString( pszSection, pszItem, pszOptions, pszIniFile );
}
 
//--------------------------------------------------------------------
//                            GetIniFile()
//
// If there is a command line specifying an ini file, it will be used.
// Otherwise it is assumed that the ini file will be in the same 
// directory as the exe and will have the same filename with an
// extension of "INI" rather than "EXE."   Yes, that does mean that
// if you rename "SKELETON.EXE," to "BUD.EXE," it will look for 
// "BUD.INI."   This nifty feature allows you to run multple icons
// in the tray from the same directory without specifying command
// line parameters.
//--------------------------------------------------------------------
void GetIniFile( HINSTANCE hinst, char * pszIniFile )
{
   if( strlen( _pszIniFile ) )
      strcpy( pszIniFile, _pszIniFile );
   else
   {
      // Get the ini file name with these assumptions:
      // 1. The ini file is in the same directory as the program.
      // 2. The ini files has the same name as the exe ("Skeleton" - 
      //    unless it was renamed).
 
      GetModuleFileName( hinst, pszIniFile, MAXLEN );
   }
 
   // Now, change the EXE extension to INI:
   strcpy( pszIniFile+strlen(pszIniFile)-3, "INI" );
 
#ifdef _DEBUG
   MessageBox( NULL, pszIniFile, "Here's the ini file name:", MB_OK );
#endif                           
}
 
//--------------------------------------------------------------------
//                            CloseConfirmed()
//--------------------------------------------------------------------
BOOL CloseConfirmed( HINSTANCE hinst )
{
   char pszAreYouSure[MAXLEN+1], 
        pszTitle[MAXLEN+1];
   UINT uResponse = IDNO,
        uMsgOptions = MB_YESNO | MB_ICONQUESTION | MB_SYSTEMMODAL;
 
   LoadString( hinst, IDS_CONFIRMCLOSE, pszAreYouSure, MAXLEN );
   LoadString( hinst, IDS_CLOSETITLE, pszTitle, MAXLEN );
 
   uResponse = MessageBox( NULL, pszAreYouSure, pszTitle, uMsgOptions );
 
   return (uResponse == IDYES ? TRUE : FALSE );
}
 
//--------------------------------------------------------------------
//                       ProcessCommandLine()
//--------------------------------------------------------------------
int  ProcessCommandLine( const char * lpszCmdLine )
{
   char sCmdLine[MAXLEN+1], * pCmd;
   strcpy( sCmdLine, lpszCmdLine );   
 
   pCmd = strtok( sCmdLine, " " );
 
   while( pCmd )
   {
      // Build an array of command line items:
      // MyStringArrary += pCmd;
      pCmd = strtok( NULL, " " );
   }
   // Process the array...
 
   return 0;
}

Lynn Hollerman

Posts: 67
Nickname: gmholler
Registered: Mar, 2002

Re: How is this executed? Posted: Apr 25, 2002 8:17 AM
Reply to this message Reply
Thank you again! Being an old FORTRAN/COBOL programmer, I am just not used to having things programmed for me - like the Java API! I have to resist the urge to re-invent the wheel at every turn!

Lynn.

Flat View: This topic has 6 replies on 1 page
Topic: How do I get <url-pattern> of a servlet ? Previous Topic   Next Topic Topic: php and Java2 in win2k

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use