增强包装类
为了解决8种基本数据类型的变量不能当成Object类型变量使用的问题,Java提供了包装类(Wrapper Class)的概念,为8种基本数据类型分别定义了相应的引用类型,并称之为基本数据类型的包装类。
除了int和char有点例外之外,其他的基本数据类型对应的包装类都是将其首字母大写即可。
把基本数据类型变量包装成包装类实例是通过对应包装类的构造器来实现的,不仅如此,8个包装类中除了Character之外,还可以通过传入一个字符串参数来构建包装类对象,下面是个例子:
public class Primitive2Wrapper
{
public static void main(String[] args)
{
boolean bl=true;
//通过构造器把b1基本类型变量包装成包装类对象
Boolean blObj=new Boolean(bl);
int it=5;
//通过构造器把it基本类型变量包装成包装类对象
Integer itObj=new Integer(it);
// 把一个字符串转换成Float对象
Float fl=new Float("4.56");
// 把一个字符串转换成Boolean对象
Boolean bObj=new Boolean("false");
//下面程序运行时将出现java.lang.NumberFormatException异常
// Long lObj=new Long("ddd");
System.out.println(fl);
System.out.println(bObj);
}
}
上面程序分别把true、5等基本类型变量包装成包装类对象。除此之外,上面程序还通过向包装类构造器里传入一个字符串参数,分别利用"4.56"、"false"等字符串来创建包装类对象。在上面程序的最后一行:Long lObj=new Long(“ddd”);,这行代码试图把"ddd"字符串转换成Long类型变量,这行代码编译时没有问题,但运行时会引发java.lang.NumberFormatException异常。
当试图使用一个字符串来创建Byte、Short、Integer、Long、Float和Double等包装类对象时,如果传入的字符串不能成功转换成对应的基本类型变量,则会引发java.lang.NumberFormatException异常。
如果希望获得包装类对象中包装的基本类型变量,则可以使用包装类提供的xxxValue()实例方法。例如,下面代码可以拆出前面创建的包装类对象里的基本类型变量:
//取出Boolean对象里的boolean变量
boolean bb=bObj.booleanValue();
//取出Integer对象里的int变量
int i=itObj.intValue();
//取出Float对象里的float变量
float f=fl.floatValue();
JDK 1.5提供了自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)功能。所谓自动装箱,就是可以把一个基本类型变量直接赋给对应的包装类变量,或者赋给Object变量(Object是所有类的父类,子类对象可以直接赋给父类变量);自动拆箱则与之相反,允许直接把包装类对象直接赋给一个对应的基本类型变量:
public class AutoBoxingUnboxing
{
public static void main(String[] args)
{
//直接把一个基本类型变量赋给Integer对象
Integer inObj=5;
// 直接把一个boolean类型变量赋给一个Object类型变量
Object boolObj=true;
// /直接把一个Integer对象赋给int类型变量
int it=inObj;
System.out.println(inObj.intValue());
if (boolObj instanceof Boolean)
{
//先把Object对象强制类型转换为Boolean类型,再赋给boolean变量
boolean b=(Boolean)boolObj;
System.out.println(b);
}
}
}
除此之外,包装类还可实现基本类型变量和字符串之间的转换。把字符串类型的值转换为基本类型的值有两种方式:
- 利用包装类提供的parseXxx(String s)静态方法(除了Character之外的所有包装类都提供了该方法。
- 利用包装类提供的Xxx(String s)构造器。
String类提供了多个重载valueOf()方法,用于将基本类型变量转换成字符串,下面程序示范了这种转换关系:
public class Primitive2String
{
public static void main(String[] args)
{
String intStr="123";
//把一个特定字符串转换成int变量
int it1=Integer.parseInt(intStr);
int it2=new Integer(intStr);
System.out.println(it2);
String floatStr="4.56";
//把一个特定字符串转换成float变量
float ft1=Float.parseFloat(floatStr);
float ft2=new Float(floatStr);
System.out.println(ft2);
//把一个float变量转换成String变量
String ftStr=String.valueOf(2.345f);
System.out.println(ftStr);
//把一个double变量转换成String变量
String dbStr=String.valueOf(3.344);
System.out.println(dbStr);
//把一个boolean变量转换成String变量
String boolStr=String.valueOf(true);
if (boolStr instanceof String)
{System.out.println(boolStr.toUpperCase());}
}
}
如果希望把基本类型变量转换成字符串,还有一种更简单的方法:将基本类型变量和""进行连接运算,系统会自动把基本类型变量转换成字符串:
//intStr的值为"5"
String intStr=5 + "";
包装类型的变量是引用数据类型,但包装类的实例可以与数值类型的值进行比较,这种比较是直接取出包装类实例所包装的数值来进行比较的:
public class WrapperClassCompare {
public static void main(String[] args){
Integer a=new Integer(6);
//输出true
System.out.println("6的包装类实例是否大于5.0" + (a > 5.0));
//输出false
System.out.println("比较2个包装类的实例是否相等:"
+ (new Integer(2)==new Integer(2)));
//通过自动装箱,允许把基本类型值赋值给包装类实例
Integer ina=2;
Integer inb=2;
//输出true
System.out.println("两个2自动装箱后是否相等:" + (ina==inb));
Integer biga=128;
Integer bigb=128;
//输出false
System.out.println("两个128自动装箱后是否相等:" + (biga==bigb));
}
}
上面程序让人比较费解:同样是两个int类型的数值自动装箱成Integer实例后,如果是两个2自动装箱后就相等;但如果是两个128自动装箱后就不相等,这是为什么呢?这与Java的Integer类的设计有关,查看Java系统中java.lang.Integer类的源代码,如下所示:
//定义一个长度为256的Integer数组
static final Integer[] cache=new Integer[-(-128) + 127 + 1];
static {
//执行初始化,创建-128到127的Integer实例,并放入cache数组中
for(int i=0; i < cache.length; i++)cache[i]=new Integer(i - 128);
}
从上面代码可以看出,系统把一个-128~127之间的整数自动装箱成Integer实例,并放入了一个名为cache的数组中缓存起来。如果以后把一个-128~127之间的整数自动装箱成一个Integer实例时,实际上是直接指向对应的数组元素,因此-128~127之间的同一个整数自动装箱成Integer实例时,永远都是引用cache数组的同一个数组元素,所以它们全部相等;但每次把一个不在-128~127范围内的整数自动装箱成Integer实例时,系统总是重新创建一个Integer实例,所以出现程序中的运行结果。
开发者就可以通过包装类提供的compare(xxx val1, xxx val2)方法来比较两个基本类型值的大小,包括比较两个boolean类型值,两个boolean类型值进行比较时,true > false。例如如下代码:
System.out.println(Boolean.compare(true , false)); //输出1
System.out.println(Boolean.compare(true , true)); //输出0
System.out.println(Boolean.compare(false , true)); //输出-1
Java实例联系
矩阵的转置
在数组的程序开发中,二维数组使用的最为频繁,它可以存储表格数据,还可以根据数组下标索引加入各种运算。作为对数组知识的巩固,本实例实现数组在矩阵运算中的转置运算,即实现一个二维数组的行列互换
1.
新建项目MatrixTranspose,并在其中创建一个MatrixTranspose.java文件。在该类的主方法中定义一个二维数组,输出该数组的内容,然后创建一个同样大小的二维数组,并利用双层for循环遍历数组。在循环中将新数组与原数组的行列索引进行交换,然后再输出新数组内容:
public class MatrixTranspose {
public static void main(String[] args){
//创建二维数组
int arr[][] = new int[][]{{1,2,3},{4,5,6},{7,8,9}};
System.out.println("转置前矩阵:");
printArray(arr);
int arr2[][] = new int[arr.length][arr[0].length];
for (int i =0; i< arr.length; i++){
for (int j=0; j<arr[i].length; j++){
arr2[i][j] =arr[j][i];
}
}
System.out.println("转置后的矩阵:");
printArray(arr2);
}
private static void printArray(int[][] arr){
for (int i=0; i < arr.length; i++){
//遍历数组
for (int j=0; j < arr[i].length; j++) {
System.out.print(arr[i][j]); //不换行输出数组元素
}
System.out.println(); //换行
}
}
}
本实例应用的主要技术是创建两个相同大小的二维数组,并使用双层的for循环遍历这两个二维数组。同时把新数组和原数组的行列索引交换进行元素赋值,从而实现将二维数组中的行列进行交换,实现矩阵的转置。
求矩阵的际(主对角线之和)
求矩阵的迹,也就是矩阵的主对角线之和:
1.
新建项目MatrixTrace,并在其中创建一个MatrixTrace.java文件。在该文件的主方法中定义一个数组内容接收器,然后使用for循环获得该矩阵的对角线元素,最后输出该矩阵的对角线元素之和,即该矩阵的迹:
package MatrixTrace;
import java.io.*;
import java.util.*;
public class MatrixTrace {
public static void main(String args[]) throws IOException{
int n = 0;
System.out.print("请输入矩阵的维数及数组的内容:"); // 获取矩阵的维数信息
Scanner reader = new Scanner(System.in);
n=reader.nextInt();
String[] s=new String[n];
Scanner[] scan=new Scanner[n];
long[][] a=new long[n][n];
long sum=0;
BufferedReader stdin=new BufferedReader(new InputStreamReader(System.in));
for (int i=0;i<n;i++){
s[i]=stdin.readLine(); //连续输入多行
}
System.out.println("您输入的矩阵为:"); //显示输入矩阵
for (int i=0;i<n;i++){
//for 循环遍历数组
scan[i]=new Scanner(s[i]);
}
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
a[i][j]=scan[i].nextLong();
}
}
for (int i=0;i<n;i++){ //获取矩阵对角线上的元素值
for (int j=0;j<n;j++){
System.out.print(a[i][j]+"");
if(i==j){
sum=sum+a[i][j];
}
}
System.out.println("");
}
System.out.println("矩阵的迹为:"+sum); //输出矩阵的迹
}
}
本实例的难点在于求矩阵的对角线元素。由于矩阵的对角线上的元素下一行总比上一行在行数和列数上都多1,而第一个元素肯定也在对角线上,而且矩阵的维数又一定,所以我们仍然可以使用for循环获得该矩阵所有的对角线值。