2013年第2周三Java的苦恼

今天遇到java基本类型Integer的比较,被findbugs报错才发现java的麻烦,java基本数据类型的封装类型真是麻烦,java中8种基本数据类型都会有默认值,但其它引用类型变量默认值为null,所有在用equals方法判断前一定要先确保对象不能为null,就是是Integer a在使用a.intValue前也要先判断a!=null,真麻烦。

Integer比较

例如:两个对象里面都有一个方法为getInteger()的方法,返回的类型也是Integer的,这时候想比较两个Integer是否相等不能用"=="号,要用equals方法.

原因很简单equals方法来自Object基类。在Object里,equals的实现是直接用 == 操作符比较两个对象的内存地址。

举两个例子:

代码1(equals方法)代码

public class MainClass {

public static void main(String[] args) {

Integer n1 = new Integer(47);

Integer n2 = new Integer(47);

System.out.println(n1.equals(n2));

}

}

public class MainClass {

public static void main(String[] args) {

Integer n1 = new Integer(47);

Integer n2 = new Integer(47);

System.out.println(n1.equals(n2));

}

}

输出结果为true,看来Integer中没有按照Object里的默认实现来比较内存地址。在Integer中,equals重载了Object的equals方法(重载指的是子类的方法覆盖掉父类的方法,而改为自己的实现),它比较的是Integer的实际值。

代码2(相等比较)代码

public class MainClass {

public static void main(String[] args) {

Integer n1 = new Integer(47);

Integer n2 = new Integer(47);

System.out.println(n1 == n2);

System.out.println(n1 != n2);

}

}

public class MainClass {

public static void main(String[] args) {

Integer n1 = new Integer(47);

Integer n2 = new Integer(47);

System.out.println(n1 == n2);

System.out.println(n1 != n2);

}

}

这里输出的第一个结果为false,第二个为true。结合上面的代码1可以看出,==和equals的区别。

Long的equals和相同数值的Integer比较为何为false

The java code:

代码后运行!">

普通浏览复制代码打印代码

Integer i = new Integer(42);

Long b = new Long(42);

System.out.println(b.equals(i));

Integer i = new Integer(42);

Long b = new Long(42);

System.out.println(b.equals(i));

运行结果为

false

我们查看一下Long.equals的源代码

public boolean equals(Object obj) {

if (obj instanceof Long) { // 这里是关键

return value == ((Long) obj).longValue();

}

return false;

}

public boolean equals(Object obj) {

if (obj instanceof Long) { // 这里是关键

return value == ((Long) obj).longValue();

}

return false;

}

如果传入的类型不是Long,那么全部返回false,这就是原因了

Java对象比较

一、简单类型比较

Java中,比较简单类型变量用"==",只要两个简单类型值相等即返回ture,否则返回false;

二、引用类型比较

引用类型比较比较变态,可以用"==",也可以用"equals()"来比较,equals()方法来自于Object类,每个自定义的类都可以重写这个方法。Object类中的equals()方法仅仅通过"=="来比较两个对象是否相等。

在用"=="比较引用类型时,仅当两个应用变量的对象指向同一个对象时,才返回ture。言外之意就是要求两个变量所指内存地址相等的时候,才能返回true,每个对象都有自己的一块内存,因此必须指向同一个对象才返回ture。

在用"equals()"比较引用类型时,情况就比较复杂,甚至有些变态,容易掉进陷阱。

在Java API中,有些类重写了equals()方法,它们的比较规则是:当且仅当该equals方法参数不是 null,两个变量的类型、内容都相同,则比较结果为true。这些类包括:String、Double、Float、Long、Integer、Short、Byte、、Boolean、BigDecimal、BigInteger等等,太多太多了,但是常见的就这些了,具体可以查看API中类的equals()方法,就知道了。

解析变态的Boolean类:在这些类中,最最变态的是要数Boolean类了,我感觉是开发Boolean类的人员头脑进水了。我也不想细说了,你有好四中方式来创建一个Boolean对象(两构造方法,两个静态方法valueOf(),推荐用静态方法)。

Boolean类的变态之处不在于其equals()方法。而是在于Boolean对象创建方法。其实Boolean类的对象最多有两个,其toString()值分别是true和false。当且仅当用true或者"true"创建的Boolean类为同一个对象且toString()值为true。其他的字符串或者false创建的Boolean对象的值一律相等且toString()值为false。

 

三、重写equals()方法

在定义一个类的时候,如果涉及到对象的比较,应该重写equals()方法。重写的一般规则是:

1、先用"=="判断是否相等。

 

2、判断equals()方法的参数是否为null,如果为null,则返回false;因为当前对象不可能为null,如果为null,则不能调用其equals()方法,否则抛java.lang.NullPointerException异常。

 

3、当参数不为null,则如果两个对象的运行时类(通过getClass()获取)不相等,返回false,否则继续判断。

 

4、判断类的成员是否对应相等。往下就随意发挥了。呵呵!

 

 

四、总结

"=="比较对象是否引用了同一个对象,或者比较简单类型变量值是否相等。

Object类的equals()方法用来比较是否一个对象(内存地址比较),可以重写。

JDK中有些类重写了equals()方法,只要类型、内容都相同,就认为相等。

很变态的Boolean类,仅存在两个实例。具体可查看API。

一般来说,一个类如果涉及到比较,应该重写equals()方法,因为内存地址比较没有意义。

深入Java关键字null

一、null是代表不确定的对象

Java中,null是一个关键字,用来标识一个不确定的对象。因此可以将null赋给引用类型变量,但不可以将null赋给基本类型变量。

比如:int a = null;是错误的。Ojbect o = null是正确的。

Java中,变量的适用都遵循一个原则,先定义,并且初始化后,才可以使用。我们不能int a后,不给a指定值,就去打印a的值。这条对对于引用类型变量也是适用的。

有时候,我们定义一个引用类型变量,在刚开始的时候,无法给出一个确定的值,但是不指定值,程序可能会在try语句块中初始化值。这时候,我们下面使用变量的时候就会报错。这时候,可以先给变量指定一个null值,问题就解决了。例如:

 

Connection conn = null;

try {

conn = DriverManager.getConnection("url", "user", "password");

} catch (SQLException e) {

e.printStackTrace();

}

 

String catalog = conn.getCatalog();

 

如果刚开始的时候不指定conn = null,则最后一句就会报错。

 

二、null本身不是对象,也不是Objcet的实例

null本身虽然能代表一个不确定的对象,但就null本身来说,它不是对象,也不知道什么类型,也不是java.lang.Object的实例。

可以做一个简单的例子:

 

//null是对象吗? 属于Object类型吗?

if (null instanceof java.lang.Object) {

System.out.println("null属于java.lang.Object类型");

} else {

System.out.println("null不属于java.lang.Object类型");

}

结果会输出:null不属于java.lang.Object类型

 

三、Java默认给变量赋值

在定义变量的时候,如果定义后没有给变量赋值,则Java在运行时会自动给变量赋值。赋值原则是整数类型int、byte、short、long的自动赋值为0,带小数点的float、double自动赋值为0.0,boolean的自动赋值为false,其他各供引用类型变量自动赋值为null。

这个具体可以通过调试来看。

 

四、容器类型与null

List:允许重复元素,可以加入任意多个null。

Set:不允许重复元素,最多可以加入一个null。

Map:Map的key最多可以加入一个null,value字段没有限制。

数组:基本类型数组,定义后,如果不给定初始值,则java运行时会自动给定值。引用类型数组,不给定初始值,则所有的元素值为null。

 

五、null的其他作用

1、判断一个引用类型数据是否null。 用==来判断。

2、释放内存,让一个非null的引用类型变量指向null。这样这个对象就不再被任何对象应用了。等待JVM垃圾回收机制去回收。

 

简单点说null表示还没new出对象,就是还没开辟空间 ""表示new除了对象,但是这个对象装的是空字符串。

比如声明一个 String str ;

如果说str是null,那么内存根本没创建字符串对像.

如果说str是空串,那么确实存在一个由str引用的字符串对像,只不过这个字符串的值是""

null用来表示一个引用没有实例存在,而""本身是一个实例,有自己的对象空间,和"zzyyxx"这样的String没什么区别。两个都是有值 !!!

String s1 = "";

String s2 = null;

调用s2.length() 抛出nullpointerexception.

调用s1.length() 返回0.

 

Java中Integer与int类型的装箱和拆箱 .

其实Integer与int类型的赋值与比较最关键的一点就是:这两个变量的类型不同。Integer是引用类型,int是原生数据类型。

我们分四种情况来讨论:

1) Integer与int类型的赋值

a.把Integer类型赋值给int类型。此时,int类型变量的值会自动装箱成Integer类型,然后赋给Integer类型的引用,这里底层就是通过调用valueOf()这个方法来实现所谓的装箱的。

b.把int类型赋值给Integer类型。此时,Integer类型变量的值会自动拆箱成int类型,然后赋给int类型的变量,这里底层则是通过调用intValue()方法来实现所谓的拆箱的。

2) Integer与int类型的比较

这里就无所谓是谁与谁比较了,Integer == int与int == Integer的效果是一样的,都会把Integer类型变量拆箱成int类型,然后进行比较,相等则返回true,否则返回false。同样,拆箱调用的还是intValue()方法。

3) Integer之间的比较

这个就相对简单了,直接把两个引用的值(即是存储目标数据的那个地址)进行比较就行了,不用再拆箱、装箱什么的。

4) int之间的比较

这个也一样,直接把两个变量的值进行比较。

值得注意的是:对Integer对象,JVM会自动缓存-128~127范围内的值,所以所有在这个范围内的值相等的Integer对象都会共用一块内存,而不会开辟多个;超出这个范围内的值对应的Integer对象有多少个就开辟多少个内存。

今天过来时间Tomcat总是无法启动项目(启动时间600多ms,很快),无法加载Spring框架,删除掉发布的工程再重新发布后就好了,或许跟我之前Myeclipse突然自动关闭后我强制把tomcat的javaw.exe进程强制结束掉有关。

你可能感兴趣的:(java)