BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

On Java - Autoboxing

Duke 512




Bookmark and Share





bogotobogo.com site search:






bogotobogo.com site search:
Autoboxing

Starting from Java 5, we have a new feature called Autoboxing. It is known as several names: auto-boxing, boxing, and unboxing. Boxing and unboxing make wrapper classes more convenient.

Before Java 5, if we want to make a wrapper, unwrap it, use it, and then rewrap it, we might do something like this:

Integer iwrap = new Integer(345);  		// make it
int junwrap = iwrap.intValue();			// unwrap it
junwrap++;					// use it
iwrap = new Integer(junwrap);			// rewrap it
System.out.println("iwrap = " + iwrap);		// print it

But in Java 5, we write the code:

Integer iwrap2 = new Integer(345);		// make it
iwrap2++;					// unwrap it, increment it, and rewrap it
System.out.println("iwrap2 = " + iwrap2);	// print it

The output produced from the two versions is same:

iwrap = 346
iwrap2 = 346

The line of code:

Integer iwrap2 = new Integer(345);
iwrap2++;

appears to be using post-increment operator on an object reference variable, iwrap2. However, the compiler does the unboxing and reassignment for us behind the scene. Though it also looks contradictory to the rule that wrapper objects are mutable because iwrap2's value changed from 345 to 346. What actually happened was that the second wrapper object was created and its value was set to 346.

Let's check it with the following example.

Integer iwrap3 = 345;
Integer iwrap4 = iwrap3;
System.out.println(iwrap3 == iwrap4);
iwrap3++;
System.out.println(iwrap3 + " " + iwrap4);
System.out.println(iwrap3 == iwrap4);

Its output should look like this:

true
346 345
false

So, behind the scene, when the compiler got to the line

iwrap3++;

it had to substitute some like this:

int temp = iwrap3.intValue();
temp++;
iwrap3 = new Integer(temp);

As we expected, there was a call to new.




equals() and ==

We're going to look at how wrappers work with ==, !=, and equals() more thoroughly.

What would be the intention of using equals() method? Its main intention is to determine whether two instances of a given class are meaningfully equivalent. It's up to the designer of the class to decide what equivalent means for objects of the class in question. The API developers decided that for all the wrapper classes, tow objects are equal if they are of the same type and have the same value.
So, it shouldn't be surprising that
Integer ia = 2010;
Integer ib = 2010;
if(ia != ib) System.out.println("They are not the same objects.");
if(ia.equals(ib)) System.out.println("They are meaningfully equal.");
produces the output like this:
They are not the same objects.
They are meaningfully equal.

It's just two wrapper objects that happen to have the same value. Because they have the same int value, the equals() method think them to be meaningfully equivalent, and returns true.

How about this example:

Integer ic = 20;
Integer id = 20;
if(ic == id) System.out.println("They are the same objects.");
if(ic.equals(id)) System.out.println("They are meaningfully equal.");

We'll have the following output from the run:

They are the same objects.
They are meaningfully equal.

Surprisingly, something happened to the == while the equals() method seems to be working as we expected. Why is != telling us that ia and ib are different objects, when == is telling that ic and id are the same object?
What happened? It's all about saving memory!

In order to save memory, two instances of the following wrapper object created through boxing, will always be == when their primitive values are the same:

  1. Boolean
  2. Byte
  3. Character from \u0000 to \u007f (127 in decimal)
  4. Short and Integer from -128 to 127

Note that when we use == to compare a primitive to a wrapper, the wrapper will be unwrappered and the comparison will be primitive to primitive.



Overloading with Widening

We'll look at three factors that can make overloading tricky:

  1. Widening
  2. Autoboxing
  3. Var-args

When a class has overloaded methods, one of the compiler's job is to decide which method to use when there is an invocation for the overloaded method. Let's look at the following example.

public class Overloaded {
	public static void main(String[] args) {	
		byte b =2;
		short s = 2;
		long l = 2;
		float d = 2.0f;
		
		Overloaded o = new Overloaded();
		o.go(b);
		o.go(s);
		o.go(l);
		o.go(d);
	}
	
	void go(int i) {			
		System.out.println("int ");
	}
	
	void go(long l) {			
		System.out.println("long ");
	}
	
	void go(double d) {			
		System.out.println("double ");
	}
}

The output from the run:

int 
int 
long 
double 

The calls that use byte and short arguments are implicitly widened to match the version of the go() method that takes an int. The call with the long uses the long version of go() method and the call that uses a float is matched to the method that takes a double.

In all of the cases, when an exact match isn't found, the JVM uses the method with the smallest argument that is <wider than the parameter.

If we have only double version of go(), it will be used to match all four invocations of go().

public class Overloaded {
	public static void main(String[] args) {	
		byte b =2;
		short s = 2;
		long l = 2;
		float d = 2.0f;
		
		Overloaded o = new Overloaded();
		o.go(b);
		o.go(s);
		o.go(l);
		o.go(d);
	}
	
	/*
	void go(int i) {			
		System.out.println("int ");
	}
	
	void go(long l) {			
		System.out.println("long ");
	}
	*/
	
	void go(double d) {			
		System.out.println("double ");
	}
}

All of the calls uses go() which takes a double as we expected.

double 
double 
double 
double 


Overloading with Boxing

Let's modify the code by adding boxing.

public class OverloadedWithBoxing {
	public static void main(String[] args) {	
		int i = 2010;	
		OverloadedWithBoxing o = new OverloadedWithBoxing();
		o.go(i);
	}
	
	void go(Integer i) {			
		System.out.println("Integer ");
	}
	
	void go(long l) {			
		System.out.println("long ");
	}
}

Which go() will be invoked?
If the only version of the go() method is the one that takes an Integer, then Java 5's boxing capability would allow the invocation of go() to succeed. Similarly, if only the long version existed, the compiler would use it for the invocation of the go().

The question is, given that both methods exist, which one will be used? In other words, does the compiler think that widening a primitive parameter is more desirable that performing an autoboxing operation? The answer is that the compiler will choose widening over boxing. So, the output is:

long

Widening beats boxing








Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Java Tutorials



Java Tutorial Home

Basics - Compiling and Launching

Inner Classes

Constructor

Enums

Static & Finally

Default and Protected

Polymorphism

Exception Handling

Exception Handling II

String Class

Threads

Threads II - State Transition

Threads III - Synchronization

Object Class

File I/O

Serialization

ArrayList

Autoboxing

Java Graphics Interface I - Basics

Java Graphics Interface II - Labels, Text Fields, Layouts

Java Graphics Interface III - paintComponent

TCP Sockets Server/Client

Scala - Functional Java Programming

Apache CXF install

Tomcat 7 Ubuntu 14 Install on Amazon EC2 instance

What is Apache Maven?

Maven life cycle

Eclipse Maven 3 plugin on Ubuntu 14.04

Apache Maven 3 - Setting up and creating a project

Apache Maven 3 - Compile, build, and install a Maven project

Apache Maven 3 - Dependencies

Apache Maven 3 - Web Application

Apache Maven 3 - Plugins (compiler)

Apache Maven 3 - Plugins (Jetty)

Eclipse CDT / JNI (Java Native Interface) / MinGW



Spring Framework

Hello World App with Spring 4 & Maven 3 - Part I




Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Spring Boot



Spring Boot : Hello world with Mavan 3

Spring Boot : Hello world with Gradle 2

Spring Boot (Gradle 2) : Hello world with Authentication

Spring Boot : Deploying War file to Tomcat 8's webapps

How to Setup Apache as Reverse Proxy for Tomcat Server using mod proxy

Maven : mvn command cheat sheet

Spring-Boot REST API with CORS App Maven war file deploy to Tomcat

Spring-Boot / Spring Security with AngularJS - Part I (Introduction)

Spring-Boot / Spring Security with AngularJS - Part II (Dynamic resource load from Angular)

Spring-Boot / Spring Security with AngularJS : Part III (Form-based Authentication)





JUnit & Maven Tutorial



JUnit 4 Introduction (Hello World)

JUnit 4 Test with Eclipse Luna (Hello World)

JUnit 4 Test with Maven (Hello World)











Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master