大家好,今天来为大家分享Java核心知识day09详解:内部类使用规则、静态内部类应用、匿名内部类技巧及异常处理基础的一些知识点,和的问题解析,大家要是都明白,那么可以忽略,如果不太清楚的话可以看看本篇文章,相信很大概率可以解决您的问题,接下来我们就一起来看看吧!
因此,当一个类定义在另一个类内部时,相对的类称为内部类(也称为内置类或嵌套类)。
例如:
访问特点:
内部类可以直接访问外部类的成员,包括私有成员。
要访问内部类的成员,外部类必须创建内部类的对象。
这就相当于孙悟空要想找到牛魔王的心脏,必须先找到牛魔王,然后才能找到它的心脏,这就是牛魔王.getHeart()方法。但如果孙悟空进入牛魔王的腹中,他就可以直接探访牛魔王的心脏。
我们可以直接访问内部类的成员吗?
但是如果还有一个类叫Outer2,还有一个内部类叫Inner,怎么区分是哪个内部类呢?
所以一定要指定Inner() 属于哪个类。
右侧的格式也需要更改。应该写成酱子:
但这很少使用,因为内部类可能是私有的,无法直接访问。这只是一种格式,只能在面试时使用。
班级可以是私人班级吗?
内部类可以设为私有。当一个类是另一个类的内部类时,可以将其设为私有。
但一般班级不得为私人班级。
为什么内部类可以直接访问外部类的内容?
一个例子。
如果你想打印x=6,那么:
如果你想打印x=4,那么:
如果你想打印x=3,那么:
当然,如果内部类中没有另外定义x=4和x=6,那么打印x时,会默认打印外部类的x=3。这时候x前面就隐含了一个Outer.this。
内部类之所以可以直接访问外部类的成员,是因为内部类以外部类名.this的格式保存了对外部类的引用。
02-面向对象(静态内部类)
访问格式:
1、当内部类被定义为外部类的成员且不是私有的时,可以在其他外部类中直接创建内部类对象。
格式:
外部类名.内部类名变量名=外部类对象.内部类对象;
即Outer.Inner in=new Outer().new Inner();
2.当内部类处于外部类的成员位置时,可以通过成员修饰符进行修饰。
例如private:将内部类封装在外部类中。
static:内部类具有静态的特性。当内部类被静态修改时,只能直接访问外部类。
静态成员有访问限制。
如何在其他外部类中直接访问静态内部类的非静态成员?
这有效:
如果function() 也是静态的怎么办?
这有效:
但使用频率很低。
注意:当内部类中定义了静态成员时,内部类必须是静态的。否则会报错。
这是正确的:
另一个例子:
把它改成紫色就可以了:
注意:当外部类中的静态方法访问内部类时,内部类也必须是静态的。
03-面向对象(内部类定义原理)
当描述一个东西的时候,这个东西的内部就有一些东西,而这个东西是通过一个内部类来描述的。
因为内在的东西是利用了外在的东西的内容。
如心脏之于人体。
我们的心不能被别人直接触及,所以必须是私密的。
当一个类需要直接访问另一个类的成员时,就将另一个类写入到这个类中。写完之后,尽量将这个类封装在一个外部类中,这样就不会暴露给外界,但是提供了外部访问的方法。
04-面向对象(匿名内部类)
我们发现刚才写的内部类是定义在外部类的成员位置上的。只有在成员位置定义的内部类才能被私有或静态修改。一般情况下,内部类不会被公开修改。是这样吗?有。还会出现更多特殊情况。我不会谈论这个。
内部类除了定义为外部类的成员之外,还可以写在其他位置,比如写在外部类的方法中:
这门课是本地的。但访问规则没有改变,仍然可以直接访问外部类中的成员。
还可以静态修改吗?不能。因为static 修饰符只修改成员,所以它现在是本地的,无法修改。它还可以定义静态成员吗?不能。因为如果内部类中有静态成员,那么内部类也必须是静态的,所以不能定义静态成员。
现在调用这个内部类中的函数,因为必须有这个内部类的对象才能使用它,所以需要这样写:
可以看到运行没有问题。
这是在本地位置定义的内部类的一个小功能。
为什么不先定义内部类对象呢?会报错:
因为如果放在前面,类定义在后面,那么内部类对象定义的时候,这个类的定义还没有被读取到。因此,内部类对象的定义应该放在内部类的定义之后。
那么内部类是否可以访问其所在方法中定义的变量y呢?会报错:
这是可以的:
当内部类在本地定义时:
1. 不能被成员修饰符修改。
2.可以直接访问外部类中的成员,因为外部类中的引用仍然保留着。
但不能访问其所在局部区域的变量,只能访问被final修饰的局部变量。
这个可以打印吗?
不。
为什么?
因为a是变量,需要经过final修饰后才能访问。
像姜子一样:
我此时心情郁闷。 a 不会变成常数吗?那么a就被赋值为7,这不是很矛盾吗?
这个其实没问题,把7赋值给a,然后a就会被锁住。看一下,运行没有任何问题:
尝试再次为其指定值8:
或者这种形式:
但是,对于赋值,两种方法没有区别。
因为a 不在对象中。它是一个标准的局部变量。如果给x 赋值,这两种方法就会有区别。
好吧,其实无论用哪种方法,都是可以编译通过的。为什么? a不是常数吗?
我们来做一下分析:当method()方法被调用时,它被压入栈内存中。堆栈上还有一个。如果将7赋值给a,则它被锁定,a将永远是7。直到执行out.method(7)这句话时,它才会从堆栈中弹出并释放。下一句,再次调用method(),再次入栈,就是新的a。此时8被赋值给a,a被锁定。所以这没关系。
那么什么是不可以的呢?
姜子还不够宽:
匿名内部类:
1、匿名内部类实际上是内部类的简称。
2、定义匿名内部类的前提条件:内部类必须继承一个类或者实现一个接口。
例如,每个人都有一颗心。如果你在外部定义了一个抽象的心,那么每个人内部的心类都会继承它以及里面的方法。
这是一个常规的内部类:
我们现在将其简化为匿名内部类。如何简化呢?
绿色部分其实就是我们需要简化的部分。
在简化之前,我们先来分析一下。内部类有什么作用?
1.它继承了一个类; 2.重写父类的方法; 3. 创建一个对象; 4. 通话。
这个内部类原来的名字是Inner,现在已经没有这个名字了。我们怎么称呼它?
姜子来:
因为我们是匿名写作,所以Inner 目前不再可用。我们将其更改为父类的名称:
这时候就需要重写父类的方法并继续:
没关系。这是一个匿名内部类,而且也是一个有内容的对象,一个很胖的对象!
请记住:这整体是一个对象!它是什么物体?它是AbsDemo的子类对象,因为只有子类才能重写AbsDemo中的抽象方法。这整体就是绿色部分的简化写法~
这种写法很简单,但可能不太容易理解。但这种写法在开发中很常见。
继续上面的匿名内部类:
3、匿名内部类的格式:new父类或接口(){定义子类的内容}
4.实际上,匿名内部类是匿名子类对象。而且这个话题有点肥。可以理解为有内容的物体。
您还可以在其中编写其他函数并调用它们:
如果你想再次调用abc() 和show() 怎么办?姜子:
但这也太麻烦了。你能给我一个名字吗?但这不是匿名类吗?不让报个名吗?但它的工作原理是这样的:
这其实就是父类在多态中调用子类对象。但是第二个abc不能被父类调用,因为abc是子类的方法,并没有在父类中定义。因此,只能调用父类方法,而不能调用子类方法,这没有多大意义。我们编写匿名类是为了简化编写,这样就比较麻烦了。
匿名内部类有局限性。它看起来简化了书写,所以这样做有优点也有缺点。缺点是无法直接调用自己的方法(如上面的情况)。另一个缺点是,如果父类中有太多方法,则不应使用它们。定义一个匿名内部类,如:
这就是匿名内部类的样子:
这样的话,如果你想调用的话,就会很麻烦。里面方法太多了,可读性就没了。如果每个方法的代码多一点,那就是一屏(甚至几屏)代码,我们根本看不到。知道了!
因此,在编写匿名内部类时,里面的方法一般不会超过3个,多为2个或1个,这样匿名对象调用方法就会方便很多。
因此,继续前面的匿名内部类:
5、匿名内部类中定义的方法最好不要超过3个。
如果没有其他办法,父类只有这么多方法怎么办?然后按照常规的内部类,定义一个内部类,继承它,然后创建这个类的内部对象,慢慢一一调用~
方法较少时,匿名内部类可以简化编写,方便调用。如果它们太复杂,它们就会失去意义。
这是一个小练习:
分析这句话:
Test类中必须有静态成员,这个静态成员方法的名称是function。
因此,你可以肯定这样写:
继续分析这句话:
调用完函数之后,就会调用method方法。从前面Inter接口的内容我们可以看出,该方法是非静态的(因为是抽象的,所以一定是非静态的)。可以推断Test调用函数的结果是一个对象。因为只有当对象返回时,对象才能调用method方法。
我们想一下哪个对象可以调用方法?它一定是国际米兰的目标。所以返回值类型也确定了,就是Inter:
我们先用内部类来写。运行不会有问题:
接下来使用匿名内部类来写:
总结和回顾:
有一种很常见的情况需要匿名内部类。我们来谈谈吧:
目前的想法是,调用show()的时候,括号里应该传入一个接口类型对象吗?
我们能做什么?
要分解它,首先创建一个类并实现接口。该类可以在内部或外部定义。定义之后,将这个类的对象作为参数传递给show方法。但这样做很麻烦。
当使用的对象是接口类型时,检查接口中的方法。如果不超过三个,我们可以定义一个匿名内部类,并将匿名内部类作为参数传递。
姜子:
如果没有父类或接口,我只想调用函数方法,还可以写匿名内部类吗?
很酷的事情来了,我们可以创建一个新的Object 对象。
顺便说一句,一定要注意:
后面跟一个分号:
Object 对象后面是大括号:
对象子类对象好,这样就可以了:
然后我们要添加一个函数,所以我们需要给它起一个名字:
请注意,这是不允许的。这是一个错误示例。认为Object类中没有定义这个方法,所以不能这样调用。
05-面向对象(异常概述)
什么是例外?也就是我们所说的不正常。
我写了一个小除法程序:
但有时会传入非法值,我们会发现编译的时候没有问题,但是运行的时候就有问题,程序异常结束:
这就是我们所说的异常。
异常:是程序运行时出现的异常情况。
异常的由来:该问题也是现实生活中的具体事物。也可以用Java类的形式来描述,封装成对象。
其实就是Java描述异常情况的对象表现。
关于问题的分类,分为两类:一类是严重问题,一类是非严重问题。
对于严重的,java通过Error类来描述。
对于Error,一般不会编写有针对性的代码来处理它。 (就像得了癌症一样,只是保守治疗,没有针对性的治疗可以根治这种疾病。)
对于不严重的情况,Java使用Exception类来描述它们。
可以有针对性地处理异常情况。 (感冒发烧可以喝感冒药来治疗)
所以我们重点关注可以处理的部分,也就是Exception。
内存溢出的例子:
虚拟机本身有自己的默认启动空间。任何启动的软件都会被划分到这个默认空间来存储数据。然而,虚拟机的空间是有限的。它只有这么大。如果您必须打开超过其大小的一个,它就会挂起。掉了。原因很简单,超出了虚拟机的范围。
虚拟机启动时,可以通过其提供的参数将其更改为更大的空间。但分配多大并不重要。如果数组空间超出了物理内存空间,则更改它是没有意义的。就像这个问题一样,没有办法处理。
那么错误和异常有什么共同点吗?
一些。
以感冒发烧为例。这两种疾病都有名称和原因。
Error和Exception都有一些共同的内容。
例如:异常情况、原因等信息。
然后当它们有共性时就会向上提取。提取完成后,就会形成一个基本的体系。提取出来的父类称为Throwable。 Throwable下有两个子类,一个叫Error,另一个叫Exception。这两个类下面还会有很多子类。 (就像感冒和发烧一样,也分为不同类型的感冒)
我们看一下Java的API文档,看看它是如何介绍这个系统的。
在java.lang中,有一个Throwable类。 throw就是投掷的意思,加“able”就是可以投掷的意思。
Throwable是Java中所有异常的父类(超类)。
在这个类中,定义了本系统的公共内容。所以如果要使用一个系统,就需要查看该系统的父类的定义,并创建子类的对象。
我们来看看这个类的定义。它继承了Object并实现了Serialized。它有两个直接子类,我们要讨论的就是Exception。
我们先看一下错误:
错误有这么多弟弟!而且我们发现它弟弟的名字末尾有Error。因此,Java命名时,会将父类的名称放在子类名称的末尾。这是我们在今后的发展中可以借鉴的!而且通过这样的命名,就可以清楚谁是它的父类,又是谁的子类了!
我们再看一下异常:
哇!它还有更多的小兄弟。我们要全部学习吗?
尝试单击其中一个子类别并查找:
我居然还有弟弟,哇,这么多东西我都学不完。
所以我们只需要完成基本的事情。
Java描述了一些常见的问题并将其封装成异常。
这是异常的基本系统。
06-面向对象(异常try-catch)
接下来我们的程序出现了异常!我们可以通过抛出异常来处理吗?
仅仅因为被除数为0,就抛出异常,我们需要处理它。为什么?因为就因为这个小问题,后面的就跑不了了,哼!该怎么办?
在解决之前,我们先来了解一下异常的抛出过程。
Java 虚拟机识别这个称为ArithmeticException 的异常,因为它定义了它。如果触发了它熟悉的情况,它会为你处理。那是因为Java虚拟机内部有内置的异常处理机制。它处理它所熟悉的异常,但是做法很简单,就是只要程序出现问题,就不再运行。但我们希望的是解决问题。
这次说到第二部分,异常处理。
对于异常处理,Java为我们提供了独特的语句进行处理。
尝试
{
需要检测的代码;
}
catch(异常类变量)
{
处理异常的代码; (处理方法)
}
最后
{
肯定会执行的语句;
}
现在我们重写刚才的代码,就会打印出over。
我们来谈谈这个异常:
有一个小问题。 catch中并没有使用传入的对象e来处理这个问题。
想使用它吗?没问题~
catch接收到异常后就相当于这样了~
这是多态吗?父类的引用指向子类的对象。
如果我想操作这个e该怎么办?当然,要想办法。 Throwable中定义了异常对象的常用方法。我们去Throwable看一下。有哪些方法?
我的心好痛
不管怎么样,我都会努力的。
我们发现这里有一个getMessage方法来获取信息,它返回的是一个字符串。
对捕获的异常对象执行常用方法操作:
String getMessage();//获取异常信息
试试这个:
还有另一种方法:
试试这个:
这个打印输出比较全面,既包括异常信息,也包括异常名称。
String toString();//打印:异常名称:异常信息
还有这个方法:
打印堆栈中的跟踪信息。请注意,该方法没有返回值,因此不要将其放在输出语句中。可以自己打印。
尝试:
是否全面?有异常名称、异常信息和异常位置。
void printStackTrace();//打印:异常名称、异常信息、异常发生位置。
事实上,jvm默认的异常处理机制是调用printStackTrace方法来打印异常的堆栈跟踪信息。
07-面向对象(异常声明抛出)
下一个问题来了。这个函数是别人写的。当你使用它时,你必须尝试一下吗?不确定。为什么?因为你不知道这个功能会不会有问题。因此,这个问题你可以处理也可以不处理。这样就会导致你传递参数的时候程序可能会停止的现象。
所以这样的发展是不行的。我们怎样才能让它好呢?
作为一个写demo的人,在写除法方法的时候,必须要考虑传入的被除数为0的可能性,这时候就必须在方法上做个标记,告诉调用这个方法的人,“有这种方法可能有问题。”这个标志是抛出的。
标记后会发生什么?
让我们尝试一下:
对方声明了一个函数:这可能会导致问题。而它并不能解决这个问题,所以它告诉调用者这个问题。
这时候,作为打电话的人,对方已经告诉你可能出现问题了。这个时候,你需要做的就是:处理它。
如果不处理的话编译会失败。如果你不处理它,你将不被允许使用它。它还旨在提高安全性。
那么该怎么办呢?
我们再读一遍这个错误:
我们处理问题有两种方法,要么抓住它,要么扔掉它。
处理方法一:
我也不在乎!把它扔出去!
这是扔给谁的?把它扔到虚拟机上。结果是这样的:
所以问题还是没有解决。
通常情况下,我们不会扔它,而是接住它。 (稍后我还会讲什么时候扔什么时候尝试,是有区别的。)
蒋子写了,运行一下,就OK了:
这是传递错误值的一个:
用一个例子来比较一下投掷和接球的区别:
有一家面包店,有一块面包已经三天没有卖出去了。这时,面包可能会变质。于是良心的店主在上面贴了一个标签:放三天就坏了。然后价格从3元降到30分钱。有人买了。
抛出:回家后我想,这个可能坏了,我不知道怎么解决,所以我就把它给别人了。有可能这个人会给别人,但总会有一个结束,相当于虚拟机。连它都不吃!
capture:用微波炉加热(catch),然后吃掉(最后执行println("over"); 通常情况下)。
有点不太合适~
08-面向对象(多种异常处理)
当我们定义一个函数时,可能会出现不止一个问题。当我们在函数上声明异常时,可能会出现多个问题。就像刚才声明的异常throws Exception 一样,这个方法其实不太好。因为太笼统了,这里的问题是除法运算中被除数可能为0。如果声明更具体,我们可以更具体地处理。
我们一般都是这样处理的。
声明异常时,建议声明更具体的异常,以便处理更具体。
例如,在刚才的例子中,我们可以抛出算术异常:
多写一些语句来查看各种异常情况:
抛出算术异常和数组索引异常。调用时的处理:
注意,声明了几个异常,调用时必须写几个catch语句。
没有出现异常:
发生算术异常:
数组下标异常
况: 那会不会两种异常同时发生呢?不会。因为当出现一个异常之后,这个异常就被抛出了,后面的语句就不会执行了哦。 我们不写这么多catch,也一个catch可以吗? 这样来写: 它存在的原因是多态性。不管抛什么异常它都可以处理。但是它处理没有针对性哦。 所以最好写上有针对性的处理,每种异常要有与之匹配的catch。所以一般声明了几个抛出异常,调用时就应该写几个catch。 这时候又有个问题,调用者担心万一发生的问题是那两个之外的,又写了一个catch语句: 这样写也不是不可以,但是它有一个问题,就是处理的不具体。也就是说,你都不知道具体发生了,就把这个问题干掉了,相当于把这个问题隐藏了。而程序还在继续运行,也就是说,程序不知道发生什么事情了,继续在运行当中。为了安全性考虑,如果这个时候发生了对方指定的问题以外的问题,这个时候最好的处理方式就是:程序停掉。因为我们得知道,到底哪里卡住了,哪里出问题了,哪里是需要修正的。不能莫名其妙的把问题处理掉,发生了什么都不清楚。 所以这个时候依旧写两个catch,当发生第三种问题的时候,我们就是要让程序停下来,来寻找这第三个问题到底是什么,把它标识出来,声明出来,调用的时候也可以提出具体的更有针对性的解决方法。 注意,还有一种情况: 运行之后会这样: 第一个catch是大哥,后面两个是小弟,发生什么问题,大哥都能处理。因为catch是按顺序执行,而第一个catch都能处理,所以后面两个catch的存在,跟废话一样,永远执行不到。所以就报错了。 综上: 对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。 如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。 建议在进行catch处理时,catch中一定要定义具体的处理方式。【Java核心知识day09详解:内部类使用规则、静态内部类应用、匿名内部类技巧及异常处理基础】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
今天学习到java内部类的知识了,感觉还挺有意思的。
有14位网友表示赞同!
终于了解了静态内部类是什么东西了!
有15位网友表示赞同!
这个Java基础笔记看的挺透彻的,解释很清楚。
有11位网友表示赞同!
匿名内部类确实很有用,以后要多练习一下。
有17位网友表示赞同!
异常处理一直是我头疼的问题,这个概述还是很有帮助的。
有17位网友表示赞同!
try块和catch块配合起来使用,问题就能很容易解决。
有17位网友表示赞同!
学习了内部类的访问规则,觉得语法又更加清晰了。
有11位网友表示赞同!
感觉这篇文章总结的都很好,每个概念都解释得很详细。
有19位网友表示赞同!
以后遇到异常的时候,可以参考一下这篇笔记!
有12位网友表示赞同!
Java的基础知识还是要掌握住啊,这个笔记很有用的
有6位网友表示赞同!
明天再来看看内部类的应用实例。
有12位网友表示赞同!
这篇文章对我理解Java的学习进度很重要。
有16位网友表示赞同!
学习编程,基础知识是首要的!
有5位网友表示赞同!
Java真是一门好学又实用的语言!
有13位网友表示赞同!
最近想把Java学精通,这篇笔记刚好可以帮我提升!
有14位网友表示赞同!
这篇文章让我对内部类有了更深入的了解。
有18位网友表示赞同!
感觉Java的异常处理机制很强大!
有16位网友表示赞同!
学习Java的过程很有乐趣,每天都能学到新东西!
有16位网友表示赞同!
感谢作者分享这篇干货满满的笔记!
有11位网友表示赞同!