基本数据类型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 } }