Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / First Aid / September 2004

Tip: Looking for answers? Try searching our database.

byte, int....professor responds, confusion increases.

Thread view: 
Todd - 14 Sep 2004 03:25 GMT
Hi all,

I'm am taking an introduction to Java class at my university and I'm
having trouble with some of the concepts.  The IDE we are using is
jGrasp and the text for the class is Java Software Solutions 3rd
edition, Lewis & Loftus. I would appreciate it if anyone could help me
out.

We are currently going over primitive data types and data conversion.
I was playing around with bytes and I ran into a problem.  I contacted
my professor and she responded but her answer has confused me more
than before I asked.

Here is the message I sent to my professor:

I'm working with the "byte" primitive data type in Java and I have a
strange problem.  Could you help me understand why the compiler is
giving me an error?  I have attached a source file with an example of
the problem.  It seems that some type of data conversion is going on
behind the scenes that I can't figure out.

Here is a copy of the source file I sent with the message:

public class ByteMath {
    public static void main(String[] args) {
        byte x = 10, y = 10;
       
        // x * y = 100 which should be in byte's range of {-128,127}
        byte big = x * y;
       
        System.out.println(big);
    }
}

Here is message I received from the professor relating to my question:

The following statement contains a "hidden" conversion request from
int to byte, which is
illegal in Java:
byte x = 10;
The constant, 10, is considered to be of type int. As explained on
page 86, this is
considered a "widening" conversion and cannot be accomplished in an
assignment,
typically.  You might experiment with casting the conversion to see
how/if that works.
For example
byte x = (byte)10;

I've solved my problem by casting but I'm pretty confused still.

I don't understand how "byte x = 10;" is illegal in Java because the
constant 10 is considered to be of type int.  I also can't understand
how trying to put a int in a byte is widening.

Again, thanks for any help in helping me understand what is going on.

-Todd
Chris Smith - 14 Sep 2004 05:48 GMT
> I'm am taking an introduction to Java class at my university and I'm
> having trouble with some of the concepts.  The IDE we are using is
> jGrasp and the text for the class is Java Software Solutions 3rd
> edition, Lewis & Loftus. I would appreciate it if anyone could help me
> out.

Sure.  See below.

> public class ByteMath {
>     public static void main(String[] args) {
[quoted text clipped - 6 lines]
>     }
> }

> Here is message I received from the professor relating to my question:
>
[quoted text clipped - 10 lines]
> For example
> byte x = (byte)10;

I believe your professor is mistaken about your problem, and the
initialization is perfectly valid.  If you want to know more, read on.  
Otherwise, skip the next couple paragraphs, as they aren't needed to
answer your question.  Your more direct answer is below that.

Indeed, the initializations (x = 10, y = 10) are perfectly legal.  
However, understanding why they are legal is rather complex.  Your
professor is quite close to being right here.  Specifically, 10 *is* an
'int' in Java, as your professor said, and an 'int' *can't* be assigned
normally to a variable of type 'byte' (because there are legal values
for 'int' that aren't legal values of 'byte').  To correct a simple typo
on your professor's part, this is called a narrowing conversion, not a
widening conversion.

However, the initializations are perfectly legal.  That's because the
Java Language Specification makes a special exception for this case in
section 5.2, provided that the expression is compile-time constant, the
target variable is of a small integer type, and that the known value of
the expression is legal for the target data type.  This implicit
narrowing conversion is something of an oddity; it only applies to
assignment (never to parameter passing, for example), and only if those
conditions are met.

> I've solved my problem by casting but I'm pretty confused still.
>
> I don't understand how "byte x = 10;" is illegal in Java because the
> constant 10 is considered to be of type int.  I also can't understand
> how trying to put a int in a byte is widening.

Your actual problem is in the line:

   byte big = x * y;

Multiplication of bytes is not strictly possible in Java.  Instead, when
performing any arithmetic on variables of type 'byte', they are first
converted to a type of 'int'.  Because of that, the result is an 'int',
regardless of the types of the two variables you are multiplying.  (See
section 5.6.2 of the language spec for the official proclamation of this
fact.  The important bits are that (1) multiplication performs "binary
numeric promotion", as seen in the second bulleted list, and (2) that
"binary numeric promotion will produce an 'int' from 'byte' inputs, as
seen in the first bulleted list.)

The fact that the result (100) fits into a type byte is irrelevant in
this case.  The compiler does its reasoning with data types, not with
values.

(Again, stop paying attention if the next bit confuses you... but it's
worth pointing out.

You are very close to having an exception that falls under section 5.2
of the JLS again; the only thing you are missing is that "a * b" is NOT
a compile-time constant.  You can remedy this by declaring the variables
as 'final', as follows.  This code should compile:

   final byte a = 10, b = 10;
   byte big = a * b;

But because the 'final' keyword is missing in your example, section 5.2
doesn't apply, and you are stuck with an 'int' instead.)

> Again, thanks for any help in helping me understand what is going on.

I hope I did that.  If not, please feel free to ask more questions.

Signature

www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation

Todd - 17 Sep 2004 15:09 GMT
> > I'm am taking an introduction to Java class at my university and I'm
> > having trouble with some of the concepts.  The IDE we are using is
[quoted text clipped - 94 lines]
>
> I hope I did that.  If not, please feel free to ask more questions.

So, constant numbers such as 10, 11,..., 256 are all considered
integers by default.  Then as you said the Java language specification
has a special way of dealing with this specific type of implicit data
conversion.  This I follow, however, I cannot understand why there is
no data conversion when the bytes are declared as constants.  At the
most primitive level what exactly is going on different in the
assignment:

    byte a = 10;

And the assignment:

    final byte a = 10;

Or is the difference in the declaration of the declaration?  From what
I've gathered in my text the declaration of a byte reserves 8bits of
space in memory while integer declarations reserve 32bits of space.
The number 10 in binary is represented as 00001010 correct?  So if
possible please explain how memory is being allocated and what is
being stored.

I understand how to solve the original problem.  Thank you very much.
I realize this may be splitting hairs but I feel that I should make a
valid effort to understand what is going on behind the scenes if I
wish to become a good programmer.

Oh, one more thing.  If constants such as 25 are integers then is the
uppermost limit of an integer + 1 still considered to be an integer or
does it become a long.

-Todd
Chris Smith - 17 Sep 2004 16:33 GMT
> So, constant numbers such as 10, 11,..., 256 are all considered
> integers by default.  Then as you said the Java language specification
[quoted text clipped - 9 lines]
>
>     final byte a = 10;

Both of these assignments work fine.  The difference is that in the
second case, 'a' cannot be changed to a different value later.  That's
what the 'final' keyword means.

The reason that final matters, in this case, is that the compiler has
certain rules for deciding when it "knows" the value of a variable.  
Such variables, whose values are known to the compiler, are referred to
as compile-time constants.  One of these rules is that for a variable in
an expression to be a compile-time constant, the variable has to be
declared with the 'final' qualifier.  That's because you could change
the value of a non-final variable, so it isn't really a constant.

Another rule for compile-time constants says that if you multiply
together two compile-time constants, the result is also a compile-time
constant.  The result is that when considering the expression 'a * b',
it is a compile-time constant *only* of both a and b are already
compile-time constants, which means they need to be declared as final.

The rule for implicit assignment conversion of the int to a byte in Java
requires that the value be a compile-time constant.  So there are a
couple levels of indirection there, but that's why declaring 'a' and
'b' as final makes your code work.

> Or is the difference in the declaration of the declaration?  From what
> I've gathered in my text the declaration of a byte reserves 8bits of
> space in memory while integer declarations reserve 32bits of space.

Sort of.  If that mental model helps you understand the behavior of a
Java program, then go ahead and use it.  However, you should understand
that it's only a model.  The Java Language Specification doesn't specify
how much memory is reserved to hold variables; it only specifies the
results of doing things to variables.  8 bits would be enough memory to
correctly implement operations on the 'byte' data type, but that doesn't
mean the program couldn't reserve more.

In practice, because of the details of implementation of modern CPUs,
things are different.  If you could peek inside the system as your
application runs, you'd be likely to discover that it has actually set
aside 32 bits, or perhaps even 64 bits on certain processors, to hold a
local variable declared as type 'byte'.  In fact, certain details of the
Java bytecode format make this almost a sure bet for Java source that's
compiled to bytecode.

So the lesson is: mental models are fine, but don't confuse them with
reality.  Especially if you start thinking about improving the memory or
time efficiency of your code at a low level, you will need to abandon
that simplistic model of what's occurring.  For example, replacing use
of the 'int' data type with 'byte' for local variables is unlikely to
save memory; but doing the same for an array is a more promising
prospect.

> The number 10 in binary is represented as 00001010 correct?  So if
> possible please explain how memory is being allocated and what is
> being stored.

The Java literal "10" is represented as:

   0000 0000 0000 0000 0000 0000 0000 1010

That's the same as what you said, except you should remember that it's
an integer, and therefore 32 bits long.  If that number is converted to
a "byte" data type (either through a cast, or an implicit assignment
conversion of a compile-time constant), then it becomes:

   0000 1010

(though recall that this still may be stored in a 32-bit or even 64-bit
slot in implementation.)

> I realize this may be splitting hairs but I feel that I should make a
> valid effort to understand what is going on behind the scenes if I
> wish to become a good programmer.

Let me make a recommendation, then.  You will need to come to terms with
the difference between specified behavior and actual implementation.  In
this message, we've crossed that boundary several times.  The original
question that you asked dealt with specification.  Now we've crossed
into implementation realm.  There will be no end to confusion if you mix
up the two.

All the rules about implicit and explicit conversions, etc. that have
been discussed to this point are rules created as part of the Java
programming language.  They are *not*, for the most part, related to the
implementation of arithmetic in any CPU.  They are chosen instead
because it creates a safer programming environment in which you are less
likely to make a mistake.

When you begin talking about actual implementation, then you need to do
one of two things: either restrict your discussion to the probability of
certain implementations, as I have done above; or pick a specific
implementation (e.g., "Sun's reference implementation of the Java
virtual machine for Windows, version 1.4.2_05") instead of just "Java".

> Oh, one more thing.  If constants such as 25 are integers then is the
> uppermost limit of an integer + 1 still considered to be an integer or
> does it become a long.

Section 3.10.1 of the Java Language Specification answers your question.  
It says:

   A compile-time error occurs if a decimal literal of type int is
   larger than 2147483648 (2^31), or if the literal 2147483648 appears
   anywhere other than as the operand of the unary - operator, or if a
   hexadecimal or octal int literal does not fit in 32 bits.

So an integer literal that's too large to fit in an int causes the
compiler to give an error.  You can learn from the same section that
appending the letter 'L' to the end of a literal makes it of type
'long'.  That would be the answer.  So you can *not* write:

   long val = 99999999999;  // compiler error

but you can write:

   long val = 99999999999L; // okay

Signature

www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation

Tony Morris - 15 Sep 2004 01:01 GMT
> Hi all,
>
[quoted text clipped - 54 lines]
>
> -Todd

Your professor is incorrect.
This will compile quite happily, since x is assigned to a compile-time
constant value which is within the range of a byte.
byte x = 10;

The problem is the following line
byte big = x * y;
Neither x or y are constants and so there is an implicit conversion to type
int - you are attempting an implicit narrowing conversion, which fails
compilation.
There are two things you can do:
1. you can make x and y constants, in which case, they will fall within the
range of a byte.
2. you can perform an *explicit* narrowing conversion.

1.
final byte x = 10; // make x a constant
final byte y = 10; // make y a constant

2.
byte big = (byte)(x * y); // explicit narrowing conversion.

Signature

Tony Morris
http://xdweb.net/~dibblego/



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.