概述(NullPointException)
的一些问题或者说是错误。好,首先我们去看一看到底什么是空指针,如何从根源避免控制人?不仅仅是Java语言控制人问题,是任何一个出入编程的同学他们遇到的问题,我们通常也把它叫做npe问题。其实 npe就是now point exception首字母的一个简称,我这里控制人异常分为了三段,也就是代表着三个概念,分别是空,指针以及异常。
内存地址为空
首先空它指的内存地址为空,也就是now我们知道数据结构和数据都是保存在内存中的,那么内存就一定会是那么如果地址为空,则意味着这是一个无效的地址。可以看到我下面这张图,有两个指针,指针a和指针B跟a指向的是一个实际的内存地址,00020002又指向到内存中的一个数据结构,或者说对象,那么指针a是有效的,对于指针B可以看到它指向的是now,也就是内存地址为0,这就是一个无效的地址,也就是说指针B的一个无效的指针。
指针/引用
好,第二个指针,那么指针它是C和C++中的概念,它是一个变量,用来保存内存池的变量,而在Java中实际上是没有指针的概念的,与指针相对应的概念叫做引用,它指向一个实例对象,
异常
最后是异常。那么从Java类结构图去看,空指针它属于运行时异常的一个子类,它不是throw的,也就是说我们不需要去主动的try catch,在程序运行的过程中才可能会爆出来,
而且它会造成程序的一个中断。由此我们可以知道,当一个变量的值为null,那么在Java里面它就是表示一个不存在的空对象,他没有实际的内容,也没有给他内存,null,也是对象成员变量的一个默认值。所以一个对象如果没有进行初始化操作,这时候如果你调用对方法或者变量或者说直接去访问这个对象,就会出现空指针异常,这个也就是产生控制人异常的一个最根本原因,就是因为对象没有初始化,你就直接去使用它。
好,那么接下来为了更清晰的认识到空指针,我去做一些场景复现以及复现这些场景抛出控制帧之后,我们去对堆栈的一个阅读。好,我在课上去创建了一个Java工程,在idea中创建了一个Java工程,Java工程叫做Java escape,可以看到目前 Java工程是空的,只有一个碰点抢麦文件,我加工成的坐标是com点CN慕课,点Java点give,escape,名字叫做Java escape,版本可以是任意的。
大家在课下自己创建工程,这个工程将来也会去演示其他的Java相关的一些坑。
好,我们首先在 Java下面去创建一个包,这个项目的一个根的包。太理解,我们把它叫做come点iPhone,看不见M个点,Java点is gap,与我们公众号it是相对应的。好,我们把它关掉。好,接下来由于我们这节课想要理解什么是控制帧,所以我们就直接一点把这个场景复现的一个例子就叫做what is npe?
好,这样我们就创建出来了加法类,简单的写一故事,主要是类的一个作用。
理解。什么是空指针?好,我们首先去创建一个对象,因为我刚才讲过空指针产生的最根本原因就是没有初始化这个对象,你就直接使用它,我们在代码中去创建出来。Probably studying the class.用来掩饰控制人。这个对象有两个属性,以及两个方法,private。String .Name它是一个SQL类型,再接下来它也是一个实训类型,但是它是一个磁数据,
分别是name和CD。好,再接下来我们去创建两个方法,主任的方法,我们随便在这里面写上一些内容,打印反映一句话,最后最后一个方法叫做read book users对象去读书的一个方法。也去写一句话,那么user read I lookescape.最后我们去返回一个now。好,因为这是一个带有返回值的方法,所以说我们需要去返回一个now,好,此时我们已经把 Java类以及对象都建好了,接下来我们就去做场景复线,去演示一些可能产生控制人的场景,慢方法。
空指针产生情况
调用了对象的实例方法
第一种情况,一种产生空指针的情况,也就是调用了新对象的实例方法。比如说我们去定义了一个User的对象,我们去定义了一个User的对象,那么 User的对象它没有经过初始化,我们就直接去调动它,user点print Pro的方法是定义在 U的对象里面的,所以说我们可以直接去调用它。但是由于 U的对象没有经过初始化,所以说这样的调用就抛出空指针异常,好,我们去做演示给大家执行一下。
我们去run起来 what is npd的示范方法等程序的一个编译执行。可以看到此时程序已经抛出了空指针异常,其实就是空指针的一个堆栈信息,去阅读一下堆栈,可以看到堆栈信息,他其实会告诉你很多事情,他告诉你在其中引发异常的一个Java类的名,那么对于一个简单的程序或者一个线程来说,就像是这样,可以看到它会报的是the exception in thread men,也就是我们的主线程抛出了控制人异常。
首先是告诉你哪个线程抛出了控制人异常,然后他告诉你引发异常的一个群,这里就是Java点language点点,no point exception。如果异常具有关联的错误消息,也就是这个错误消息在异常的名称之后输出控制人一场在这个方面比较特殊,因为他很少有其他的错误消息,只是告诉你说你的某一个对象是那么再接下来我们就根据异常战排查是哪一行的代码抛出了控制帧,那么在逐步的对代码进行中,从而去解决问题,可以看到这里告诉你是27行,我们点过去,就是这里从这里抛出了空中的异常,U的对象为空,我们去调用了它的方法。
好,这样的话我们就把控制人异常的第一个场景以及阅读对战的过程给大家去讲解了。
接下来我们在其他的一些场景,这就是对象去调用一个方法是一个空对象。
访问空对象的属性
第二种情况,访问了空对象的few或者说房子空对上的一些属性,我们仍然去第一个空的学校的对象。然后我们去直接输出它的内部属性,讲内容属性,由于U的对象它是没有经过处的,也就是它的内存地址是0,我们直接去访问他的内部属性,实际上也会抛出控制争议场,我这里就不再去执行演示以及这段了,应该跟刚才的情况是类似的,大家在课下可以自己去尝试一下,好,这是第二种情况。
数组未实例化
第三种情况,当数组是一个空对象的时候,那么取它的长度会抛出控制人异常,user.好,我们此时已经把 U的对象给它扭出来了, U的对象与刚才的两种机制不一样的,因为它是一个实际的对象,他在内存中是有值的,所以说我们通过使用 U的去访问Turing的方法,以及去访问内部属性都是可行的。
但是我们的 user类定义了一个string数组address,它是没有经过初始化的,它是没有基础化的,所以说你直接去访问这个数组对象,取它的长度也会抛出异常,控制这异常user。
第二dress叫lens。虽然U的对象经过了初始化,但是address是没有初始化的,所以说address的地址仍是now他去访问一个less属性的,会类似于前两种情况,跑出控制人一场,我这里也不去再做演示,好,这是三种情况。接下来第4种情况,我们不用 U的去演示,我们去写一个异常类,自定义一个异常类,比如public,虽然一个classcustomerexception去继承的 run time一场,我们去自定义一个运行时异常,自定义一个运行时异常,那么对于异常,如果你没有经过初始化去直接去抛出异常,他也是会报以控制人一场,这个比较特殊,customer exception,我们去定义一个custom exception,那么对于一些情况,我们需要在这个代码中主动的去抛出些异常,但是你抛出异常的时候,同样需要对异常进行初始化,是你不能抛出一个内存地址为空的异常,对于我们的定义了customer exception这个exception它是一个now,如果你直接去在0exception,对于这种情况他也会抛出一个控制人一场。
对于李涛的议程实际上是一个错误性,你不能抛一个空对象出来。这个就是第4种情况。或者说第4种控制人的一个常见场景,no,当做不值。这是第4种情况。
方法返回值
好,再接下来我们去写最后一种情况,就是第5种情况。第5种情况也是大家常犯的一个错误,就是方法的返回值。No.那么调用方直接去使用。好,我们网上回头去看一看6的对象,deu的对象定义了一个read book这个方法,这个方法它的范围值是一个string类型,此时我们并不能直接为它返回的,真正的是一个CD项,因为它实际上返回了一个no,这是有可能的,因为now可以对应到所有的对象对象类型,我讲一下第5种情况是怎么样发生的。
我们初始化一个U的对象,初始V的对象,然后直接去输出,通过user去调用read book,很显然是不会抛出控制值异常,因为U的对象它是有内存地址的,它是真实存在的一个对象,所以说他可以去调用user的 read book方法,但是它调用方法之后返回的不是词类型,而是一个now。
那么如果此时他再去做一些相关的操作返回值,做一些相关的操作,比如说他去比较一下返回值是否是马SOHO,此时就会抛出控制人异常了,因为这一段 user rate不可能,它的返回值是一个now,这就是控制人一场最常见的活动场景,大家在课下自行去练习它,然后掌握一下,去理解一下为什么会产生控制帧,它的根本原因是什么?好,接下来我们针对于控制人的常见场景,这里有哪些方式可以避免问题?
预防空指针
使用之前一定初始化
第一个使用之前一定要初始化,或者说检查一下是否说实话90%的控制人问题它的来源都是没有初始化,这个问题基本上都是疏忽造成的,比如直接使用了方法返回的对象,而忘记了校验因使用第一的对象而忘记了数字化等等。
我们看两个例子,我们的疏忽造成的估值跟错误,那么第一个例子可以看到,那么request中就用了它的 get Perry的方法,然后去获取这样一个参数对象,那么由于我们没有直接去判断一下,而直接的时候这里的打印可能是一个空的结果,也就是一个no,我们应该将它修改为去通过if判断它是否为not或者是 or not,就去抛出控制人,否则我们就不一样了,可以打印结果,
这是一种第一种方式造成的。那么第二种就是我们天道虽然说是拥有了一个对象,但是接下来我们又通过其他的对象给我们的原先new的对象又重新复职,那么先复制之后再去使用这样一个对象,那么可以知道虽然我们用的时候这里一定不会出现控制人,但是我们代理对象重新副职可能会有控制人的问题,因为你的兔子点盖的柚子这样一个反馈对象可能是闹的,所以说我们可以做出一个修改,首先去判断一下兔子点get you的是否为not。
如果没闹我们去给他重新,你有一个user给他重新分了一个队,否则就是可以用这样一个返回的对象重新复制,然后再去使用这样一个对象,那么这就是我们经常会出现的数造成的控制人问题。
好的,我们再回到之前的PPT里面,所以如果你不确定在业务逻辑中是否已经做得出什么,那么检查一下是否初始化过。
避免函数中返回null
第二尽量避免在函数中返回null,或者就是你给出详细的一个注释。我们不论是我们的函数声明返回的是什么类型,我们都可以直接去返回到,而不会有语法错误的出现。但是这往往也是引起控制人的陷阱,所以我们应该尽量避免在函数中直接去反为闹,即使是没有办法必须要反问到我们,就在函数上面都要说明我们在方法上面做一个说明,如果你经常阅读开源代码,你会发现好的开源代码他都会这样做。
外部传值 一定判断
第三点,外部传值除非有明确的说明,否则一定要及时去判断,那么这种问题它其实与第二类错误是类似的,也就是说直接去使用其他的代码对应的传值,比如说数据库网络请求等等。对于这样的传值来说,我们已经没办法知道传过来的值是否是no,
所以说即使判断是最好的办法。当然除了我这里提到的避免控制人问题的方法之外,你还会有其他的方法,如果你在日常的工作学习中有更好的思路或者说办法,欢迎随时在问答区和我交流,那么最后留下客户讨论的问题。
你是如何认识控制人呢?令你印象最深刻的控制人一场是什么情形或者说是什么场?好,大家注意到我在课程的结束会留下客户讨论问题,当然也可能在课程中给大家留下一些任务或者作业,让大家自己去完成,谢谢。
其实不仅仅是这一节课,在以后的每一节课程中都会有类似的客户讨论以及任务,我建议大家一定要在问答区写下自己的想法,自己的见解,当然也可以是对课程知识点的扩展,我也建议大家去浏览其他同学问答区写下的想法和见解。久而久之你会发现我们的课程问答区不再是简单的问题与答复,而是我们自己的知识库,我们自己的学习笔记。