Wednesday, 26 March 2014

Paint Shapes - Paint With File-Handling

As promised, we are back with a whole new Paint Applet, this time using javax.swing and JFrame. If you havent seen our previous attempt at the Paint Brush Applet, you can view it here. The bugs that we encountered last time have been somewhat solved in this applet.

First of all, the output looks something like this:

As you can see, one can draw rectangle, round rectangle and ovals to their file. The applet provides facility to save their file, rename it, save it in a different location and to view saved files. 

You can view the actual source code here. We have tried our best to comment wherever necessary. Still, if you have any doubts or any kind of ambiguity, please feel free to leave a comment: 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
import java.io.*;
@SuppressWarnings("serial")
public class Paint2 extends JFrame {
public static void main(String[] args) {
new Paint2();
}
String fileName;
JCheckBoxMenuItem addLargeShapes; // Controls whether newly added
// shapes will be large or small.
JCheckBoxMenuItem addBorderedShapes; // Controls whether newly added
// will have a black border.
JRadioButtonMenuItem red, green, blue, // Control the color
cyan, magenta, yellow, // of newly added shapes.
black, gray, white;
JPopupMenu popup; // The pop-up menu, which is used for editing shapes.
public Paint2() {
super("Paint - Tejash Desai");
/* Create the "canvas" which displays the shapes and serves as
the content pane of the frame. */
ShapeCanvas canvas = new ShapeCanvas();
setContentPane(canvas);
/* Create the menu bar and the menus */
JMenuBar menubar = new JMenuBar();
setJMenuBar(menubar);
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic('F');
menubar.add(fileMenu);
JMenu addShapeMenu = new JMenu("Add Shapes");
addShapeMenu.setMnemonic('A');
menubar.add(addShapeMenu);
JMenu shapeColorMenu = new JMenu("Edit Color");
shapeColorMenu.setMnemonic('E');
menubar.add(shapeColorMenu);
JMenu optionsMenu = new JMenu("Options");
optionsMenu.setMnemonic('O');
menubar.add(optionsMenu);
//the file menu
JMenuItem newCmd = new JMenuItem("New");
newCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl N") );
newCmd.addActionListener(canvas);
fileMenu.add(newCmd);
JMenuItem openCmd = new JMenuItem("Open...");
openCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl O") );
openCmd.addActionListener(canvas);
fileMenu.add(openCmd);
JMenuItem saveCmd = new JMenuItem("Save...");
saveCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl S") );
saveCmd.addActionListener(canvas);
fileMenu.add(saveCmd);
JMenuItem quitCmd = new JMenuItem("Quit");
quitCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl Q") );
quitCmd.addActionListener(canvas);
fileMenu.add(quitCmd);
//the Add menu
JMenuItem rect = new JMenuItem("Rectangle");
rect.setAccelerator( KeyStroke.getKeyStroke("ctrl R") );
addShapeMenu.add(rect);
rect.addActionListener(canvas);
JMenuItem oval = new JMenuItem("Oval");
oval.setAccelerator( KeyStroke.getKeyStroke("ctrl V") );
addShapeMenu.add(oval);
oval.addActionListener(canvas);
JMenuItem roundrect = new JMenuItem("Round Rect");
roundrect.setAccelerator( KeyStroke.getKeyStroke("ctrl D") );
addShapeMenu.add(roundrect);
roundrect.addActionListener(canvas);
/* The color menu. A ButtonGroup is used
to make sure that only one color is selected. */
ButtonGroup colorGroup = new ButtonGroup();
red = new JRadioButtonMenuItem("Red");
shapeColorMenu.add(red);
colorGroup.add(red);
red.setSelected(true);
green = new JRadioButtonMenuItem("Green");
shapeColorMenu.add(green);
colorGroup.add(green);
blue = new JRadioButtonMenuItem("Blue");
shapeColorMenu.add(blue);
colorGroup.add(blue);
cyan = new JRadioButtonMenuItem("Cyan");
shapeColorMenu.add(cyan);
colorGroup.add(cyan);
magenta = new JRadioButtonMenuItem("Magenta");
shapeColorMenu.add(magenta);
colorGroup.add(magenta);
yellow = new JRadioButtonMenuItem("Yellow");
shapeColorMenu.add(yellow);
colorGroup.add(yellow);
black = new JRadioButtonMenuItem("Black");
shapeColorMenu.add(black);
colorGroup.add(black);
gray = new JRadioButtonMenuItem("Gray");
shapeColorMenu.add(gray);
colorGroup.add(gray);
white = new JRadioButtonMenuItem("White");
shapeColorMenu.add(white);
colorGroup.add(white);
/* Create the "Clear" menu item, and add it to the
"Options" menu. The canvas will listen for events
from this menu item. */
JMenuItem clear = new JMenuItem("Clear");
clear.setAccelerator( KeyStroke.getKeyStroke("ctrl C") );
clear.addActionListener(canvas);
optionsMenu.add(clear);
optionsMenu.addSeparator(); // Add a separating line to the menu.
addLargeShapes = new JCheckBoxMenuItem("Add Large Shapes");
addLargeShapes.setSelected(true);
optionsMenu.add(addLargeShapes);
addBorderedShapes = new JCheckBoxMenuItem("Add Shapes with Border");
addBorderedShapes.setSelected(true);
optionsMenu.add(addBorderedShapes);
optionsMenu.addSeparator();
/* Create a menu for background colors.*/
JMenu background = new JMenu("Background Color");
optionsMenu.add(background); // in the above cases, we used to add JMenuItem to a JMenu
//here, we add a JMenu to another JMenu creating a heirarchial menu
background.add("Red").addActionListener(canvas);
background.add("Green").addActionListener(canvas);
background.add("Blue").addActionListener(canvas);
background.add("Cyan").addActionListener(canvas);
background.add("Magenta").addActionListener(canvas);
background.add("Yellow").addActionListener(canvas);
background.add("Black").addActionListener(canvas);
background.add("Gray").addActionListener(canvas);
background.add("White").addActionListener(canvas);
/* Create the pop-up menu and add commands for editing a
shape. This menu is not used until the user performs
the pop-up trigger mouse gesture on a shape. */
popup = new JPopupMenu();
popup.add("Delete Shape").addActionListener(canvas);
popup.addSeparator();
popup.add("Bring to Front").addActionListener(canvas);
popup.addSeparator();
popup.add("Make Large").addActionListener(canvas);
popup.add("Make Small").addActionListener(canvas);
popup.addSeparator();
popup.add("Add Black Border").addActionListener(canvas);
popup.add("Remove Black Border").addActionListener(canvas);
popup.addSeparator();
popup.add("Set Color to Red").addActionListener(canvas);
popup.add("Set Color to Green").addActionListener(canvas);
popup.add("Set Color to Blue").addActionListener(canvas);
popup.add("Set Color to Cyan").addActionListener(canvas);
popup.add("Set Color to Magenta").addActionListener(canvas);
popup.add("Set Color to Yellow").addActionListener(canvas);
popup.add("Set Color to Black").addActionListener(canvas);
popup.add("Set Color to Gray").addActionListener(canvas);
popup.add("Set Color to White").addActionListener(canvas);
setDefaultCloseOperation(EXIT_ON_CLOSE);
/* Set the size and location of the frame. */
setLocation(20,50);
setSize(550,420);
setVisible(true);
} // end constructor
//---- Nested class definitions ---
//
// These are just like regular classes, except that they are defined inside
// another class (and hence have full names, when used outside this class, such
// as ShapeDraw.ShapeCanvas).
class ShapeCanvas extends JPanel
implements ActionListener, MouseListener, MouseMotionListener {
ArrayList shapes = new ArrayList();
// holds a list of the shapes that are displayed on the canvas
ShapeCanvas() {
setBackground(Color.white);
addMouseListener(this);//for right-clicking components and choosing options like "Bring to front"
addMouseMotionListener(this);//to drag components in the screen
}
public void paintComponent(Graphics g) {
super.paintComponent(g); // First, fill with background color.
int top = shapes.size();
for (int i = 0; i < top; i++) {
Shape s = (Shape)shapes.get(i);
s.draw(g);
}
}
public void actionPerformed(ActionEvent evt) {
// Called to respond to action events from the
// menus or pop-up menu.
String command = evt.getActionCommand();
if (command.equals("New")) {
//the "new" command doesn't open a new file. It just clears the current file.
//it is somewhat similar to "clear" command
shapes.clear(); // Remove all items
setBackground(Color.white); // Clear to white.
}
else if (command.equals("Open...")) {
openFile();//call the custom open function
}
else if (command.equals("Save...")) {
saveFile();//call the custom save function
}
else if (command.equals("Quit")) {
System.exit(0);//system is exited either when Quit is pressed or when window is closed
}
else if (command.equals("Clear")) {
shapes.clear();
//this is the difference b/w new and clear command. new doesn't call the paint() again.
repaint();
}
else if (command.equals("Rectangle"))
addShape(new RectShape());
else if (command.equals("Oval"))
addShape(new OvalShape());
else if (command.equals("Round Rect"))
addShape(new RoundRectShape());
else if (command.equals("Red"))
setBackground(Color.red);
else if (command.equals("Green"))
setBackground(Color.green);
else if (command.equals("Blue"))
setBackground(Color.blue);
else if (command.equals("Cyan"))
setBackground(Color.cyan);
else if (command.equals("Magenta"))
setBackground(Color.magenta);
else if (command.equals("Yellow"))
setBackground(Color.yellow);
else if (command.equals("Black"))
setBackground(Color.black);
else if (command.equals("Gray"))
setBackground(Color.gray);
else if (command.equals("White"))
setBackground(Color.white);
else if (clickedShape != null) {
// Process a command from the pop-up menu.
if (command.equals("Delete Shape"))
shapes.remove(clickedShape);
else if (command.equals("Bring to Front")) {
/*Suppose we have a rectangle over a circle. If we remove the circle and then
* add it again after the rectangle, it will produce the effect of "bringing to front"
*/
shapes.remove(clickedShape);//removes the first occurrence of clickedShape
shapes.add(clickedShape); //adds clickedShape to the end of the ArrayList
}
else if (command.equals("Make Large"))
clickedShape.setSize(100,60);
else if (command.equals("Make Small"))
clickedShape.setSize(50,30);
else if (command.equals("Add Black Border"))
clickedShape.setDrawOutline(true);
else if (command.equals("Remove Black Border"))
clickedShape.setDrawOutline(false);
else if (command.equals("Set Color to Red"))
clickedShape.setColor(Color.red);
else if (command.equals("Set Color to Green"))
clickedShape.setColor(Color.green);
else if (command.equals("Set Color to Blue"))
clickedShape.setColor(Color.blue);
else if (command.equals("Set Color to Cyan"))
clickedShape.setColor(Color.cyan);
else if (command.equals("Set Color to Magenta"))
clickedShape.setColor(Color.magenta);
else if (command.equals("Set Color to Yellow"))
clickedShape.setColor(Color.yellow);
else if (command.equals("Set Color to Black"))
clickedShape.setColor(Color.black);
else if (command.equals("Set Color to Gray"))
clickedShape.setColor(Color.gray);
else if (command.equals("Set Color to White"))
clickedShape.setColor(Color.white);
repaint();//paint function will draw all the shapes in the ArrayList
}
}
void addShape(Shape shape) {
if (red.isSelected())
shape.setColor(Color.red);
else if (blue.isSelected())
shape.setColor(Color.blue);
else if (green.isSelected())
shape.setColor(Color.green);
else if (cyan.isSelected())
shape.setColor(Color.cyan);
else if (magenta.isSelected())
shape.setColor(Color.magenta);
else if (yellow.isSelected())
shape.setColor(Color.yellow);
else if (black.isSelected())
shape.setColor(Color.black);
else if (white.isSelected())
shape.setColor(Color.white);
else
shape.setColor(Color.gray);
shape.setDrawOutline( addBorderedShapes.isSelected() );
if (addLargeShapes.isSelected())
shape.reshape(3,3,100,60);
else
shape.reshape(3,3,50,30);
shapes.add(shape);
repaint();
}
// --------------- File-related methods for opening and saving --------------------------
void saveFile() {
File file; // The file that the user wants to save.
JFileChooser fd; // A file dialog that let's the user specify the file.
fd = new JFileChooser("."); // Open on current directory. ".." argument will open on the directory above the current one.
fd.setDialogTitle("Save As File...");
int action = fd.showSaveDialog(this);
if (action != JFileChooser.APPROVE_OPTION) {
// User has canceled, or an error occurred.
return;
}
file = fd.getSelectedFile();
fileName = file.getName();
if (file.exists()) {
// If file already exists, ask before replacing it.
action = JOptionPane.showConfirmDialog(this, "Replace existing file?");
if (action != JOptionPane.YES_OPTION)
return;
}
try {
ObjectOutputStream out =
new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(getBackground());//we first save the background color as an object
out.writeObject(shapes);//we then save the entire ArrayList shapes as an object. Remember that ArrayList extends Object class.
out.close();
}
catch (IOException e) {
JOptionPane.showMessageDialog(this,
"Error while trying to write the file:\n" + e.getMessage());
}
} // end saveFile()
void openFile() {
File file; // The file that the user wants to open.
JFileChooser fd; // A file dialog that let's the user specify the file.
fd = new JFileChooser("."); // Open on current directory.
fd.setDialogTitle("Open File...");
int action = fd.showOpenDialog(this);
if (action != JFileChooser.APPROVE_OPTION) {
// User canceled the dialog, or an error occurred.
return;
}
file = fd.getSelectedFile();
fileName = file.getName();
Object obj1; // Object to be read from file. Should be a color. Because we saved the file that way.
Object obj2; // Second object. Should be an ArrayList of shapes. Because we saved the file that way.
try {
ObjectInputStream in =
new ObjectInputStream(new FileInputStream(file));
obj1 = in.readObject();//obj1 now has the bgColor
obj2 = in.readObject();//obj2 now has the list shapes
in.close();
}
catch (IOException e) {
JOptionPane.showMessageDialog(this,
"Error while trying to read the file:\n" + e.getMessage());
return;
}
catch (Exception e) {
JOptionPane.showMessageDialog(this,
"Unexpected Data type found in file:\n" + e.getMessage());
return;
}
try {
setShapes(obj1,obj2);
}
catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(this,
"File did not contain legal data for this program.");
}
} // end openFile()
private void setShapes(Object backgroundColor,Object newShapes)
throws IllegalArgumentException {
// Throws IllegalArgumentException if objects are not of
// of the correct types.
if (backgroundColor == null || !(backgroundColor instanceof Color))
/*Note the use of the keyword instanceof
* Basically, you check if an object is an instance of a specific class.
* You normally use it, when you have a reference or parameter to an object that is of a
* super class or interface type and need to know whether the actual object has some other type (normally more concrete).
*/
throw new IllegalArgumentException(
"Invalid data types in file.");
if (newShapes == null || !(newShapes instanceof ArrayList))
throw new IllegalArgumentException(
"Invalid data type. Expecting list of shapes.");
ArrayList v = (ArrayList)newShapes;
for (int i = 0; i < v.size(); i ++)
if (!(v.get(i) instanceof Shape))
//if v.get(i) is not a valid shape, it is invalid. Therefore, throw exception.
throw new IllegalArgumentException("Invalid data type in shape list.");
shapes = v;
setBackground((Color)backgroundColor);
}
// -------------------- This rest of this class implements dragging ----------------------
Shape clickedShape = null; // This is the shape that the user clicks on.
// It becomes the draggedShape if the user is
// dragging, unless the user is invoking a
// pop-up menu. This variable is used in
// actionPerformed() when a command from the
// pop-up menu is processed.
Shape draggedShape = null; // This is null unless a shape is being dragged.
// A non-null value is used as a signal that dragging
// is in progress, as well as indicating which shape
// is being dragged.
int prevDragX; // During dragging, these record the x and y coordinates of the
int prevDragY; // previous position of the mouse.
public void mousePressed(MouseEvent evt) {
if (draggedShape != null) {
// A drag operation is already in progress, so ignore this click.
// This might happen if the user clicks a second mouse button before
// releasing the first one(?).
return;
}
int x = evt.getX(); // x-coordinate of point where mouse was clicked
int y = evt.getY(); // y-coordinate of point
clickedShape = null; // This will be set to the clicked shape, if any.
for ( int i = shapes.size() - 1; i >= 0; i-- ) {
// Check shapes from front to back. This loop will determine which shape is clicked.
Shape s = (Shape)shapes.get(i);
if (s.containsPoint(x,y)) {
clickedShape = s;
break;
}
}
if (clickedShape == null) {
// The user did not click on a shape.
return;
}
else if (evt.isPopupTrigger()) //Returns whether or not this mouse event is the popup menu trigger event for the platform.
//Note: Popup menus are triggered differently on different systems.
//Therefore, isPopupTrigger should be checked in both mousePressed and mouseReleased for proper cross-platform functionality.
{
// The user wants to see the pop-up menu
popup.show(this,x-10,y-2);
}
else {
draggedShape = clickedShape;
prevDragX = x;
prevDragY = y;
}
//Note: no repaint() is mentioned, as there are no components which are changed.
}
public void mouseDragged(MouseEvent evt) {
if (draggedShape == null) {
// User did not click a shape. There is nothing to do.
return;
}
int x = evt.getX();
int y = evt.getY();
draggedShape.moveBy(x - prevDragX, y - prevDragY);
prevDragX = x;
prevDragY = y;
repaint(); // redraw canvas to show shape in new position
}
public void mouseReleased(MouseEvent evt) {
if (draggedShape == null) {
// User did not click on a shape. There is nothing to do.
return;
}
int x = evt.getX();
int y = evt.getY();
if (evt.isPopupTrigger()) {
// Check whether the user is trying to pop up a menu.
// As mentioned above, this should be checked in both the mousePressed() and
// mouseReleased() methods for cross-platform functionality.
popup.show(this,x-10,y-2);
}
else {
draggedShape.moveBy(x - prevDragX, y - prevDragY);
if ( draggedShape.left >= getSize().width || draggedShape.top >= getSize().height ||
draggedShape.left + draggedShape.width < 0 ||
draggedShape.top + draggedShape.height < 0 ) { // shape is off-screen
shapes.remove(draggedShape); // remove shape from list of shapes
}
repaint();
}
draggedShape = null; // Dragging is finished.
}
public void mouseEntered(MouseEvent evt) { } // Default methods for MouseListener and MouseMotionListener
public void mouseExited(MouseEvent evt) { } // They are programmed to do nothing.
public void mouseMoved(MouseEvent evt) { }
public void mouseClicked(MouseEvent evt) { }
} // end class ShapeCanvas
// ------- Nested class definitions for the abstract Shape class and three -----
// -------------------- concrete subclasses of Shape. --------------------------
static abstract class Shape implements Serializable {
// A class representing shapes that can be displayed on a ShapeCanvas.
// The subclasses of this class represent particular types of shapes.
// When a shape is first constructed, it has height and width zero
// and a default color of white.
int left, top; // Position of top left corner of rectangle that bounds this shape.
int width, height; // Size of the bounding rectangle.
Color color = Color.white; // Color of this shape.
boolean drawOutline; // If true, a black border is drawn on the shape
void reshape(int left, int top, int width, int height) {
// Set the position and size of this shape.
this.left = left;
this.top = top;
this.width = width;
this.height = height;
}
void setSize(int width, int height) {
// Set the size of this shape
this.width = width;
this.height = height;
}
void moveBy(int dx, int dy) {
// Move the shape by dx pixels horizontally and dy pixels vertically
// (by changing the position of the top-left corner of the shape).
left += dx;
top += dy;
}
void setColor(Color color) {
// Set the color of this shape
this.color = color;
}
void setDrawOutline(boolean draw) {
// If true, a black outline is drawn around this shape.
drawOutline = draw;
}
boolean containsPoint(int x, int y) {
// Check whether the shape contains the point (x,y).
// This method should be
// overridden by a subclass if the default behavior is not
// appropriate for the subclass.
if (x >= left && x < left+width && y >= top && y < top+height)
return true;
else
return false;
}
abstract void draw(Graphics g);
// Draw the shape in the graphics context g.
// This must be overridden in any concrete subclass.
} // end of class Shape
static class RectShape extends Shape {
// This class represents rectangle shapes.
void draw(Graphics g) {
g.setColor(color);
g.fillRect(left,top,width,height);
if (drawOutline) {
g.setColor(Color.black);
g.drawRect(left,top,width,height);
}
}
}
static class OvalShape extends Shape {
// This class represents oval shapes.
void draw(Graphics g) {
g.setColor(color);
g.fillOval(left,top,width,height);
if (drawOutline) {
g.setColor(Color.black);
g.drawOval(left,top,width,height);
}
}
boolean containsPoint(int x, int y) {
// Check whether (x,y) is inside this oval, using the
// mathematical equation of an ellipse.
double rx = width/2.0; // horizontal radius of ellipse
double ry = height/2.0; // vertical radius of ellipse
double cx = left + rx; // x-coord of center of ellipse
double cy = top + ry; // y-coord of center of ellipse
if ( (ry*(x-cx))*(ry*(x-cx)) + (rx*(y-cy))*(rx*(y-cy)) <= rx*rx*ry*ry )
return true;
else
return false;
}
}
static class RoundRectShape extends Shape {
// This class represents rectangle shapes with rounded corners.
// (Note that it uses the inherited version of the
// containsPoint(x,y) method, even though that is not perfectly
// accurate when (x,y) is near one of the corners.)
void draw(Graphics g) {
g.setColor(color);
g.fillRoundRect(left,top,width,height,width/3,height/3);
if (drawOutline) {
g.setColor(Color.black);
g.drawRoundRect(left,top,width,height,width/3,height/3);
}
}
}
} // end class ShapeDrawFrame
view raw gistfile1.txt hosted with ❤ by GitHub

BUGS AND HOW THEY ARE SOLVED:

Now we will show how the 3 bugs mentioned in Paint Brush Applet are solved.


  1. The shapes that are added do not now disappear when paint() is called again (implicitely and explicitely). This is because all shapes are stored in an ArrayList of the name "shapes". The paint function simply draws all the shapes in the list again, thus losing none!
  2.  File Handling concepts are used to store and open files. Note that the files thus created do not have any extensions like .jpg, etc. and are thus read by the Windows System as of the type "file". It cannot be rendered effectively by any application other than this applet. Results may/may not be different in Linux-based systems because of its "Everything is a file" policy.
  3.  The "drawing area" is defined separately and does not include the menu bar, thus solving this error.

Saturday, 15 March 2014

Basic Calculator Applet


After about 1-2 days of work, I finally created a Java Applet of a simple binary calculator which performs binary operations on positive numbers. The main aim was to solve using this calculator an expression like:
32+45/89*6 = 5.19101

from left-to-right, step by step i.e. computing two variables at a time.(so you enter 32 + 45 = and the result (77) then becomes your first operand)
basic binary calculator using java.applet class

The idea was not to give a demonstration of the calculator algorithm, but to show the use of the applet class and the basic components like buttons, text fields, etc. Thus, this can be the ideal code for anyone who is planning to make a small project using java applet class. The functions and the overall view and flow of the code is deliberately made very simple so that even those who are not-so-experienced with applets can understand.
I encourage the readers to go through the code and mail/leave a comment if you have doubts, suggestions or if you made an improvised version of the code!


import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;
@SuppressWarnings("serial")
public class CalculatorApplet extends Applet implements ActionListener{
char operator = ' ';
Font font = new Font(Font.SANS_SERIF, Font.BOLD, 20);
boolean firstVarOver = false; //checks whether the first variable entering is completed
boolean isBckspAble = true; //checks whether Back Space is allowed. Back Space is not allowed on the final result, as the result isnt editable, its computed.
float result;
int whichVar = 0; // whichVar will point the variable number currently processed. Since its a binary calculator, whichVar can be either 1 or 2
String var[] = {"","",""}; // here variable is a string array because only string can be uploaded on the text field.
TextField textField = new TextField("");
Button numberButton[] = new Button[10]; //There is an array of 10 numbers
Button operatorButton[] = new Button[4];
Button specialButton[] = new Button[3];
Button equal = new Button("=");
Button zero = new Button("0");
String operatorArray[] = new String[]{"+", "-", "*", "/"};
String specialArray[] = new String[] {"<-", "C", "."};
public void init(){
setLayout(null);
setSize(67*4, 53*6); // the values 67*53 are the dimensions of each button; chosen after trial-and-error
textField.setBounds(0,0,67*4,53);
textField.setEnabled(false);
add(textField);
setUpButtons();
}
//this function will draw all the buttons on the screen and assign them labels
public void setUpButtons(){
int x = -67;
int y = 53*2;
Button thisButton;
//add the number buttons
for (int i = 1; i < 10; i++) {
if(x >= 67*2){ //only 3 buttons in a row
y += 53;
x = -67;
}
thisButton = new Button(Integer.toString(i));
thisButton.setBounds(x+67, y, 67, 53);
thisButton.addActionListener(this);
x += 67;
thisButton.setBackground(Color.green);
thisButton.setForeground(Color.red);
thisButton.setFont(font);
numberButton[i] = thisButton;
add(thisButton);
}
//add 0
zero.setBounds(67*0, 53, 67, 53);
zero.setBackground(Color.green);
zero.setForeground(Color.red);
zero.addActionListener(this);
zero.setFont(font);
add(zero);
//add operator buttons
for (int i = 0; i < 4; i++) {
thisButton = new Button(operatorArray[i]);
thisButton.setBounds(67*i, 53*5, 67, 53); //it is the 5th row, and the operators are in the ith column
thisButton.addActionListener(this);
thisButton.setBackground(Color.blue);
thisButton.setForeground(Color.white);
thisButton.setFont(font);
operatorButton[i] = thisButton;
add(thisButton);
}
//add equal-to button
equal.setBounds(67*3, 53*2, 67, 53*3); //it is in the last column and is 3 columns worth in height
equal.setBackground(Color.red);
equal.setForeground(Color.white);
equal.addActionListener(this);
equal.setFont(font);
add(equal);
//add special buttons
for (int i = 0; i < 3; i++) {
thisButton = new Button(specialArray[i]);
thisButton.setBounds(67*(i+1), 53, 67, 53);
thisButton.addActionListener(this);
thisButton.setFont(font);
specialButton[i] = thisButton;
add(thisButton);
}
}
public void actionPerformed(ActionEvent event) {
String text = textField.getText();
//check if its a number button
for (int i = 0; i < 10; i++) {
if(event.getSource() == numberButton[i]){
String thisButtonText = numberButton[i].getLabel();
//show the number on the text field
text += thisButtonText;
textField.setText(text);
if(!firstVarOver){
var[1] += thisButtonText;
whichVar = 1;
return;
}
else{
whichVar = 2;
var[2] += thisButtonText;
isBckspAble = true;
return;
}
}
else if(event.getSource() == zero){
text += "0";
textField.setText(text);
var[whichVar] += "0";
return;
}
}
//number checking loop ends
//operator checking begins
for (int i = 0; i < 4; i++) {
if(event.getSource() == operatorButton[i]){
operator = operatorButton[i].getLabel().charAt(0);
firstVarOver = true; // first variable is entered completely only after an operator is entered.
text += " " + operator + " ";
textField.setText(text);
}
}
//operator checking ends
//equal-to checking begins
if(event.getSource() == equal){
text += " = ";
textField.setText(text);
try{
compute(Float.parseFloat(var[1]), Float.parseFloat(var[2]), operator);
}
catch(NumberFormatException e){
JOptionPane.showMessageDialog(null, "Whoops! Cannot compute! Need two operands!");
restart();
clear();
}
}
//equal-to checking ends
//special button checking begins
char spcLabel;
for (int i = 0; i < 3; i++) {
if(event.getSource() == specialButton[i]){
spcLabel = specialButton[i].getLabel().charAt(0);
switch(spcLabel){
case 'C': clear(); break;
case '.': {
text += ".";
textField.setText(text);
var[whichVar]+= ".";
break;
}
case '<': {
if(isBckspAble){
text = text.substring(0, text.length()-1);
textField.setText(text);
var[whichVar] = var[whichVar].substring(0, var[whichVar].length()-1);
}
break;
}
}
}
}
}
//this function will compute the result of the binary operation, i.e. this function is the calculator without the graphics
public void compute(float var1, float var2, char op) {
switch(op){
case '+':{
result = var1+var2;
break;
}
case '-':{
result = var1-var2;
break;
}
case '*':{
result = var1*var2;
break;
}
case '/':{
result = var1/var2;
break;
}
default:{
JOptionPane.showMessageDialog(null, "Oh snap! Some error occured!");
clear();
restart();
}
}
String text = textField.getText();
text += result;
textField.setText(text);
adjustForRecomputing();//after each computation, adjustment has to be done for the next computation
}
//this function makes the calculator ready for the next operation
public void adjustForRecomputing(){
var[1] = Float.toString(result);
firstVarOver = true;
var[2] = "";
whichVar = 2;
isBckspAble = false;
}
public void restart(){
JOptionPane.showMessageDialog(null, "Reloading...");
repaint();
}
public void clear(){
textField.setText("\n");
firstVarOver = false;
whichVar = 1;
var[1] = "";
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

Thursday, 13 March 2014

Addition Of Two Numbers Using Linked Lists


Another very frequently searched algorithm is to add two very long numbers (in the order of zillions) using Linked Lists.


IMPLEMENTATION:


We use the Linked List to implement such a logic. Here, we make use of the fact that “int” in java has the range -2^31 to 2^31 which is 10 digits long. Therefore, every node in the list can hold maximum upto 10 digits. If the number has more than 10 digits, the More Significant Digits are pushed in the previous node. Thus 2 Lists are created for 2 numbers and they are then added node-by-node. The carry, if generated is added to the next pair of nodes to get the proper answer.


As usual, we have used our own version of Linked List to make the addition, deletion, and searching nodes processes transparent.





public class LinkedListNode {
String info;
LinkedListNode address;
public LinkedListNode(){
info = "";
address = null;
}
}
import java.util.Scanner;
public class LinkedList {
LinkedListNode listPointer = null;
LinkedListNode lastNodePointer = null;
int numberOfNodes = 0;
static Scanner input = new Scanner(System.in);
public LinkedList() {
}
public static void main(String[] args) {
String info;
LinkedList newList = new LinkedList();
System.out.println("Enter the info in first node");
info = input.next();
newList.addFirstNode(info);
int choice;
do{
System.out.println("Enter 1 for adding a node to the end, 2 for adding a node at a particular position, 3 for deleting a node, 4 to search for a node, 5 to exit");
System.out.println("What do you want to do?");
choice = input.nextInt();
switch(choice){
case 1 : {
System.out.println("Enter the info in the node");
info = input.next();
newList.addNodeToEnd(info);
break;
}
case 2 :{
System.out.println("Enter the position of the new node");
int position = input.nextInt();
System.out.println("Enter info of the new node");
info = input.next();
newList.addNodeAtPosition(position, info);
break;
}
case 3 :{
System.out.println("Enter the position of the node you want to delete");
int position = input.nextInt();
newList.deleteNode(position);
break;
}
case 4 : {
System.out.println("Enter the info of the node you want to search");
info = input.next();
newList.searchForNode(info);
break;
}
default : System.out.println("Give appropriate choice");
}
}while(choice != 5);
}
public void addFirstNode(String info){
LinkedListNode firstNode = new LinkedListNode();
firstNode.info = info;
firstNode.address = null;
listPointer = firstNode;
lastNodePointer = firstNode;
numberOfNodes = 1;
viewList();
}
public void addNodeToEnd(String info){
LinkedListNode newNode = new LinkedListNode();
newNode.info = info;
newNode.address = null;
lastNodePointer.address = newNode;
lastNodePointer = newNode;
numberOfNodes++;
System.out.println("Node added");
viewList();
}
public void addNodeAtPosition(int position, String info){
LinkedListNode tempPointer = listPointer;
for (int tempPosition = 0; tempPosition < position-1; tempPosition++) {
try{
tempPointer = tempPointer.address;
}
catch(NullPointerException e){
System.out.println("Position " + (position-1) + " has not been occupied yet!");
System.out.println("Adding node at the end");
addNodeToEnd(info);
return;
}
}
LinkedListNode newNode = new LinkedListNode();
newNode.info = info;
newNode.address = (tempPointer.address).address;
tempPointer.address = newNode;
System.out.println("Node added");
viewList();
}
public void deleteNode(int positionOfNode){
LinkedListNode tempPointer = listPointer;
for (int tempPosition = 0; tempPosition < positionOfNode-1; tempPosition++) {
tempPointer = tempPointer.address;
}
tempPointer.address = (tempPointer.address).address; // this is the main shifting statement
System.out.println(tempPointer.info + " deleted");
numberOfNodes--;
viewList();
}
public void viewList(){
LinkedListNode temp = listPointer;
for (int counter = 0; counter < numberOfNodes; counter++) {
System.out.print("[" + temp.info + ", " + temp.address + "]");
temp = temp.address;
}
System.out.println();
}
public LinkedListNode searchForNode(String info){
LinkedListNode temp = listPointer;
while(!temp.info.equals(info)){
temp = temp.address;
if(temp == null){
System.out.println("Node not in the list!");
return null;
}
}
return temp;
}
}
view raw Linked List hosted with ❤ by GitHub
The main Addition class which calls the above class is as follows:

NOTE: We have created the program keeping in mind only positive integers. Floating point numbers may/may not work in this program depending on the number!
package labWorkDSA;
import java.util.Scanner;
public class AdditionOfTwoNumbers {
/* SENTINEL is kept at 1 followed by 9 zeroes. This is the most efficient SENTINEL because :
* The range of 'int' is -(2^31) to +(2^31) -1 which is a 10 digit number.
*/
public static final int SENTINEL = 1000000000;
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter a number");
String exp1 = input.next();
LinkedList list1 = arrangeInList(exp1);
System.out.println("Enter another number");
String exp2 = input.next();
LinkedList list2 = arrangeInList(exp2);
System.out.println("The sum of the two numbers is:" + addLists(list1, list2));
input.close();
System.exit(0);
}
public static LinkedList arrangeInList(String numberString){
boolean isFirstNode = true;
String info;
LinkedList newList = new LinkedList();
while(true){
/*The entire while loop mainly contains a single if-else condition
* It checks whether the number remaining to be evaluated (initially the entire number) has a length>9
* This is because if it does, we need to break it down into numbers with max 9 digits
* if not, we simply add the whole number into a new node and break
* We break because this is obviously, the last node
*/
if(numberString.length() > 9){
info = convertLast9CharsIntoDigits(numberString);
if (isFirstNode){
newList.addFirstNode(info);
isFirstNode = false;
}
else{
newList.addNodeToEnd(info);
}
numberString = getHigherDigits(numberString);
}
else{
if(isFirstNode){
newList.addFirstNode(numberString);
}
else{
newList.addNodeToEnd(numberString);
}
break;
}
}
return newList;
}
public static String convertLast9CharsIntoDigits(String mainString){
String intString = mainString.substring(mainString.length()-9);
return intString;
}
public static String getHigherDigits(String string){
String temp = "";
for(int i = 0; i < string.length()-9; i++){
temp+= string.charAt(i);
}
return temp;
}
public static String addLists(LinkedList list1, LinkedList list2){
String result = ""; // the result of the addition will be a string as it may be too long
String temp = "";
byte carry = 0; //carry is a single byte which will store only 1 digit number
int sum = 0;
String sumString = ""; // This is the string after parsing int sum to string
boolean lastOfList1 = false; //These store whether list1 or 2 have ended or not.
boolean lastOfList2 = false;;
while(list1.listPointer!= null || list2.listPointer!= null){
/*This if-else ladder will check if any node is null and therefore, not take into consideration
A node will be null when one of the 2 numbers is much larger than the second
*/
if(list1.listPointer == null){
sum = carry + Integer.parseInt(list2.listPointer.info);
lastOfList1 = true;
}
else if(list2.listPointer == null){
sum = carry + Integer.parseInt(list1.listPointer.info);
lastOfList2 = true;
}
else{
sum = carry + (Integer.parseInt(list1.listPointer.info) + Integer.parseInt(list2.listPointer.info));
}
//end of if-else ladder-1
/* This ladder will check whether the number is greater than SENTINEL i.e.
* whether a carry is generated or not
*/
if(sum/SENTINEL != 0){
carry = Byte.parseByte(Integer.toString(sum/SENTINEL)); // V IMP STEP : Use Of Wrapper Classes Byte, Integer and String
sum = sum % SENTINEL;
}
else{
carry = 0;
temp = "";
}
//end of if-else ladder-2
sumString = Integer.toString(sum);
for (int i = 0; i < 9-sumString.length(); i++) {
temp += "0";
}
temp += sumString;
sumString = temp;
temp = sumString + result;
result = temp;
if(!lastOfList1){
list1.listPointer = list1.listPointer.address;
}
if(!lastOfList2){
list2.listPointer = list2.listPointer.address;
}
}
return result;
}
}
NOTE: A more elegent solution will be to input the number from Most Significant Digits and keep pushing the nodes into a stack. Thus, we will have 2 stacks for 2 numbers. Now, all we need to do is add the node pointed by the top of each stack with each other and and keep pushing it into a "result" stack.

The Josephus Problem


Problem Statement:
A group of soldiers is surrounded by the enemy from all the sides. There is no hope of victory for them and they have only 1 horse. In order to choose which soldier amongst them gets the chance to get on the horse and escape/call for reinforcements, they devise a method. The soldiers are arranged in a circle. A number n is picked up at random from a chit-box. Then a name is also picked up at random from another box. Starting from the soldier whose name came from the box, they count clockwise till n. When the count reaches n, that soldier is removed from the circle and is no longer counted. The counting then starts again from the next soldier. This is done continuously till only one soldier remains and that soldier is allowed to escape on the horse.
Implementation:
We use a Circular Linked List to solve the problem, as the last node in a circular list is connected to the first, thus there is no node with next address null at any time. The list is traversed n times and when a soldier has to be removed, that particular node is deleted from the list. Eventually, the list will have only 1 node pointing to itself (it is still a circular list) and containing the name of the soldier that can escape.

Now, java.util already has Linked List functionalities, yet it seemed prudent to make the readers understand the inner functionalities of the list. Hence, a new class of Circular Linked List is made complete with add, delete, search functionalities.

import java.util.Scanner;
public class CircularLinkedList {
String info;
CircularLinkedList address;
static CircularLinkedList listPointer = null;
static CircularLinkedList nodePointer = null;
static int numberOfNodes = 0;
static Scanner input = new Scanner(System.in);
public CircularLinkedList() {
info = "";
address = null;
}
public static void main(String[] args) {
String info;
System.out.println("Enter the info in first node");
info = input.next();
addFirstNode(info);
int choice;
do{
System.out.println("Enter 1 for adding a node, 2 for deleting a node, 3 to search a node, 4 to exit");
System.out.println("What do you want to do?");
choice = input.nextInt();
switch(choice){
case 1 : {
System.out.println("Enter the info in the node");
info = input.next();
addNode(info);
break;
}
case 2 :{
System.out.println("Enter the info of the node you want to delete");
info = input.next();
deleteNode(info);
break;
}
case 3 : {
System.out.println("Enter the info of the node you want to search");
info = input.next();
searchNode(info);
break;
}
default : System.out.println("Give appropriate choice");
}
}while(choice != 4);
}
public static void addFirstNode(String info){
CircularLinkedList node = new CircularLinkedList();
node.info = info;
node.address = node;
listPointer = node;
nodePointer = node;
numberOfNodes = 1;
viewList();
}
public static void addNode(String info){
CircularLinkedList node = new CircularLinkedList();
node.info = info;
node.address = listPointer;
nodePointer.address = node;
nodePointer = node;
numberOfNodes++;
System.out.println("Node added");
viewList();
}
public static void deleteNode(String info){
CircularLinkedList tempPointer = listPointer;
CircularLinkedList tempNodePointer = nodePointer;
while(!tempPointer.info.equals(info)){
tempPointer = tempPointer.address;
tempNodePointer = tempNodePointer.address;
}
tempNodePointer.address = tempPointer.address;
listPointer = tempPointer.address;
nodePointer = tempNodePointer;
System.out.println(tempPointer.info + " deleted");
numberOfNodes--;
viewList();
}
public static void viewList(){
CircularLinkedList temp = listPointer;
for (int counter = 0; counter < numberOfNodes; counter++) {
System.out.print("[" + temp.info + ", " + temp.address + "]");
temp = temp.address;
}
System.out.println();
}
public static CircularLinkedList searchNode(String info){
CircularLinkedList temp = listPointer;
while(!temp.info.equals(info)){
temp = temp.address;
if(temp == listPointer){
System.out.println("Node not in the list!!");
return null;
}
}
return temp;
}
}
The actual Josephus Class that calls this CircularLinkedList class is as follows:

import java.util.Scanner;
import <package>CircularLinkedList;
public class JosephusProblem {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String soldierName;
boolean isFirst = true;
System.out.println("Enter the names of the soldiers in clockwise order. Press '-' key when done." );
do{
soldierName = input.next();
if(soldierName.equals("-")){
break;
}
else if(isFirst){
CircularLinkedList.addFirstNode(soldierName);
isFirst = false;
}
else{
CircularLinkedList.addNode(soldierName);
}
}while(!soldierName.equals("-"));
System.out.println("Pick up a chit from the number box. Enter the number");
int number = input.nextInt();
System.out.println("Pick up a chit from the name box. Enter the name");
String name = input.next();
josephus(number, name);
}
public static void josephus (int number, String name){
CircularLinkedList startingNode, temp;
while(CircularLinkedList.numberOfNodes != 1){
startingNode = CircularLinkedList.searchNode(name);
temp = startingNode;
for (int counter = number; counter > 1; counter--) {
temp = temp.address;
}
name = temp.address.info;
CircularLinkedList.deleteNode(temp.info);
}
System.out.println("The soldier that can escape on the horse is : " + name);
}
}
view raw Josephus Class hosted with ❤ by GitHub
An example of the output is as follows:

 Enter the names of the soldiers in clockwise order. Press '-' key when done. a
[a, labWorkDSA.CircularLinkedList@ec5aba9]
b
Node added
[a, labWorkDSA.CircularLinkedList@5388ebd2][b, labWorkDSA.CircularLinkedList@ec5aba9]
c
Node added [a, labWorkDSA.CircularLinkedList@5388ebd2][b, labWorkDSA.CircularLinkedList@423252d6][c, labWorkDSA.CircularLinkedList@ec5aba9]
d
Node added [a, labWorkDSA.CircularLinkedList@5388ebd2][b, labWorkDSA.CircularLinkedList@423252d6][c, labWorkDSA.CircularLinkedList@5fbd8c6e][d, labWorkDSA.CircularLinkedList@ec5aba9]
e
Node added [a, labWorkDSA.CircularLinkedList@5388ebd2][b, labWorkDSA.CircularLinkedList@423252d6][c, labWorkDSA.CircularLinkedList@5fbd8c6e][d, labWorkDSA.CircularLinkedList@154ebadd][e, labWorkDSA.CircularLinkedList@ec5aba9]
-
Pick up a chit from the number box. Enter the number
5
Pick up a chit from the name box. Enter the name
a
e deleted
[a, labWorkDSA.CircularLinkedList@5388ebd2][b, labWorkDSA.CircularLinkedList@423252d6][c, labWorkDSA.CircularLinkedList@5fbd8c6e][d, labWorkDSA.CircularLinkedList@ec5aba9]
a deleted
[b, labWorkDSA.CircularLinkedList@423252d6][c, labWorkDSA.CircularLinkedList@5fbd8c6e][d, labWorkDSA.CircularLinkedList@5388ebd2]
c deleted
[d, labWorkDSA.CircularLinkedList@5388ebd2][b, labWorkDSA.CircularLinkedList@5fbd8c6e]
d deleted
[b, labWorkDSA.CircularLinkedList@5388ebd2]
The soldier that can escape on the horse is : b

The Story Behind "public static void main"


All the beginners in Java language are first taught the Hello World program, which although very simple looking, contains a lot of the functionality secrets of Java.
The first method that a new java programmer writes is the “main” method.
The entire Hello World program looks something like the following:
public class HelloWorld {
 public static void main(String[] args) {
  System.out.println("Hello World");
 }
}


The output, obviously is:
Hello World


Let us explore the main method and all its keywords one by one:
The first thing one should know that the execution of a java program starts from the main function. After loading the program, the Java Virtual Machine (JVM) scans the program to search for “public static void main (String[] args)”
Public: “public” is an access-specifier and it means that the method can be called from outside of the class. The main method has to public so that the JVM can call it and begin the program.
Static: “static” means that only one copy of the main function is shared between all objects of the class and one doesn’t have to initialize a class object to call the main method. (For more information on “static”, click here)
Void: “void” is a return type. It indicates that the main function does not return anything. This is quite logical, as the main function is called implicitly by the JVM and not by another function. So it has no function to return value to.
(String[] args): The entire phrase inside the parentheses are arguments passed to the main function. The argument type is an array of the type java.lang.string and the name of the array is “args”. Consider the following program:

public class HelloWorld {
 public static void main(String[] args) {
  System.out.println("Hello World"); 
    for (int i = 0; i < args.length; i++) {
  System.out.println(args[i]);
     }
   }
}



If you are operating from the command prompt/terminal, and you enter
       java HelloWorld I’m Batman

The output will be:

Hello World

I’m

Batman
If you type: java HelloWorld “I’m Batman”, the output is:
Hello World
I’m Batman
If you are using the Eclipse IDE, you can enter the “program arguments” from Run>Run Configurations>(x)= Arguments (That’s the second tab) and then enter your arguments.
Run Configurations In Eclipse.jpg

What does "static" mean in Java?


I have gone through many books of java but not many give sufficient explanation of what is the meaning of the keyword "static" in Java and when does one use it.


STATIC VARIABLES:


Making a variable static basically means that only one copy of the variable is shared between all the objects of the class. If one object changes the value of that variable, all the variables get the updated value.

Consider the following code snippet:
class StateOfACountry; 
 public String stateName;
 public String CM_name;
 public static String PM_name;
  
 public static void main(String []args){
  StateOfACountry state1 = new StateOfACountry();
  state1.CM_name = "CM1";
  state1.PM_name = "PM";
  System.out.println("State 1 CM name " + state1.CM_name);
  System.out.println("State 1 PM name " + state1.PM_name);
 
  StateOfACountry state2 = new StateOfACountry();
  System.out.println("State 2 CM name " + state2.CM_name);
  System.out.println("State 2 PM name " + state2.PM_name);
  
  state2.CM_name = "CM2";
  state2.PM_name = "PMabc";
  
  System.out.println("State 2 CM name " + state2.CM_name);
  System.out.println("State 2 PM name " + state2.PM_name);

  System.out.println("State 1 CM name " + state1.CM_name);
  System.out.println("State 1 PM name " + state1.PM_name);
  }
}
The output is:
State 1 CM name CM1
State 1 PM name PM
State 2 CM name null
State 2 PM name PM
State 2 CM name CM2
State 2 PM name PMabc
State 1 CM name CM1
State 1 PM name PMabc
In the above example, the variables stateName, CM_name are not static while the variable PM_Name is. This is correct logically because if there are many states in a country, the Chief Minister (CM) of one state may be different from another. However, all states will share the same Prime Minister (PM) name. Thus we see that, if there is a variable which is common amongst all the objects in the same class, we should treat it as static.

Now, consider a case of re-elections. If the CM of state1 is changed, it is not necessary that the CM of state2 be changed as well. However, if the PM of the country is changed, then the change is reflected on the PM of all the states! (which is correct logically).
Thus, we see that the static variables belongs to the class on a whole and not to a particular object of the class. In the above case, a Prime Minister (PM) belongs to a country on a whole, rather than the state of a country.
All such variables which are not tied to an object should be made static in your programs.
STATIC FUNCTIONS:
The definition of static extends to functions as well i.e. a copy of static function is shared between all the objects of the class. A function is made static when two static functions have nothing in common between them.
Also, there is an additional clause: Static functions can access and operate on only static variables. This, of course, is logical as static functions are something that belong to the class rather than an object, and therefore should operate only on variables that too belong to the class.
Accessing non-static variables in static functions causes an error (try it!)
Consider the above example, now modified:
class StateOfACountry{
   public String stateName;
   public String CM_name;
   public static String PM_name;
           
   public static void changePM(String newPM_name){
     PM_name = newPM_name;
   }
           
   public void changeCM(String newCM_name){
     this.CM_name = newCM_name;
   }
 
   public static void main(String []args){
 
      StateOfACountry state1 = new StateOfACountry();
      state1.CM_name = "CM1";
      state1.PM_name = "PM";
           
      StateOfACountry state2 = new StateOfACountry();     
      state2.CM_name = "CM2";
      state2.PM_name = "PMabc";
      state1.changeCM("newCM1");
      System.out.println(state1.CM_name);
      System.out.println(state2.CM_name);
           
      state1.changePM("newPM1");
      System.out.println(state1.PM_name);
      System.out.println(state2.PM_name);          
     }
}

The output is:

newCM1

CM2

newPM1

newPM1


Thus we see that the function changeCM operates on the CM_name of a particular object, while the static function changePM operates on the static variable PM_name which is common for all the objects in the class.


INITIALIZING A STATIC VARIABLE:


Since static variables are not tied to any objects, they need not be initialized using an object. In other words, they do not have an “object state”.

public class MeaningOfStatic {
public static int var = display();
  public MeaningOfStatic() {
     System.out.println("Constructor Entered. Object is instantiated.");
  }
 public static int display(){
     System.out.println("Hello World");
     System.out.println(var);
     return 10;
   }
 
  public static void main(String[] args) {
     System.out.println("Main entered.");
     MeaningOfStatic object = new MeaningOfStatic();
     object.display();
     System.out.println(Math.PI);
     System.out.println(Math.sqrt(2)); //No object of Math is                                                initialized to invoke sqrt, because its static! 
     }
}

The output is:

Hello World

0
Main entered.
Constructor Entered. Object is instantiated.
Hello World
10
Thus we see that the static variable var was declared even before an object was initialized. It was also assigned value using the static function even before the main function was started! Because it isn’t tied to any particular object.
All lang.Math methods in java are static (e.g. Math.Random(), Math.sqrt()) because it wouldn’t make sense to tie all this methods to an object i.e. the methods Math.random, Math.sqrt have nothing in common.