1)基础类型带来的便利与不便
java作为纯面向对象语言,编程思维宣称一切都是对象,java的所有对象都有一个共同的父类-Object,但事情总有例外,可能是为了延续编程语言基本操作连贯性,java还是保留了基础类型(主要包括int,char,short,boolean,long等),这些类型定义的变量不是Object,
一开始每次要人手工在封装类型和基础类型之间转化,这给写程序带来小小的麻烦
后来java加入了自动封装和解封装的特性,由此带来容易犯的另一个问题
经常会碰到由于封装类型转化导致的NullPointException异常,
比如如下这段代码
public class Foo {
Integer count;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public static void main(String[] args) {
Foo foo = new Foo();
int i;
i = foo.getCount();
}
}
如果你运行,会发生NPE异常。可能上面的代码还比较直观看出异常来,但在实际工程中,如果这些数据来自于数据库或外部参数设定,而我们又在潜意识中认为这些值不可能为空的情况,那很可能就在不知不觉中犯下这些小错误,测试时都一切正常,一旦上线,抛出NPE异常,故障随之而来。
2)java潜在已有的值对象
java为了性能考虑,会内置一些初始化的值。比如从-128到127的数字,26个字母等,程序员很少关心,实际上大多情况下也不需要关心,但有时候这会导致一些违背我们原本思维逻辑的情况,会费解。
public static void main(String[] args) {
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);
Integer c = 100;
Integer d = 100;
System.out.println(c == d);
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b);
Integer c = 100;
Integer d = 100;
System.out.println(c == d);
}
运行上段代码会返回false,true。因为100是内置已有的值对象,c和d指向的都是同一个内置值对象。
所以不是所有的对象都是重新生成的,我们不必害怕重复生成了很多常用值会导致内存浪费。
3)到底是传值还是传引用
按照c++参数传递给我们的基本印象,一开始会认为java的参数传递是传应用,我们在方法内部修改参数的值,运行完该方法后,参数对象的内容确实被改变了,这个和c++传引用得到的效果类似,因此我相信大多数人凭直觉会认为java也是传引用的。但是java确实是传值的,而我们根据概念知道传值的话,参数对象的内容就不应该会被改变,那么如何解释这个对象被修改了呢?
事实上java传过去的是参数地址的值,而不是参数本身的内容,这就是java所谓的传值,那么后续对这个参数地址值的修改离开方法后是无效的,但通过调用参数对象的方法修改参数的值,确实是生效的。
public class Foo {
Integer count;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public static void main(String[] args) {
Foo foo = new Foo();
foo.setCount(100);
Foo.checkreference(foo);
System.out.print("return parameter value:" + foo.getCount());
Foo.checkvalue(foo);
System.out.print("return parameter value:" + foo.getCount());
}
public static void checkreference(Foo foo){
foo.setCount(101);
}
public static void checkvalue(Foo foo){
Foo tmp = new Foo();
tmp.setCount(99);
foo = tmp;
}
Integer count;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public static void main(String[] args) {
Foo foo = new Foo();
foo.setCount(100);
Foo.checkreference(foo);
System.out.print("return parameter value:" + foo.getCount());
Foo.checkvalue(foo);
System.out.print("return parameter value:" + foo.getCount());
}
public static void checkreference(Foo foo){
foo.setCount(101);
}
public static void checkvalue(Foo foo){
Foo tmp = new Foo();
tmp.setCount(99);
foo = tmp;
}
}
运行上面这个程序,输出结果是101,101。你会发现,第一个是调用参数对象的方法改变了参数的内容(从100改到101),第二个试图直接改变参数对象的值(想改为99),结果没有改动(还是101)。
这里又有个例外,就是String类型的参数怎么就不能改值呢?因为String类型是immutable类型,即它的值对象不可变,每次在方法内修改String类型的参数内容其实是生成了一个新String对像,因此离开方法后,那个String类型的参数对象还是原来的值,并没改变。