1.对于类
2.对于方法
3.对于属性
4.对于局部变量NUM
final细节总结对于final修饰的变量我们可以知道,他就是一个常量。我们在创建一个这样的常量的时候,必须要赋于初值
对于赋予初始值,我们有三种方式:如图所示:
根据前面所学的知识可知:代码块实际上就是构造器的一种补充机制,其实二者相当于是一种
3.
如果是静态的:有以下规则,
解释:我们知道,构造器只会在创建一个对象的时候才会被调用,但是对于一个静态的常量来说,我们要在类加载的时候就完成对常量的初始化。因此不可以。
4.
5.
我们可以继承之后,通过子类类型创建出来的对象引用去调用这个方法
final和static进行搭配使用,会进行底层优化,优点是:不会导致类加载
8.
final练习
形参是支持加final的,但是不支持改变x的值。。
抽象类
当一个方法被声明为一个抽象方法的时候,我们要把这个类也搞成抽象类
抽象类细节总结abstract不可以修饰属性或其他,一旦一个类中包含抽象方法,你们这个类必须声明为抽象类。
5.
7.
一个抽象类是不可以被实例化的,但是这个抽象类是可以被继承的。但是一旦继承了之后,我们就必须实现这个抽象类中的所有的抽象方法或者把这个继承抽象类的子类也定义为抽象类
static是一个与重写无关的关键字
final表示最终的意思,它修饰的就是常量,不可以进行变化或重写
private私有,重写访问不到
这三个关键字一旦修饰抽象方法,当我们继承之后需要重写方法的时候都是不可以的。
对于第四个题:我们把不同对象的不确定的结果,因此把work设置为抽象类。让子类继承去是重写实现 ,不同的子类重写work的方法是不一样的,其他的都简单明了
抽象类实践-模板设计模式抽象类Template:
AA类继承抽象类:并且重写job方法
BB继承这个抽象类:并且重写job方法
测试类:
分析测试类中调用方法时动态绑定机制:
我们知道在调用方法的时候,是会发生动态绑定机制的。
把运行类型和方法进行绑定,我们知道aa的运行类型是AA,那么aa调用的calculateTime方法是先从动态绑定的运行类型AA这个类中开始向上找的,然而我们发现,这个类中没有这个方法,最终在父类Template进行,然后bb执行第二个calculateTime方法,同理这个方法也和运行类型BB发生动态绑定机制,先看看运行类型的类中是否包含这个方法,如果没有,那么再一层层向上找,直到找到为止再调用。
这种一层层向上寻找的机制是因为类加载的原因:如图所示解释:
接口
实现类:
使用接口的实现类必须重写接口中所有的方法
接口:
电脑类:
最后我们通过一个接口类型的参数来接收两个实现类,然后去调用接口中的方法
测试类:
在接口当中默认是抽象方法,因此可以省略abstract关键字
在JDK8之后新增属性特点了:
总结:
当我们实现了一个接口的时候,我们要实现里面的所有的抽象方法
倘若说没有接口,那么类中创建的方法起的名字就会五花八门的,参差不齐。所以我们定义一个接口,让类实现这个接口,既然使用了这个接口,那么一定会实现接口的抽象方法,那么命名也会规范。
例子:
接口:
实现接口的类1:
实现接口的类2:
测试类:
这个方法的参数为接口类型,可以接收实现这个接口的类1和类2,这起到了规范和管理的作用
接口的注意事项和细节:
倘若使一个普通类,那么实现接口时必须要实现接口中的所有的方法。
但是一个抽象类可以不用实现接口中的方法
5.
6.
接口中的局部量必须是 public 静态 和final修饰的常量
7.
8.
接口练习:
三个全部正确:
分析一下:
b是一个对象实例,那么a这个量是一个public修饰的因此可以访问
A接口名可以访问接口中的属性
B是一个静态类名是可以访问static类型的a量的
继承类VS实现接口:如上图,只要我们继承之后,我们可以通过子类创建出来的实例对象去调用父类的方法。底层原理是由于类加载信息的原理。
深度分析一下:子类创建出来的实例对象去调用父类的方法
当我们创建出一个对象实例之后,我们用这个对象实例调用一个方法,这个对象实例的运行类型即是类A会和这个方法发生动态绑定,调用的这个方法先从与其发生动态绑定的类A开始寻找,可惜的是,与其动态绑定的运行类型类A中,并没有这个方法,所以我们向上找,向上面的父类寻找,这个寻找的原理是类加载信息的传输机制。
对于类我们只可以单继承,但是对于接口我们可以实现多实现。这样增强了功能的拓展性。
这一条记录一下:接口更加灵活了。。。。
对于继承而言我们必须是is a的关系,也就是 猫就是动物不可以继承鸟这个类(猫不可以是鸟)
但是接口就不同了,可以实现猫像鸟一样飞翔这个接口。。
接口和继承体现的多态接口体现多态:
接口类型的变量可以指向实现了该接口类的对象实例
继承体现的多态:
多态传递现象:
当一个接口继承了另外一个接口,那么这两个接口之间就会具有联系与传递性。那么使原本没有实现IH这个接口,但是IH类型的变量ih也可以指向这个实现IG接口的实例对象。因为IG继承了IH。
如图所示:
接口练习
我们访问的时候要明确指定是哪一个x值?
接口中的属性为 public static final int x=1; 它是为静态的,所以可以直接用接口名去访问
内部类 类的五大成员:属性,方法,构造器,代码块,内部类局部内部类:
依次分析上面五点:
1.
局部内部类可以直接访问外部类私有的属性成员等
2.
不可以加访问修饰符,因为它就是类似于一个局部变量但又不是,因为它是可以被继承的
但是当我们不想这个局部内部类被继承的时候,我们可以加上final去修饰,这样就不会被继承了
我们知道加了final之后的一个类是不可以被继承的
3.
局部内部类的作用域在定义的那个方法体或被定义在的代码块内
4.
5.
但是外部类访问内部类的成员(属性或方法)的时候,我们需要内部类对象的对象实例引用才可以访问方法
局部内部类虽然是一个局部变量,但是它本质上还是一个类
还有一分钟,就2022年了。
我希望自己2022年能够更加乐观勇敢,永不言弃,永不停息,继续前行。新年快乐!!!!!!2022,你好!!!哈哈哈哈哈哈哈 加油!!!
7.
当外部类中的成员和内部类的成员重名时,调用的时候,遵守就近原则
谁调用的这个m1这个方法,Outer02.this就是哪一个对象
显然,是Outer02这个类去调用这个m1方法的
匿名内部类(重点) 1.基于接口的匿名内部类匿名内部类可以简化开发
测试类:
但是当我们对一个类只是使用一次,后面再也不使用了。因此定义一个类过于啰嗦了。。。
使用匿名内部类来简化开发:结果一样
重点来了:
对于这个题中的tiger来说,编译类型是IA接口类型
但是运行类型比较复杂:它就是这个匿名内部类 名字为外部类的名字加上$1
(这个类名是系统自动分配的,是在底层自动分配的)
即是Outer04$1
这个getclass方法是为了获取一个对象实例引用的运行类型的方法
8.
匿名内部类只可以使用一次,就不可以再使用(即是每调用一次才可以使用一次匿名内部类,使用一次之后就不可以再次使用,直到下一次再进行调用)
但是tiger这个对象实例引用是可以多次使用的:
基于接口的匿名内部类创建流程总结及底层原理:我们总结一下这个匿名内部类的创建流程:
我们先用这个接口类型IA去创建一个实例对象tiger,但是我们知道接口是不可以new出来对象的,所以系统底层会识别出这个是一个匿名内部类,说匿名不是因为它没有名字。匿名内部类在被创建之后,JDK底层系统会自动给它的运行类型分配一个名字:外部类名字+$1。
我们JDK底层创建一个匿名内部类对象,在JDK搞出来这个匿名内部类之后就结束了,Outer04$1这个临时分配的运行类型就没有了。但是会创建一个Outer04$1实例返回给这个匿名内部类,且只创建一次,并且返回地址给tiger,我们知道调用方法的时候会发生运行时绑定,方法会与运行类型绑定,我们调用方法的时候,就是从绑定的这个运行类型的类(即这个匿名内部类)中先开始寻找,看是否包含这个方法,倘若不包含再往上(往父类,往更高类)寻找。这个运行类型的地址已经返回给了tiger。因此后面我们可以通过tiger反复调用匿名内部类中的方法cry。【但是之后Outer04$1就没有了,所以我们不可以通过这个类名Outer04$1再次new对象实例出来】
那么,为什么称之为匿名呢?
所以我们程序员不可以通过JDK默认给的这个类名再去new一个对象实例,因为JDK底层搞完之后Outer04$1就没有了,所以我们不可以通过这个类名Outer04$1再次new对象实例出来,程序员是找不到的。所以这是不可以的,所以称之为匿名【见上面分析结合看看即可得出结论】
2.基于类的匿名内部类这个运行类型的判断和基于接口的匿名内部类一样,都是底层会创建。
我们分析一下:这个对象实例引用father调用方法test,会产生运行时绑定,这个方法会与对象实例的运行类型发生绑定,我们知道基于类的匿名内部类的运行类型在底层创建时,这个运行类型就是基于整一大块的运行类型,所以这个方法和底层这个匿名内部类发生绑定。
那么调用这个test方法,肯定先去与其绑定的运行类型的类中进行访问,即是这个匿名内部类中的test方法
即是:
运行类型:Outer04$2
底层系统JDK生成匿名内部类:注意啊:这个匿名内部类底层还是继承了Father类
细节:这个参数列表会传递给对应类写好的构造器
同理:
基于抽象类的匿名内部类。但是这个抽象类必须重写方法eat
匿名内部类的注意事项及细节动态绑定之后:调用的hi方法是匿名内部类中的hi方法,因为p的运行类型是外部类类名+$1
我们找方法肯定从这个运行类型的类中开始找,不想解释了,上面说的够清楚了。
测试类:
当匿名内部类中的方法注释之后:
由底层创建可知:匿名内部类是继承Person类的
我们通过类加载寻找信息及其继承机制查找机制可知,访问的hi方法变成父类Person类中的hi方法
——————————————————————————————————————————
直接调用,不创建对象引用实例,因为匿名内部类本身也是返回对象:
解释:
我们JDK底层创建一个匿名内部类对象,在JDK搞出来这个匿名内部类之后就结束了,Outer05$1这个临时分配的对象类型就没有了。但是会创建一个Outer05$1实例返回给这个匿名内部类,且只创建一次,因此可以通过这个返回的对象实例直接调用各种方法。
注意:这里的Person是一个类。。。。
3.
4.注意:这里的Person是一个类。。。。
5.注意:这里的Person是一个类。。。。
作用域就在这匿名内部类这内部一瞬间,只可以一次,用完就没有了,也就是说不可以再拿这个JDK底层自动生成的类名Outer05$1 去new一个对象实例,这是不可以的 。
但是Outer05$1创建的实例返回给了这个匿名内部类,因此我们调用其中的方法有两种做法:
1.我们拿着这个实例可以接收到一个对象引用实例p中,用p反复去调用匿名内部类中的方法。
2.当然也可以用整个匿名内部类直接去反复调用其中的方法。
【这两种做法在前面都有解释】
6.
匿名内部类可以直接访问外部类
7.
这个和前面是同理,只可以使用一次,外部不可以再次创建对象实例
8.
访问成员重名的时候,遵循就近原则
但是就是想访问外部类的成员的时候,
Outer05.this就是一个外部类创建的一个对象实例,也就是outer05 如图:
谁调用了外部类包含的f1方法,Outer.this就是哪个对象实例引用
检验一下:
哈希值相同,那么证明是同一个对象实例引用。
匿名内部类的最佳实践:匿名内部类的写法:
传统的写法:
但是这种调用一个参数就直接创建一个类的写法,是属于硬编码,比较死板。
分析使用选择:
1.倘若说你只使用这个类只是使用一次,那么推荐用匿名内部类,但是如果说你要用很多次的Picture这个类,我们还是可以推荐使用硬编码去创建一个类,然后去调用它。
2.硬编码比较统一些,当你改变了类Picture中的输出语句,只要调用它的会全部改变。
但是匿名内部类每调用一次都是独立成一个的,我们可以随意改变,不会影响别的匿名内部类的创建调用的输出结果。
匿名内部类课堂练习
不同的匿名内部类当做一个参数传过去,运行时绑定 方法绑定的运行类型是不一样的,因此调用的时候,先去运行类型的类寻找调用的ring方法,这个运行类型,二者不一样,都是由JDK分配一次给它的,也就是指对应传进去的参数对应的匿名内部类
匿名内部类即是运行类型
成员内部类我们只可以在这个外部类中进行创建对象实例,毕竟它的本质还是内部类
可以在成员内部类加任意访问修饰限定符
3.与上面那个例子是一样的道理
4.
可以访问的成员包括属性和方法
外部类中可以通过创建一个对象实例引用之后来访问成员内部类中的所有成员(属性或方法) 【包括私有的】
如图所示:
方法二在外部类中创建一个方法,返回创建的成员内部类的实例
三种调用方式:
Outer08 messi=new Outer08();[创建外部其他类的实例引用对象]
如果成员内部类的成员和外部类的成员重名了,那么遵守就近原则
静态内部类静态内部类访问非静态的就会报错,只可访问静态的。
内部类测试题
结果是输出两个5
每new一次内部类,都会产生一个新的内部类对象,那么输出两个5就显而易见了。



