回忆java来时路-第二章 对象之外

本文探讨了Java编程中的几个常见陷阱:基础类型与封装类型的转换引起的NullPointerException;内置值对象导致的逻辑困惑;以及Java参数传递机制的实际行为,帮助开发者避免潜在错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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);
}
运行上段代码会返回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;
    }
}
运行上面这个程序,输出结果是101,101。你会发现,第一个是调用参数对象的方法改变了参数的内容(从100改到101),第二个试图直接改变参数对象的值(想改为99),结果没有改动(还是101)。

这里又有个例外,就是String类型的参数怎么就不能改值呢?因为String类型是immutable类型,即它的值对象不可变,每次在方法内修改String类型的参数内容其实是生成了一个新String对像,因此离开方法后,那个String类型的参数对象还是原来的值,并没改变。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值