Previous
Index

Next


2.2) Data Types variables and operators

Variables and names

Like all programming languages Java allows data to be stored in variables. The term variable has its origins in the idea that the contents may vary, i.e. At the start of a program variable may contain 10 and later it might contain 99. Because it is an OO language Java can store information in either Objects or primitives. A primitive is a fixed building block type of data that you cannot change the structure of, whereas an Object is a way of storing data that is defined by the programmer. For this section I will concentrate on primitives.

Behind the scene a variable is a name or label given to a piece of memory. That name can be used to refer to whatever value is currently stored in the memory location. It is a little like the use of symbols such as X or Y in algebraic equations.

There are rules for what names can be given to variables, but you are generally safe if you stick to names containing all letters, and preferably a name that means something to you. Thus if you are storing the height of an image you are better off calling it Height rather than z or p. There is a convention amongst some programmers to add letters to variables to indicate the data type. Thus if the height of an image is being stored in an integer you might call a variable iHeight.

All variables must be given a data type when they are created. There are some languages sometimes called “weakly typed” languages that do not require this. For example in the PHP language used to create web pages there is no concept of assigning a type to a variable. Although this can seem very convenient it can cause problems where people misspell a variable name and the language assumes it is an attempt to create a new variable and so the programmer is not warned. The requirement to give a type to all variables is considered to be a feature that makes Java "safer", i.e. It is not so easy to create bugs.



Java is a strongly typed language, variables must be assigned a data type.

You can create a variable ready for use elsewhere or you can assign a value to it at the same time you create it. Here is an example of creating an integer (int) variable without assigning a value.

int i;

This tells Java to create a variable called i with the type int. An int is a type that can store the values between approximately plus or minus 2 billion and has no fractional part (decimal point values).

The other form of creating a variable is

int iHeight=10;

This does the same as the previous example, except that it assigns a value to the variable at the same time as it creates it. Note that in both examples the line ends with a semi colon. This indicates the end of the statement to the compiler. Sooner or later everyone misses off the semi colon or places a colon or similar character by mistake. Luckily the error messages from Java give a good indication what the error is.

Final values

There are times when you may want to have a variable with a fixed value (OK, if it's value cannot vary its not really a variable). For example if you were dealing with a cricket team you might want to refer to the fixed size of the team as 11. It would be useful if you could be certain that this value would be fixed under all circumstances and could not be changed by accident. The keyword to use for this circumstance is final. The following code shows how you can use this keyword

public class Cricket{      
        final int TeamSize=11;
        public static void main(String argv[]){
                Cricket ck = new Cricket();
                }               
}       
                



The final keywork makes a value fixed, i.e. It cannot be changed.

The final keyword can bring performance benefits becase te compiler and runtime know that the value will not change.

Method and class variables

A variable can be created either at class level or method level. A class level variable is also known as a field and is visible from within any method in that class. The following code shows how you can create a class field and initialize it with a value.

public class InitField{
        static int MyField = 10;
        public static void main(String argv[]){
                System.out.println(MyField);
        
        }
}

Note how the field is created outside of any method just before the name of the class. Don't worry about the use of the word static before the field, that will be explained later.



Class fields are initialized to default values if you don't explicitly initialize them.

If you write code with an uninitialized field variable you will get a compile time error. Thus if you were to attempt to compile the following code you would get a compile time error that says something like “variable i may not have been initialized”.

public class NonDefault{
     public static void main(String argv[]){
       new NonDefault();

     }
     NonDefault(){
             int i;
             System.out.println(i);
     }
}

The default values assigned to class fields are approximatly what you might expect, thus numbers are generally zero. Thus the following code will print out zero.

public class Default{   
     static int myfield;
     public static void main(String argv[]){
             System.out.println(myfield);    
     }
}    

By contrast a method level variable is only visible within that method. Another important property of a method level variable is that it comes into existence when the code enters the class and does not persist between calls to the class. Thus if you take the example of the following code.

Void amethod(){

int i = 1;
}

The variable i will be re-initialised each time amethod is called. Method variables are not given default values and if you attempt to use them without assigning a value it will generate a compile time error. The following code demonstrates this.

public class MetVar{
        public static void main(String argv[]){
                MetVar mv = new MetVar();
                mv.amethod();
                }
                public void amethod(){
                int i;
                System.out.println(i);
                }
}

If you attempt to compile this code it will generate the error

MetVar.java:8: variable i might not have been initialized
                System.out.println(i);
                                   ^
1 error



Exercise OutField

Create a class called OutField that has a field of type int called myfield that is initialized with a value of 10. Create a method called go with a void return type. Within the body of the go method put in code that output the value of myfield, then create code that adds 10 to its value and then output that new value.

Method Parameters

Methods can take parameters of primitive or object types. When a method is declared it is given the data type and a name for the data type. The name is just a convenience for the programmer. Thus you have seen how the name of the parameter to the main method is usually called argv, but can be called anything you like, so the following is a valid main method.

public static void main(String bicycle[]){
}

OK it would be rather silly to call the parameter bicycle, but its perfectly legal. You can have just about as many parameters you like for a method, though generally methods only have a small number, more than about 4 parameters is unusual. Thus the following is quite valid.

public void go(String name, int age){
   System.out.println(“My name is “ + name + “and my age is “ + age +” years”);
}

If you were calculating volume you might have a method with the signature.

public void getArea(int height, int depth, int width){

}

You can call a method with different parameters as often as you like. So for example if you had a method that added values you could call it multiple times with different values as follows.

public class AddValues{    
        public static void main(String argv[]){
                AddValues av = new AddValues();
                av.go();
                }
                
                public void go(){
                        add(1,1);
                        add(10,10);
                        add(2,2);               
                }
                public void add(int first, int second){
                        System.out.println(first + second);
                }
        }
        




Exercise GetArea

Create a class called GetArea. Create a standard main method that creates an instance of the class and create a go method that is called from the instance of the class. Create a method called getArea that takes two int parameters. Within the getArea method create code that multiplies the height by the width and prints out the results.

Within the body of the go method create two calls to the getArea method. One passes the values of 10 for the height, and 5 for the width. Create a second call to the getArea method within the go method that passes 100 to the height and 100 to the width.

When the program is run it should print out the two area values.

Pass by value or reference?

An important question with methods is are parameters passed as a copy or is the original value. Java methods parameters are considered to be pass by value, i.e. A copy of the value is passed into the method. Thus if a primitive is passed into a method, any changes will not be reflected once the method returns (finishes execution).

/**

*Java method parameters
*are passed by value
*what will be output by
*this program?
*@author Marcus Green
**/
public class PassByValue{       
        public static void main(String argv[]){
                new PassByValue();              
         }
         PassByValue(){
                int i = 10;
                amethod(i);
                System.out.println(i);
         }
         public void amethod(int i){
                i=i * 10;
                System.out.println(i);
         }
}

However if an object is passed into a method, what is passed is the reference or pointer to that object. Any manipulation of the object through its pointer will be present when method returns. The following code demonstrates this by manipulating a field of an object that is passed to a method. When amethod returns the value of field i will reflect the changes made within the method.

/**
*Java method parameters
*are passed by value
*including object references
*what will be output
*by this program?
*@author Marcus Green
**/
class MyClass{
        int i;
}
public class PassObjectByValue{ 
        public static void main(String argv[]){
                new PassObjectByValue();                
         }
         PassObjectByValue(){
                MyClass mc = new MyClass();
                /*pass a reference to mc to the method */
                amethod(mc);
                System.out.println(mc.i);
         }
         public void amethod(MyClass mc){
                mc.i = 100;
                System.out.println(mc.i);
         }
} 



Constructors

So far each of the examples you have seen have had code that creates an instance of the class and then calls a method with an arbitrary name such as go. Java supports the idea of a magically named method that will be executed every time an instance of the class is created. This type of method is called a constructor and it must have the same name of the class and no return type. I will return to the subtleties of constructors later in the course, meanwhile we will just use it as an easy way to get your code to go rather than creating a method with a name like go each time.



A constructor must have the same name as the class and no return type.

Here is an example of a class with a constructor (note the lack of a return value for the constructor “method”.

public class MyCon{
        public static void main(String argv[]){
                MyCon mc = new MyCon();
        }
        public MyCon(){
                System.out.println("This is the MyCon constructor");
        }
}




A class can have multiple constructors, each with different parameters.

A class can have more than one constructor as a constructor can have parameters just like methods. Thus you might have a class that you want to initialze with a String or with a String and a number.



Exercise ConArg

Create a class called ConArg. Create a constructor method marked as public and write the constructor so it accepts a String array parameter. Create a main method for the class and within the main method create an instance of the ConArg class that takes the argv parameter of the main method as a parameter. Within the Constructor output the first (element zero) item within the String array passed from the command line. Compile and run your program. Test it to check that the first item on the command prompt gets sent to the constructor and is printed out, i.e. Java ConArg one. What happens if you run the program without any parameter after the program name?

Variable Length Arguments (VarArgs)

Variable length arguments to methods were introduced with JDK1.5. The problem that Variable length arguments addresses is where you want to pass multiple values as parameters to a method. This problem is addressed in previous versions of Java by allowing you to populate an array and passing it as a parameter to a method. You can see this in action in the way the signature of the default main method accepts a String array, without requiring you to know how many parameters are going to be passed to the method. Passing an array is an acceptable solution to many situations, but for the programmer it represents a step that could be automated by the compiler/runtime and that is what the new VarArgs idea

The Syntax

The syntax for varargs is that you include three dots after the data type and before the name of the parameter. Those three dots are sometimes called “elipsis”. Note it is three dots and not two (as I mistakenly typed the first time I used this feature).

public class Va{
    public static void main(String[] argv){
        new Va();
    }
    Va(){
        cboste("Holy Waters","Take My Hand","Cry Down");
    }
    public void cboste(String ... tracknames){
        for(String trackname :tracknames){
            System.out.println(trackname);
        }
    }
}

Note how this code uses the new version of the for loop to iterate through each element of the array that was created and passed to the method. You could treat the parameter in the same way as you would any other array, e.g. You could read its length property to find out the number of elements and walk through it using the original version of the for loop, but why work harder than strictly necessary?

Limitations

There are some limitations to the use of VarArgs, you can only have one vararg parameter per method and it must be the last argument to the method. Interestingly at least one other language (PHP) has a similar limitation, so I suspect it must make the compiler writers lives easier to include this limitation. You can of course have as many array parameters to a method as you like, so if you really do need multiple variable arguments to a method, that could be a solution.

Primitive Types

Primitive types are the basic building blocks of programming, and are present in almost all languages. Primitives cannot have methods, and cannot be inherited from or redefined. They can be directly manipulated with the math operators such as +, - and *.

For much of your time programming you will not care much about the size of the primitives you use. Indeed in some languages such as PHP there is no concept of assigning a type to a variable, and millions of lines of PHP code are written and many people love the languages.

Java was designed to allow large scale software engineering however and being able to control data types gives the programmer a fine control over resource usage.

Thus for many (most?) simple counting operations the data type called int will do just fine, as it will store numbers up to 2 billion odd and if you are counting the numbers of windows your program has open or the number of CD's in your collection an int will probably do just fine.

However of Bill Gates, is calculating his net worth he might need to pay more attention to his choice of data type (OK so he wouldn't admit in public that he was using Java, but he is a smart technologist under all that marketing).

Unlike C/C++ the size of Java primitives are fixed no matter what platform it is used on. In C/C++ you can often see code that uses the sizeof operator to try to ensure that code is platform neutral by determining the size of a data type on the current platform. Because this is not mandatory the move from one platform to another can often break C/C++ code in a subtle manner.

Primitive data types can broadly be divided into integral types and floating point types. Floating point types can store vast, huge, enormous numbers but they bring with them a certain imprecision. For many purposes one of the integral types such as int or long will do just nicely.

Size of Primitives.

The size of Primitives

Name

Size

Range

byte

8 bit

-27 to 27-1

short

16 bit

-215 to 215-1

int

32 bit

-231 to 231-1

long

64 bit

-263 to 2 63-1



The boolean type

A boolean value can have one of two values true or false. A boolean cannot be assigned any other values, this is unlike some language where true or false can be represented by zero or non zero values. Boolean values are used where there is only two possible outcomes, for example as the argument to an if statement boolean will be set to either go into the if block or not.

Character Data

Character data is stuff like car licence plates, phone numbers and social security numbers, data that might consist of numbers but that you don't normally perform math on. The two main ways of storing character data is via the char primitive or the String class. The String class is generally preferable as it has a whole swag of methods for slicing, dicing and generally manipulating the characters. The char primitive data type is actually a 16 bit integer that can store characters from the Unicode character set. You generally don't need to know much about Unicode unless you are involved in internationalisation (apologies if that is horribly English centred, but I am horribly English centred). Unicode is a way of storing almost any of the worlds character sets, so you can represent the accents in European languages or even Vietnamese, Chinese and Japanese that do not even use the European style character sets.

An important difference between the String class and the char data type is that when you put a character into a char variable you use single quotes and when you put a character into a String you use double quotes.

Thus

String s = new String("a");
char a = 'a';

Note that a char only stores one character, do not try to store a string thus

char a='error';

Will not compile.

The String Class

So many programming tasks require the manipulation of String data that Java has a built in String class. String is a class rather than a primitive type so note that the name begins with an upper case S, it is NOT string, it is String.



String is a built in class not a primitive and has its own methods.

It is a general convention in Java that the names of classes begin with upper case letters. The sequence of letters assigned to an instance of a class are surrounded by double quotes. Thus you can create a String variable thus

String sName = "Hello java";

If you have ever used the C programming language you may have become used to storing Strings as arrays of character primitives. An instance of the Java String class is not the same as an array of char primitives. If you need to perform large amounts of String handling, such as importing and manipulating multiple megabytes of text, Java has a StringBuffer class that offers better performance than the String class.

Slicing and dicing Strings

Because standard HTML web pages are little more than large amounts of strings the ability to slice and dice them is very important. Most Java programmers quickly learn the basics of how to process strings with functions such as finding characters, splitting, joining and changing characters. If you look up the API docs for the String class you will see it has a huge number of methods, however you can do most things you require with only a limited number of methods. A common requirement is to turn a String to either all upper or all lower case. This is quite common when poking data into a database and can be done with the toUpperCase and toLowerCase methods of the String class.



Exercise StringThing

Create a class called StringThing with a standard main method. Create a zero parameter
constructor that gets called within the main method.

Within the Constructor create a two variables, one called called name and another called temp. Initialize name to your name and temp to initialize it to a blank value ("");

Call the toUpperCase method of name and assign it to temp. Output the value of temp.
Call the toLowerCase method of name and assign it to temp. Output the value of temp.

Write a line of code that outputs the number of characters within name by calling its length method.

Chopping and joining strings often involves assigning values back to itself. Thus if you had a String called dollars and you wanted to append the dollar sign to it you would write code as follows using the + sign as a concatenation operator.

String dollars =”100”;

dollars = “$”+dollars

It is very common to want to search for a particular character or substring within another string. For example you might want to find a paragraph tag within an HTML string. The method of the string class that can do this is substring(start,end). This method returns the part of the String that starts at the offset start and end.

Create a class called MoneyFormat. Create a standard zero argument constructor and put a call to that constructor within a standard main method. Create a method called money that takes two String parameters, one called pounds and one called pennies. Have the method return a String value. Within the money method append a pound symbol to the start of the first pounds string, append a period to the start of the pennies string. Then join the two together and return the value from the method.



Exercise UpperFirst

Create a class called UpperFirst. Create a standard zero argument constructor and put a call to that constructor within a standard main method. Within the Constructor create a String called name and populate that String with your own name, all in lower case.

Create a String variable called firstletter for storing the first letter of the string. Populate firstletter by pulling out the first letter of your name using the substring method. Note, the substring method will need to get the parts of the string from zero to one. Convert the single letter to upper case using the toUpperCase method of the String class.

Create a String called remains that contains all of your name except the first letter. You can do this by using the substring method of String. Create a final String called allname that contains the firstletter concatenated with the remains of the name String. Output the result which should now be the name with an upper case first letter.

As an additional exercise you might like to wrap up this functionality in a method that takes a parameter of a String and returns a String where the first letter of the String has had the first letter set to upper case.

The following example takes a standard email address as a parameter and chops off the domain part, i.e. If you give it myname@mydomain.com it will output just myname.

public class EmailFind {
    public static void main(String argv[]){
        new EmailFind();
    }
    public EmailFind() {
        String address= "joesoap@hotmail.com";
        int i = address.indexOf("@");
        String name= address.substring(0,i);
        System.out.println(name);
    }
} 



Exercise PenniesOnly

Create a class called PoundsOnly with a standard main method that calls a zero argument constructor. Within the constructor create a String called fullsum populated with the value “£100.55”. Create a String variable called pennies. Use the indexOf method to locate the position of the point (the full stop) within fullsum. Store that location in an int variable. Create a String called pennies and populate it with the pennies part of the full sum by using the substring method (i.e. From where the point is to the end of the string). You can find the end of the string by using the length method of the fullsum String. Output the pennies value of the full sum String.

If you complete this easily try wrapping up the code in its own method that takes a String for a parameter and returns the pennies value of the String from the method. If that works o.k. you can look into using Integer.parseInt(String s) to convert from a String to an integer to return the pennies value as a number instead of a String.



Exercise DomainOnly

Write a program called DomainOnly that has a standard main method. Create a zero argument constructor and place a call to that constructor within the main method. In the body of the Constructor create a String variable called email. Initialize that String with your full email address (i.e. Your name, the @ symbol and the full domain).

Write code that finds the index of the @ symbol. Create a String variable called domain. Write code that will return just the domain of the email address, i.e. From the at symbol to the end of the address. You will need a variable that contains the length of the total email address which you can find by calling the length() method of the address string. This code will require use of the substring method.

Java Keywords

Keywords are words that cannot be used to name variables. If you attempt to use one of these names for a variable you will get a compile time error.

Java Keywords

abstract

break

byte

case

catch

char

class

const *

continue

default

do

double

else

extends

final

finally

float

for

goto *

if

implements

import

instanceof

int

interface

long

native

new

null

package

private

protected

public

return

short

static

super

switch

synchronized

this

throw

throws

transient

try

void

volatile

while

boolean



The words with asterisks are reserved and not currently used. Note that all of the keywords are in lower-case, thus null is a keyword but NULL is not.

Fields and visibility

Fields, i.e. variables declared at class level can be given a visibility (or scope) marker of public,private or protected. The most common use of a field visibility marker is for it to be marked private. A private field can only be accessed by methods in the class in which it is declared. A private field is not visible to sub classes. As a general policy I recommend marking all fields as private. The exact reasoning will be explained elsewhere in the coverage of polymorphism.



Fields (class variables) can be given a scope marker, not method variables.

For completeness I will cover the meaning of public and protected. A public field is visible to any method in any other object or class. A protected field is visible to any method in the class in which it is declared, but also to any method defined in a sub class. This means that a protected field can be more visible than a field that is marked with any specifier. The public, private and protected specifiers are also used with methods, and that will be covered elsewhere.

Arithmetical Operators

The operators used within Java are similar to those within other programming languages. Most operators can only be applied to primitives, with the major exception that the + acts as a concatenation operator when used with strings. The following code is legal.

String s1= “Hell”;

String s2=”oh”;
String s3 = s1+s2;



The + operator can be used to join Strings together but it cannot be used with any other Object type.

The other arithmetical operators do approximately what you expect. Thus you have -, * and / which act as minus, multiplication and divide by

Thus the following would output 161.

import java.util.*;
public class Test{
        public static void main(String argv[]){
                new Test();
        }
        Test(){
        int three = 3;
        int two = 2;
        System.out.print(three-two);
        System.out.print(three * two);
        System.out.print (three /two);
        
        }
}

Note that final output of 1 is because the values are integers and thus you will “loose” any floating point component resulting from an operation.

The % operator acts as a “remainder” operator. Thus the following code

import java.util.*;
public class Test{
        public static void main(String argv[]){
                new Test();
        }
        Test(){
        int three = 3;
        int two = 2;
        System.out.print(three % two);
        }
}

Will output

12

This is because if you divide two into three it goes once with a remainder of 1.

In addition to the plain addition operator + Java supplies the auto incrementing ++ (plus plus) operator which has come up previously in this course. It should be little surprise that Java also supports the auto decrementing operator – (minus minus). This can be useful when you want to count backwards through some group of elements. Thus the following would print out 54321.

/**
* @author Marcus Green
* demonstrating the -- operator
**/
public class CountBack{
        public static void main(String argtv[]){
                new CountBack();
        }
        CountBack(){
                int [] numbers = new int[] {1,2,3,4,5};
                for(int i =5; i >1; i--){
                System.out.print(i);
                }
        }
}

Relational operators

The relational operators work with boolean parameters, i.e. true and false. You have seen the greater than operator in use with the for loop, such as

           for(int i =5; i >1; i--){

The expression in the centre of this construct effectively says “continue whilst i being greater than 1 is true. As you might guess there is a matching less than relational operator with the < symbol. These two operators are matched with equivalent greater than or equals to and less than or equals to operators in the form

Greater than or equals to >=

Less than or equals to <=

The following code illustrates the <= operator and will print out 543210.

public class CountBack{
        public static void main(String argtv[]){
                new CountBack();
        }
        CountBack(){
                int [] numbers = new int[] {1,2,3,4,5};
                for(int i =5; i >=0; i--){
                System.out.print(i);
                }
        }
}

The equals operator == tests to see if two values “are the same”, the reason I put those words in quote marks is because the idea of being the same sometimes is subtle. With plain arithmetical comparisons there is no problem. Thus

public class AreTheSame{
        public static void main(String argv[]){
                new AreTheSame();
        }
        AreTheSame(){
        int one = 1;
        int two = 2;
        int anothertwo=2;
        if(one==two){
                System.out.print("one=two");
        }
        if (two==anothertwo){
                System.out.print("one=two");
                }
        }
}

But subtle problems can come up if you are comparing Objects. Thus the following code will generate no output.

public class StringMatch{
        public static void main(String argv[]){
                new StringMatch();
        }
        StringMatch(){
        String s1 = new String("one");
        String s2 = new String("one");
        if(s1==s2){
                System.out.println("we have a match");
                }
        }
}       

This is because when applied to objects the == operator compares the memory address of the object rather than what the object “contains”. The generalised way around this is to use the equals operator for comparison thus.

public class StringMatch{
        public static void main(String argv[]){
                new StringMatch();
        }
        StringMatch(){
        String s1 = new String("one");
        String s2 = new String("one");
        /* using the equals method */
        if(s1.equals(s2)){
                System.out.println("we have a match");
                }
        }
}       

Java supports a “not equal” operator in the form of != .This returns true if its two operands “are not the same”. Just like with the other operators it is straightforward if you are performaning an arithmetical comparison but you need to be careful when comparing objects as by default the comparison will be on the memory address of the object rather than the actual value. The exclamation mark ! Can be used on its own to invert the result of another operation. In the following example the equals method is used to compare strings, but the boolean value that is returned is inverted, i.e. True is converted to false and False is converted to true.

/**
*@author Marcus Green
*
*/
public class NotEqual{
        public static void main(String argv[]){
        new NotEqual();
        }
        NotEqual(){
                int i = 1;
                int j = 2;
                /*The not equals operator*/
                if(i != j){
                        System.out.println("i is not equal to j");
                }
                String s1="one";
                String s2="two";
                /*The not operator */
                if(!s1.equals(s2)){
                        System.out.println("s1 is not equal to s2");
                }
        }
}                               



The assignment (=) operator

The assignment operator takes the value on its right and assigns it to the value on its left. Generally this is a straightforward operation but you can come across complications when dealing with different data types/sizes. Thus the following code will give a compile time error

public class BigAssign{

   public static void main(String argv[]){
                new BigAssign();
        }
        BigAssign(){
                byte b = 0;
                int i = 10;
                b=i;
        }
}

BigAssign.java:8: possible loss of precision
found   : int
required: byte
                b=i;
                  ^
1 error

The compiler is explicitly pointing out that there is a potential loss of precision. This is because the int data type can contain far larger numbers than the byte data type. If you knew for some reason that the int value would never exceed the maximum value that can be stored by a byte it is possible to force this assignment using what is known as a cast thus.

b=(byte) i;

This says convert the value of i to a byte value. If the current value of i is bigger than what can be stored in a byte then the results can be unpredictable. It's generally not a good idea to perform a cast unless you know exactly what you are doing.

Casting

The term casting is shorthand for type casting, or type conversion. For example you might have a method that expects a parameter of type int but the value you want to pass to it is of type Byte. The following code demonstrates implicit casting or coercion. The variable mybyte is automatically converted to an int.

public class MyCast{
        public static void main(String argv[]){
                MyCast mc = new MyCast();
        }
        MyCast(){
                byte mybyte=10;
                castMethod(mybyte);
        }
        public void castMethod(int i){
                System.out.print(i);
        }
}       

There is no problem in converting a byte type to an int type because there can be no loss of precision. An int is larger than a byte and is thus guaranteed to be able to store any byte value. If you try this the other way around, i.e. passing an int type to a method expecting a byte you will get a compile time error.

It is however possible to force conversion even if there might be a loss of precision.

What do you think the following code will output?

public class ForceCast{
        public static void main(String argv[]){
                new ForceCast();
        }
        ForceCast(){
                int i = 9999;
            byte j = (byte) i;
            System.out.print(j);            
        }
}

Casting Objects

If you are familiar with casting primitives the idea of casting objects may seem odd, after all objects don't have a size or the exact idea of precision like integers. Before considering casting objects its worth considering what assignments can be made without explicit casting. The following code will compile without error.

abstract class Animal{
        
}

public class Cat extends Animal{
boolean hasWhiskers=true;
        public static void main(String argv[]){
        Animal a;
        Cat c = new Cat();
        a =c;
        }
        public String getName(){
                return "Cat";
        }               
}



Note that I have marked the class Animal to be abstract as it makes no sense at all to ever instantiate an object of type Animal. After all, in the real world, every animal is a sort of animal, it is never a generic animal.

The reference called A of type animal is considered to be type compatible with the object Cat object c. This may seem counter-intuitive (it did to me) because it looks like the assignment will loose data. The Cat class has additional information, i.e. the hasWhiskers field and it looks like this information will be lost because of the assignment. This type of cast is called an upcast, because it goes up the hierarchy. Upcasting is an important and recommended technique particularly with interfaces, so it is something to get used to.

The use of the = sign when creating an object is not the same as when used to assign a value to a primitive. In this context the = operator effectively says that the Object implements at least the interface of the reference objects. It might implement less and that is OK. You can perform an upcasting anywhere, including when you pass a reference to a method. When I said that it is OK to upcast, that is only up to a point. If your reference has the type of a base class, you cannot call a method in the sub class that is not in the reference type. In the example given above, you cannot call

a.getName();

Because the a reference is of type Animal and the Animal class has no getName method. You can however cast the type of the reference to the type of the Object and get at the methods that have been added to that type. The following code will compile without error and access the getName method.

abstract class Animal{
        
}

public class Cat extends Animal{
boolean hasWhiskers=true;
        public static void main(String argv[]){
        Animal a;
        Cat c = new Cat();
        a =c;
        ((Cat)a).getName();
        }
        public String getName(){
                return "Cat";
        }               
}

The syntax I have used there is rather compact, you might make your code more readable by simply creating a new reference with the following syntax.

   Cat c2 = (Cat) a;
        c2.getName();

You cannot cast to incompatible or arbitrary class types.

abstract class Animal{
}

class Cat extends Animal{
}

class Dog extends Animal{
}

public class Menagerie{
        public static void main(String argv[]){
                Cat c = new Cat();
                Dog d = new Dog();
                /* wont work */
                c = d;
        }
}

This code generates the following error message

Menagerie.java:15: incompatible types
found   : Dog
required: Cat
                c = d;                 ^
        

Other sources

Operators according to the Sun Java tutorial
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html

The String API docs
http://java.sun.com/javase/6/docs/api/java/lang/String.html

Casting Objects
http://www.volantec.biz/castingObjects.htm

Bruce Eckel on Casting
http://www.codeguru.com/java/tij/tij0070.shtml




Previous
Index

Next