When I should go for wrapper class over primitive types? Or On what circumstance I should choose between wrapper / Primitive types?
Others have mentioned that certain constructs such as Collections require objects and that objects have more overhead than their primitive counterparts (memory & boxing).
Another consideration is:
It can be handy to initialize Objects to null or send null parameters into a method/constructor to indicate state or function. This can't be done with primitives.
Many programmers initialize numbers to 0 (default) or -1 to signify this, but depending on the scenario, this may be incorrect or misleading.
This will also set the scene for a NullPointerException when something is being used incorrectly, which is much more programmer-friendly than some arbitrary bug down the line.
Generally, you should use primitive types unless you need an object for some reason (e.g. to put in a collection). Even then, consider a different approach that doesn't require a object if you want to maximize numeric performance. This is advised by the documentation, and this article demonstrates how auto-boxing can cause a large performance difference.
In my opinion, if my class members are wrapper variables, it does not rely on default values, which is developer friendly behavior.
1.
class Person {
int SSN ; // gets initialized to zero by default
}
2.
class PersonBetter {
Integer SSN; //gets initialized to null by default
}
In the first case, you cannot keep SSN value uninitialized. It may hurt if you are not checking if the value was set before you attempt to use it.
In the second case, you can keep SSN initialized with null. Which can lead to NullPointerException but it is better than unknowingly inserting default values(zero) as SSN into to the database whenever you attempt to use it without initializing SSN field.
I would only use the wrapper types if you have to.
In using them you don't gain much, besides the fact that they are Objects.
And, you lose overhead in memory usage and time spent boxing/unboxing.
Practically I had encountered a situation where use of wrapper class can be explained.
I created a service class which had a long type variable
If the variable is of type long - when not initialized, it will be set to 0 - this will be confusing to the user when displayed in GUI
If the variable is of type Long - when not initialized, it will be set to null - this null value won't show up in GUI.
This applies to Boolean as well where values can be more confusing when we use primitive boolean(as default value is false).
Collections are the typical case for the simple Java wrapper objects. However, you might consider giving the Wrapper a more specific meaning in the code (value object).
IMHO there's almost always a benefit to use value objects when it boils down to readability and maintainance of the code. Wrapping simple data structures inside of objects when they have certain responsibilities often simplifies the code. This is something that is very important in Domain-Driven Design.
There is of course the performance issue, but I tend to ignore that until I have the possibility to measure the performance with proper data and do more directed actions towards the problematic area. It might also be easier to understand the performance issue if the code is easy to understand as well.
performance of applications that are dominated by numerical calculations can benefit greatly from the use of primitives.
primitive types, one uses the == operator, but for wrapper the preferred choice is to call the equals() method.
"Primitive types considered harmful" because they mix "procedural semantics into an otherwise uniform object-oriented model.
Many programmers initialize numbers to 0 (default) or -1 to signify this, but depending on the scenario, this may be incorrect or misleading.
If you want to use Collections, you must use Wrapper classes.
Primitive types, are used for arrays. Also, to represent data that has no behaviour,for example, a counter, or a boolean condition.
Since autoboxing, the "when to use primitive or wrapper" frontier has become quite fuzzy.
But remember, Wrappers are objects, so you get all the fancy Java features. For example, you can use reflexion to create Integer objects, but not int values. Wrapper classes also have methods such as valueOf.
When to Use Primitive Types
When doing a large amount of calculations, primitive types are always faster — they have much less overhead.
When you don’t want the variable to be able to be null.
When you don’t want the default value to be null.
If the method must return a value
When to Use Wrapper Class
When you are using Collections or Generics — it is required
If you want the MIN_SIZE or MAX_SIZE of a type.
When you want the variable to be able to be null.
When you want to default value to be null.
If sometimes the method can return a null value.
from https://medium.com/#bpnorlander/java-understanding-primitive-types-and-wrapper-objects-a6798fb2afe9
If you want to create a value type. Something like a ProductSKU or AirportCode.
When a primitive type (string in my examples) defines equality, you'll want to override equality.
Primitive values in Java are not object. In order to manipulate these values as object the java.lang package provides a wrapper class for each of the primitive data type.
All Wrapper classes are final. The object of all wrapper classes that can be initiated are immutable that means the value in the wrapper object can not be changed.
Although, the void class is considered a wrapper class but it does not wrap any primitive values and is not initiable. It does not have public constructor, it just denotes a class object representing the keyword void.
Related
I'm new to the java language. I'm a php developer. There exist a lot of Variable handling Functions in the php language.
But I find it hard to imagine there aren't any built in functions that check whether value is numeric, is null, etc...
Can anyone explain why this is? Why does java not provide simple functions such as these?
PHP lets you store almost any value in any variable, and converts between types as necessary. Java does not automatically convert between most types - if you want a conversion, you have to do it yourself.
All of the is_something functions would be pointless - you know the type of a variable since you declared it!
If you have a reference to an object, you can determine the type of the object (not the variable) that it refers to using instanceof or reflection:
Object x = "hello";
// the variable x is of type Object, but it refers to a String. How can we tell?
System.out.println(x instanceof Integer); // prints "false"
System.out.println(x instanceof String); // prints "true"
System.out.println(x.getClass().getName()); // prints "java.lang.String"
However, most of the time, this simply isn't something you need to do.
So, all of the is_something functions are unnecessary, and all of the somethingval functions wouldn't fit well in the language (although there's no technical reason they couldn't exist). What else is there?
get_defined_vars - again, redundant. You know what variables are defined because you defined them!
empty (returns true if a variable doesn't exist or contains false). Using a variable that doesn't exist is a compile-time error, so you can just use thing == false (or !thing if it's a boolean) instead of empty(thing).
get_resource_type - the closest match in Java is thing.getClass().getName() instead of get_resource_type(thing).
gettype - useless for the same reason the is_something functions are useless.
import_request_variables - The language Java has no built-in concept of GET variables, POST variables or cookies. Even if it did, this wouldn't work very well, because you'd have to declare all the variables anyway.
is_null - use thing == null instead of is_null(thing).
isset - again, you can't use variables that don't exist. So just use thing != null instead of isset(thing).
serialize and unserialize - Java has a serialization system, which is more complex but more flexible. Look up ObjectOutputStream and ObjectInputStream.
settype - makes no sense, as the type of a variable cannot be changed.
strval - use String.valueOf.
unset - makes no sense. Variables exist until the end of their scope.
print_r and var_dump and var_export - the only ones that might actually be useful and don't already exist. Sadly, it just doesn't exist, though you can get something similar if you override toString in all of your classes.
But i imagine any in build function is not check a value is numeric, is null, etc...
Why java is not provide simple functions such like this?
First reason: Java supports method overloading.
In Java, you typically don't write a single method that handle all sorts of arguments with all sorts of different types. Instead, you can write multiple overloads of the same method: same method name with different declared argument types, and/or different numbers of declared arguments.
The compiler sorts out at compile time which overloaded method to call based on the static types of the argument expressions.
In this model, there is no need to a bunch of functions for sorting out whether values are numeric, null, etcetera.
Second reason: Java does not allow primitive types and object types to be used interchangeably.
For example you cannot declare an argument type that would accept both an int value and a String value. And an int argument type can never accept a null.
(Actually, the primitive wrapper classes like Integer and Java 5's addition of autoboxing / unboxing tend to blur the distinction. But the underlying hard distinction between primitive and reference types remains. Autoboxing is syntactic sugar.)
Third reason: There is instanceof and testing for == null.
As #Malik points out, in the cases where the tests do make sense in Java, they can be implemented with built-in constructs, without resorting to library "functions". The functions are unnecessary.
(AFAIK, no mainstream 3rd-party utility library has implemented the equivalent of the PHP functions you are talking about ... which supports the view that they are unnecessary. If enough people thought the functions were necessary, there would be a library and we would know about it.)
It is also worth noting that most of the "variable handling functions" are to do with dynamically declared variables in PHP. Java doesn't support that. If you want to implement a dynamic binding between names (strings) and values in Java, use a Map class.
PHP as you are aware doesn't tend to care what you store in a variable, you declare a name, give it a value and it will try and interpret it itself. In Java, you explicitly declare the type of variable you would like.
Something like an integer (whole number) can be presented by the primitive data type int, so you could use
int myNumber = 7;
And the code would know for sure that this is an integer, as you have explicitly stated that this is the case. Refer to this page for other java primitives.
If you are using a String (which is an object) in Java, you can use the function isEmpty() to determine if there are any characters in it. You can do a check on objects in Java to see if they have been instantiated by using object == null.
Some compilers will actually give you warnings if you have not initialised variables before you check them, whether these are objects or primitives.
To get a good feel of how data types work in Java, refer to the Oracle documentation I linked, it is very useful, and ill contain a lot of information of other aspects of Java you may have questions with.
First of all why check variable type when you explicitly define a variable with a type. Secondly, you can check the type in Java although you should already know the type.
Integer x = 3;
if (x instanceof Integer) {
System.out.println("Integer");
}
String s = "test";
if (s instanceof String) {
System.out.println("String");
}
I am confused about when to use primitive vs. non-primitive(?) types (i.e. int vs. Integer) in Java. I realize that in some places you can't use primitive types (for example when making use of generics). But what about in "normal" code? Is there a performance penalty for using non-primitive types? What about when working with Android?
***My question is very similar to this question, which was discovered by one of the posters below. The answers to the linked question give additional insights into this question, which are not covered below.
*** "non-primitive" types are officially referred to as reference types.
Short answer: An int is a number; an Integer is a pointer that can reference an object that contains a number. Using Integer for arithmetic involves more CPU cycles and consumes more memory. An int is not an object and cannot passed to any method that requires objects (just like what you said about Generics).
Non-primitive types are objects. They have to be dynamically allocated, garbage collected, and checked for null-ness (although some of these operations may get removed by an optimizing compiler). Reading their actual value requires loading from a pointer. Primitive types are values. They generally take up less space and are faster to access.
A good rule of thumb is, use primitive types unless you need polymorphism, in which case use the corresponding object.
There is a slight penalty for converting between the types (autoboxing). Also int will have a bit less overhead so I would always go with int if you can.
Also see this question: When to use primitive and when reference types in Java
In Java, int is a primitive data type, while Integer is a Wrapper class.
int, being a primitive data type has less flexibility. We can only store the binary value of an integer in it.
Since Integer is a wrapper class for int data type, it gives us more flexibility in storing, converting and manipulating integer data.
Integer is a class and thus it can call various in-built methods defined in the class. Variables of type Integer store references to Integer objects, just as with any other reference (object) type.
You can find a more detailed explanation here.
As an OO purist, you would likely shun the primitives altogether and damn the performance costs and lack of postfix operators. (Yes, there is a performance cost.) You may also adopt this approach simply from extensibility considerations as a designer (without necessarily being hung up on purity.)
As a practical matter (outside of theoretical and aesthetic questions), use the primitives everywhere you can and use the object version where you can't use primitives. (You already mentioned one such case. The language and APIs will drive this decision.)
As a performance freak, you would likely shun the object versions and you may not really care too deeply if you step on a few OO golden rules and sacrosanct no-goes: performance is king and you make your decisions accordingly.
I'd recommend option 2 as a good place to start until you develop your own dogmatic preferences! :)
My view: Using Integer as parameters or return values allows one thing that primitive ints don't allow: Using null. But is this a good idea? I think it rarely ever is.
As far as performance is concerned: The compiler will optimize your code to some degree, so that is most of the time not a real concern.
When I should go for wrapper class over primitive types? Or On what circumstance I should choose between wrapper / Primitive types?
Others have mentioned that certain constructs such as Collections require objects and that objects have more overhead than their primitive counterparts (memory & boxing).
Another consideration is:
It can be handy to initialize Objects to null or send null parameters into a method/constructor to indicate state or function. This can't be done with primitives.
Many programmers initialize numbers to 0 (default) or -1 to signify this, but depending on the scenario, this may be incorrect or misleading.
This will also set the scene for a NullPointerException when something is being used incorrectly, which is much more programmer-friendly than some arbitrary bug down the line.
Generally, you should use primitive types unless you need an object for some reason (e.g. to put in a collection). Even then, consider a different approach that doesn't require a object if you want to maximize numeric performance. This is advised by the documentation, and this article demonstrates how auto-boxing can cause a large performance difference.
In my opinion, if my class members are wrapper variables, it does not rely on default values, which is developer friendly behavior.
1.
class Person {
int SSN ; // gets initialized to zero by default
}
2.
class PersonBetter {
Integer SSN; //gets initialized to null by default
}
In the first case, you cannot keep SSN value uninitialized. It may hurt if you are not checking if the value was set before you attempt to use it.
In the second case, you can keep SSN initialized with null. Which can lead to NullPointerException but it is better than unknowingly inserting default values(zero) as SSN into to the database whenever you attempt to use it without initializing SSN field.
I would only use the wrapper types if you have to.
In using them you don't gain much, besides the fact that they are Objects.
And, you lose overhead in memory usage and time spent boxing/unboxing.
Practically I had encountered a situation where use of wrapper class can be explained.
I created a service class which had a long type variable
If the variable is of type long - when not initialized, it will be set to 0 - this will be confusing to the user when displayed in GUI
If the variable is of type Long - when not initialized, it will be set to null - this null value won't show up in GUI.
This applies to Boolean as well where values can be more confusing when we use primitive boolean(as default value is false).
Collections are the typical case for the simple Java wrapper objects. However, you might consider giving the Wrapper a more specific meaning in the code (value object).
IMHO there's almost always a benefit to use value objects when it boils down to readability and maintainance of the code. Wrapping simple data structures inside of objects when they have certain responsibilities often simplifies the code. This is something that is very important in Domain-Driven Design.
There is of course the performance issue, but I tend to ignore that until I have the possibility to measure the performance with proper data and do more directed actions towards the problematic area. It might also be easier to understand the performance issue if the code is easy to understand as well.
performance of applications that are dominated by numerical calculations can benefit greatly from the use of primitives.
primitive types, one uses the == operator, but for wrapper the preferred choice is to call the equals() method.
"Primitive types considered harmful" because they mix "procedural semantics into an otherwise uniform object-oriented model.
Many programmers initialize numbers to 0 (default) or -1 to signify this, but depending on the scenario, this may be incorrect or misleading.
If you want to use Collections, you must use Wrapper classes.
Primitive types, are used for arrays. Also, to represent data that has no behaviour,for example, a counter, or a boolean condition.
Since autoboxing, the "when to use primitive or wrapper" frontier has become quite fuzzy.
But remember, Wrappers are objects, so you get all the fancy Java features. For example, you can use reflexion to create Integer objects, but not int values. Wrapper classes also have methods such as valueOf.
When to Use Primitive Types
When doing a large amount of calculations, primitive types are always faster — they have much less overhead.
When you don’t want the variable to be able to be null.
When you don’t want the default value to be null.
If the method must return a value
When to Use Wrapper Class
When you are using Collections or Generics — it is required
If you want the MIN_SIZE or MAX_SIZE of a type.
When you want the variable to be able to be null.
When you want to default value to be null.
If sometimes the method can return a null value.
from https://medium.com/#bpnorlander/java-understanding-primitive-types-and-wrapper-objects-a6798fb2afe9
If you want to create a value type. Something like a ProductSKU or AirportCode.
When a primitive type (string in my examples) defines equality, you'll want to override equality.
Primitive values in Java are not object. In order to manipulate these values as object the java.lang package provides a wrapper class for each of the primitive data type.
All Wrapper classes are final. The object of all wrapper classes that can be initiated are immutable that means the value in the wrapper object can not be changed.
Although, the void class is considered a wrapper class but it does not wrap any primitive values and is not initiable. It does not have public constructor, it just denotes a class object representing the keyword void.
On the very high level, I know that we need to "wrap" the primitive data types, such as int and char, by using their respective wrapper classes to use them within Java collections.I would like to understand how Java collections work at the low level by asking:"why do we need to wrap primitive data types as objects to be able to use them in collections?"I thank you in advance for your help.
Because Java collections can only store Object References (so you need to box primitives to store them in collections).
Read this short article on Autoboxing for more info.
If you want the nitty gritty details, it pretty much boils down to the following:
Local Primitives are stored on the Stack. Collections store their values via a reference to an Object's memory location in the Heap. To get that reference for a local primitive, you have to box (take the value on the Stack and wrap it for storage on the Heap) the value.
At the virtual machine level, it's because primitive types are represented very differently in memory compared to reference types like java.lang.Object and its derived types. Primitive int in Java for example is just 4 bytes in memory, whereas an Object takes up at minimum 8 bytes by itself, plus another 4 bytes for referencing it. Such design is a simple reflection of the fact that CPUs can treat primitive types much more efficiently.
So one answer to your question "why wrapper types are needed" is because of performance improvement that it enables.
But for programmers, such distinction adds some undesirable cognitive overhead (e.g., can't use int and float in collections.) In fact, it's quite possible to do a language design by hiding that distinction --- many scripting languages do this, and CLR does that. Starting 1.5, Java does that, too. This is achieved by letting the compiler silently insert necessary conversion between primitive representation and Object representation (which is commonly referred to as boxing/unboxing.)
So another answer to your question is, "no, we don't need it", because the compiler does that automatically for you, and to certain extent you can forget what's going on behind the scene.
Read all of the answers, but none of them really explains it simply in layman terms.
A wrapper class wraps(encloses) around a data type (can be any primitive data type such as int, char, byte, long) and makes it an object.
Here are a few reasons why wrapper classes are needed:
Allows null values.
Can be used in collection such as List, Map, etc.
Can be used in methods which accepts arguments of Object type.
Can be created like Objects using new ClassName() like other objects:
Integer wrapperInt = new Integer("10");
Makes available all the functions that Object class has such as clone(), equals(), hashCode(), toString() etc.
Wrapper classes can be created in two ways:
Using constructor:
Integer i = new Integer("1"); //new object is created
Using valueOf() static method:
Integer i = Integer.valueOf("100"); //100 is stored in variable
It is advised to use the second way of creating wrapper classes as it takes less memory as a new object is not created.
To store the Primitive type values in Collection. We require Wrapper classes.
Primitive data types can't be referenced as memory addresses. That's why we need wrappers which serve as placeholders for primitive values. These values then can be mutated and accessed, reorganized, sorted or randomized.
Collection uses Generics as the bases. The Collection Framework is designed to collect, store and manipulate the data of any class. So it uses generic type. By using Generics it is capable of storing the data of ANY CLASS whose name you specify in its declaration.
Now we have various scenario in which want to store the primitive data in the same manner in which the collection works. We have no way to store primitive data using Collection classes like ArrayList, HashSet etc because Collection classes can store objects only. So for storing primitive types in Collection we are provided with wrapper classes.
Edit:
Another benefit of having wrapper classes is that absence of an object can be treated as "no data". In case of primitive, you will always have a value.
Say we have method signature as
public void foo(String aString, int aNumber)
you can't make aNumber as optional in above method signature.
But if you make signature like:
public void foo(String aString, Integer aNumber)
you have now made aNumber as optional since user can pass null as a value.
See Boxing and unboxing: when does it come up?
It's for C#, but the same concept apply to Java. And John Skeet wrote the answer.
Well, the reason is because Java collections doesn't differentiate between primitive and Object. It processes them all as Object and therefore, it will need a wrapper. You can easily build your own collection class that doesn't need wrapper, but at the end, you will have to build one for each type char, int, float, double, etc multiply by the types of the collections (Set, Map, List, + their implementation).
Can you imagine how boring that is?
And the fact is, the performance it brings by using no wrapper is almost negligible for most applications. Yet if you need very high performance, some libraries for primitive collections are also available (e.g. http://www.joda.org/joda-primitives/)
Wrapper classes provide useful methods related to corresponding data types which you can make use of in certain cases.
One simple example. Consider this,
Integer x=new Integer(10);
//to get the byte value of 10
x.byteValue();
//but you can't do this,
int x=10;
x.byteValue(); //Wrong!
can you get the point?
If a variable is known to either hold a specific bit pattern representing null or else information which can be used to locate a Java Virtual Machine object header, and if the method for reading an object header given a reference will inherently trap if given the bit pattern associated with null, then the JVM can access the object identified by the variable on the assumption that there is one. If a variable could hold something which wasn't a valid reference but wasn't the specific null bit pattern, any code which tried to use that variable would have to first check whether it identified an object. That would greatly slow down the JVM.
If Object derived from Anything, and class objects derived from Object, but primitives inherited from a different class derived from Anything, then in a 64-bit implementation it might be practical to say that about 3/4 of the possible bit patterns would represent double values below 2^512, 1/8 of them to represent long values in the range +/- 1,152,921,504,606,846,975, a few billion to represent any possible value of any other primitve, and the 1/256 to identify objects. Many kinds of operations on things of type Anything would be slower than with type Object, but such operations would not be terribly frequent; most code would end up casting Anything to some more specific type before trying to work with it; the actual type stored in the Anything would need to be checked before the cast, but not after the cast was performed. Absent a distinction between a variable holding a reference to a heap type, however, versus one holding "anything", there would be no way to avoid having the overhead extend considerably further than it otherwise would or should.
Much like the String class, Wrappers provide added functionality and enable the programmer to do a bit more with the process of data storage. So in the same way people use the String class like....
String uglyString = "fUbAr";
String myStr = uglyString.toLower();
so too, they can with the Wrapper. Similar idea.
This is in addition to the typing issue of collections/generics mentioned above by Bharat.
because int does not belongs any class .
we convert datatype(int) to object(Interger)
This is not a question of what is boxing and unboxing,
it is rather why do languages like Java and C# need that ?
I am greatly familiar wtih C++, STL and Boost.
In C++ I could write something like this very easily,
std::vector<double> dummy;
I have some experience with Java, but I was really surprised because I had to write something like this,
ArrayList<Double> dummy = new ArrayList<Double>();
My question, why should it be an Object, what is so hard technically to include primitive types when talking about Generics ?
what is so hard technically to include primitive types when talking about Generics ?
In Java's case, it's because of the way generics work. In Java, generics are a compile-time trick, that prevents you from putting an Image object into an ArrayList<String>. However, Java's generics are implemented with type erasure: the generic type information is lost during run-time. This was for compatibility reasons, because generics were added fairly late in Java's life. This means that, run-time, an ArrayList<String> is effectively an ArrayList<Object> (or better: just ArrayList that expects and returns Object in all of its methods) that automatically casts to String when you retrieve a value.
But since int doesn't derive from Object, you can't put it in an ArrayList that expects (at runtime) Object and you can't cast an Object to int either. This means that the primitive int must be wrapped into a type that does inherit from Object, like Integer.
C# for example, works differently. Generics in C# are also enforced at runtime and no boxing is required with a List<int>. Boxing in C# only happens when you try to store a value type like int in a reference type variable like object. Since int in C# inherits from Object in C#, writing object obj = 2 is perfectly valid, however the int will be boxed, which is done automatically by the compiler (no Integer reference type is exposed to the user or anything).
Boxing and unboxing are a necessity born out of the way that languages (like C# and Java) implement their memory allocation strategies.
Certain types are allocated on the stack and other on the heap. In order to treat a stack-allocated type as a heap-allocated type, boxing is required to move the stack-allocated type onto the heap. Unboxing is the reverse processes.
In C# stack-allocated types are called value types (e.g. System.Int32 and System.DateTime) and heap-allocated types are called reference types (e.g. System.Stream and System.String).
In some cases it is advantageous to be able to treat a value type like a reference type (reflection is one example) but in most cases, boxing and unboxing are best avoided.
I believe this is also because primitives do not inherit from Object. Suppose you have a method that wants to be able to accept anything at all as the parameter, eg.
class Printer {
public void print(Object o) {
...
}
}
You may need to pass a simple primitive value to that method, like:
printer.print(5);
You would be able to do that without boxing/unboxing, because 5 is a primitive and is not an Object. You could overload the print method for each primitive type to enable such functionality, but it's a pain.
I can only tell you for Java why it doesn't support primitve types in generics.
First there was the problem that the question to support this everytime brought on the discussion if java should even have primitive types. Which of course hindered the discussion of the actual question.
Second the main reason not to include it was that they wanted binary backward compatibility so it would run unmodified on a VM not aware of generics. This backward compatibility/migration compatibility reason is also why now the Collections API supports generics and stayed the same and there isn't (as in C# when they introduced generics) a complete new set of a generic aware Collection API.
The compatibility was done using ersure (generic type parameter info removed at compile time) which is also the reason you get so many unchecked cast warnings in java.
You could still add reified generics but it's not that easy. Just adding the type info add runtime instead of removing it won't work as it breaks source & binary compatibility (you can't continue to use raw types and you can't call existing compiled code because they don't have the corresponding methods).
The other approach is the one C# chose: see above
And automated autoboxing/unboxing wasn't supported for this use case because autoboxing costs too much.
Java theory and practice: Generics gotchas
Every non-array non-string object stored on the heap contains an 8- or 16-byte header (sizes for 32/64-bit systems), followed by the contents of that object's public and private fields. Arrays and strings have the above header, plus some more bytes defining the length of the array and size of each element (and possibly the number of dimensions, length of each extra dimension, etc.), followed by all of the fields of the first element, then all the fields of the second, etc. Given an reference to an object, the system can easily examine the header and determine what type it is.
Reference-type storage locations hold a four- or eight-byte value which uniquely identifies an object stored on the heap. In present implementations, that value is a pointer, but it's easier (and semantically equivalent) to think of it as an "object ID".
Value-type storage locations hold the contents of the value type's fields, but do not have any associated header. If code declares a variable of type Int32, there's no need to need to store information with that Int32 saying what it is. The fact that that location holds an Int32 is effectively stored as part of the program, and so it doesn't have to be stored in the location itself. This an represent a big savings if, e.g., one has a million objects each of which have a field of type Int32. Each of the objects holding the Int32 has a header which identifies the class that can operate it. Since one copy of that class code can operate on any of the million instances, having the fact that the field is an Int32 be part of the code is much more efficient than having the storage for every one of those fields include information about what it is.
Boxing is necessary when a request is made to pass the contents of a value-type storage location to code which doesn't know to expect that particular value type. Code which expects objects of unknown type can accept a reference to an object stored on the heap. Since every object stored on the heap has a header identifying what type of object it is, code can use that header whenever it's necessary to use an object in a way which would require knowing its type.
Note that in .net, it is possible to declare what are called generic classes and methods. Each such declaration automatically generates a family of classes or methods which are identical except fort he type of object upon which they expect to act. If one passes an Int32 to a routine DoSomething<T>(T param), that will automatically generate a version of the routine in which every instance of type T is effectively replaced with Int32. That version of the routine will know that every storage location declared as type T holds an Int32, so just as in the case where a routine was hard-coded to use an Int32 storage location, it will not be necessary to store type information with those locations themselves.
In Java and C# (unlike C++) everything extends Object, so collection classes like ArrayList can hold Object or any of its descendants (basically anything).
For performance reasons, however, primitives in java, or value types in C#, were given a special status. They are not object. You cannot do something like (in Java):
7.toString()
Even though toString is a method on Object. In order to bridge this nod to performance, equivalent objects were created. AutoBoxing removes the boilerplate code of having to put a primitive in its wrapper class and take it out again, making the code more readable.
The difference between value types and objects in C# is more grey. See here about how they are different.