Registers are inside CPU, so they are the fastest, but have very limited number. The use of them is decided by compiler. For users they doesn't exist.
In RAM. Manipulated by stack pointer. When allocating memory, stack pointer is moved down, when releasing, stack pointer is moved up. Second fastest storage. Because to use stack the size and life time of the object must be known at compiling time, it can not be used for dynamic objects. Not used by Java for user-defined objects.
In RAM. Where Java stores all its objects. Slower than Stack.
Contains data that is available for the entire time of a program. Keyword static is used to specify it. Java objects are never placed in static storage.
For small, simple objects such as integers, to create them in heap is not efficient. So Java makes it a special case: use the approaches of C and C++ to create them as automatic objects, which are not manipulated with handles:
char c = 'x';
JVM determines the size of each primitive objects, which doesn't change on different machines. This makes Java more portable.
All numeric types are signed.
Java provides two classes for high-precision arbitrary-digit numbers: BigInteger and BigDecimal. They have all the methods as int and float, but you can not use operators.
All primitives are created on the stack and do not have handles. If you want to manipulate them with handles, for example, add them into collections such as Vector, you have to use associate wrapper to wrap the primitive number in a non-primitive object:
Character C = new Character('x');
Other wrappers:
Float f = new Float(12.34); Integer i = new Integer(1234); Double d = new Double(12.34d);
They have implemented methods such as toString, hashcode, equals, etc., and they have methods to convert strings into primitive types such as Integer.parseInt. So they are more powerful than primitive objects.
However, these wrappers are immutable. They can not be modified as primitives.
High-Precision NumbersJava provides two classes for high-precision arbitrary-digit numbers: BigInteger and BigDecimal. They have all the methods as int and float, but you can not use operators.
Default Values for PrimitivesWhen a primitive type is a class member, it is guaranteed to have a default value if it is not initialized:
Boolean false
Char '\u0000' (null)
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d
However, primitive-type objects are only automatically initialized as a class member. If you don't initialize a local variable, Java compiler will generate an error.
When compiler sees the following statements,
int i = 200; long l = i;
it will automatically convert the integer to long integer. However, if you write a statement to make a narrowing conversion like:
i = l;
compiler will refuse to make an implicit conversion - because a narrowing conversion may lose information - and prompt an error message asking for explicit casting like:
i = (int)l;
In case that the compiler can not figure out the type of a constant, you should explicitly mark its type:
Hexadecimal Leading 0x or 0X
Octal Leading 0 (zero)
Long Trailing l or L
Float Trailing f or F
Double Trailing d or D
For example, in such a statement
float f4 = 3.75e-47;
compiler will automatically take exponential numbers as doubles, so compiler will issue an error that you must use cast to convert double to float. To avoid this:
float f4 = 3.75e-47f;
If you perform any mathematical or bitwise operation on primitive types lower than int, such as char, byte or short, those values will be promoted to int before the calculation, and the result will be int. So if you want to assign the result back to the lower type, you have to use cast. But compound assignments do not require casts for char, byte or short.
When two types of objects are in an expression, the result will be the higher type. For example, when you calculate a double with a float, result will be a double.
Class String has a constructor which takes a byte array as argument, and it has a getBytes method which returns a byte array.
class Test { public static void main(String [] argu) { byte [] a = new byte[100]; System.out.println("byte[] length before getBytes is " + a.length); a = "Yesterday once more...".getBytes(); System.out.println("byte[] length before getBytes is " + a.length); String s = new String(a); System.out.println("String is \n" + s); } }
Output will be:
byte[] length before getBytes is 100 byte[] length before getBytes is 22 String is Yesterday once more...
From this example you can see that the getBytes method returns a byte array, which is assigned to the left operand. The length of the array is also changed during the assignment.
Making String immutable enables String to share on memories. For example, when you say
String s1 = "Hello"; String s2 = "Hello";
Most probably handle s1 and s2 are pointing to the same memory location containing string "Hello". That's why in most cases you can use "==" to check if two strings are equal - because "==" checks if two handles are pointing to the same address.
The mutable version of class String is StringBuffer, which provides amending methods like append and insert.
Because String is immutable, when you say
String a = "aa" + "bb" + "cc";
the compiler does not just append "bb" to the end of "aa", then append "cc" to the end of "aabb". It creates a new String "aabb" from "aa" and "bb", then create another new String "aabbcc" from "aabb" and "cc". To avoid this overhead, when you have lots of appending things to do, use mutable StringBuffer:
StringBuffer a = ""; a.append("aa").append("bb").append("cc");
When operands are joined with "+" and one of them is a string, compiler will automatically turn the rest of them into strings:
int x = 0, y = 1, z = 2; System.out.println("ABC " + x + y + z);
Output will be "ABC123" instead of "ABC3".
The length of a string is the number of characters in the string. The first character's index is 0. These two characteristics are like C++. But one thing is different: its method substring(7, 15) starts from the 7th character and ends from the 14th character, not the 15th. This way you can derive the length of the substring simply by using 15 - 7 = 8.
import java.io.*; public class TestContentLength { public static void main(String [] args) { String string = "Content-length: 23"; int length = 0; System.out.println("***" + string.substring(0, 16) + "***"); System.out.println("Length of string is " + string.length()); length = Integer.parseInt(string.substring(16)); System.out.println("The number is " + length); } }
Output will be:
***Content-length: *** Length of string is 18 The number is 23