基本數據類型vs對象類型
當你閱讀這篇文章的時候,可能已經知道了Java是雙類型的系統,也就是基本數據類型和對象類型,簡稱基本類型和對象。Java中有8個預定義的基本類型,它們的名字都是保留的關鍵字。常見的基本類型有int、double和boolean。Java中所有其他的類型包括用戶自定義的類型,它們必然也是對象類型(我說”必然”是因為數組類型有點例外,與基本類型比數組更像是對象類型)。每一個基本類型都有一個對應的對象包裝類,比如int的包裝類是Integer,double的包裝類是Double,boolean的包裝類是Boolean。
基本類型基於值,而對象類型則基於引用。與基本類型相關的爭議都源於此。為了說明它們的不同,先來看一下兩個聲明語句。第一個語句使用的是基本類型,第二個使用的是包裝類。
int n1 = 100;
Integer n2 = new Integer(100);
使用新添加到JDK5的特性自動裝箱以后,第二個聲明可以簡化成:
Integer n2 = 100;
但是,底層的語義並沒有發生改變。自動裝箱簡化了包裝類的使用,減少了程序員的編碼量,但是對運行時並沒有任何的改變。
圖1展示了基本類型n1和包裝對象類型n2的區別。

n1持有一個整數的值,但是n2持有的是對一個對象的引用,即那個對象持有整數的值。除此之外,n2引用的對象也包含了一個對Double對象的引用。
內存的使用
Java中的double總是占據內存的64個比特,但是引用類型的字節數取決於JVM。我的電腦運行64位Win7和64位JVM,因此在我的電腦上一個引用占用64個比特。根據圖1,一個double比如n1要占用8個字節(64比特),一個Double比如n2要占用24個字節——對象的引用占8個字節,對象中的double的值占8個字節,對象中對Double對象的引用占8個字節。此外,Java需要使用額外的內存來支持對象的垃圾回收,但是基本類型不需要。
package mytest;
import java.util.Date;
public class Test {
/**
* @param n 矩陣n*n
* @param type 類型 1:double 2:Double
* @return 獲得存儲所使用的字節數
*/
public static long getBytesUsingPrimitives(int n,int type){
System.gc();// force garbage collection
long memStart = Runtime.getRuntime().freeMemory();
// put some random values in the matrix
switch(type){
case 1:
double[][] a = new double[n][n];
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j)
a[i][j] = Math.random();
}
break;
case 2:
Double[][] ax=new Double[n][n];
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j)
ax[i][j] = Math.random();
}
break;
default:
break;
}
long memEnd = Runtime.getRuntime().freeMemory();
return memStart - memEnd;
}
//創建double類型矩陣n*m
public static double[][] create(int n,int m){
double[][] a = new double[n][m];
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j)
a[i][j] = Math.random();
}
return a;
}
//創建Double類型矩陣n*m
public static Double[][] createD(int n,int m){
Double[][] a=new Double[n][n];
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; ++j)
a[i][j] = Math.random();
}
return a;
}
/**
* 創建矩陣,並使兩個矩陣相乘
* 返回 運行時長
*/
public static long multiply(int x1,int y1,int x2,int y2,int type){
Date d1=null;
switch(type){
case 1:
double[][] a=create(x1,y1);
double[][] b=create(x2,y2);
d1=new Date();
if (!checkArgs(y1, x2))
throw new IllegalArgumentException("Matrices not compatible for multiplication");
int nRows = a.length;
int nCols = b[0].length;
double[][] result = new double[nRows][nCols];
for (int rowNum = 0; rowNum < nRows; ++rowNum){
for (int colNum = 0; colNum < nCols; ++colNum){
double sum = 0.0;
for (int i = 0; i < a[0].length; ++i)
sum += a[rowNum][i]*b[i][colNum];
result[rowNum][colNum] = sum;
}
}
break;
case 2:
Double[][] ax=createD(x1,y1);
Double[][] bx=createD(x2,y2);
d1=new Date();
if (!checkArgs(y1, x2))
throw new IllegalArgumentException("Matrices not compatible for multiplication");
int nRowsx = ax.length;
int nColsx = bx[0].length;
Double[][] resultx = new Double[nRowsx][nColsx];
for (int rowNum = 0; rowNum < nRowsx; ++rowNum){
for (int colNum = 0; colNum < nColsx; ++colNum){
Double sum = 0.0;
for (int i = 0; i < ax[0].length; ++i)
sum += ax[rowNum][i]*bx[i][colNum];
resultx[rowNum][colNum] = sum;
}
}
break;
default:
break;
}
Date d2=new Date();
return d2.getTime()-d1.getTime();
}
private static boolean checkArgs(int y1, int x2) {
if(y1!=x2)
return false;
return true;
}
public static void main(String[] args){
//運行結果,並不是保持不變,這里是平均值
System.out.println(getBytesUsingPrimitives(1000, 1));//字節數統計 7585424
System.out.println(getBytesUsingPrimitives(1000, 2));// 28646800
System.out.println(multiply(1000,1000,1000,1000,1));//所用時間 12773
System.out.println(multiply(1000,1000,1000,1000,2));// 39017
}
}
