王國慶 发表于 2024-5-14 10:32:12

java核心技能卷1 第五章:继续

学习重要的是出,而不是入,此前不停埋头向前学,忽视了复习的重要性。写一个博客作为自己的学习条记,也可作为以后查漏补缺的资料,温故而知新。

类,超类和子类


[*]一个继续另一个类,父类也称为超类,基类。"超类"中的超来自于集合理论,指的是父类,与之后的super关键字对应
[*]java中,类的继续默以为public继续(只有公共继续),与c++不同。
[*]子类public继续父类,以是继续到的字段和方法的访问权限都稳固,和c++同,子类中无法直接访问父类的private成员(继续到了,但是无法访问)
[*]子类中可以overrride父类方法,覆写后直接调用使用的就是自己定义的方法。如在一个覆写方法中直接调用父类同名方法会循环调用直到爆栈,应该加super
[*]super只是一个指示调用父类方法的关键字,而不是任何的对象引用
[*]子类可以覆写,增长字段和方法,但不会删除继续到的字段和方法
子类的构造函数

因为子类继续了父类的字段,实例化对象是需要初始化这些字段,但是子类可能不能直接访问这些字段(private)
办理方法
构造函数中的第一句使用super(),内部填写参数,对应父类的一个构造函数,这样会调用父类的构造函数来初始化父类的那部门字段。
假如不表现调用super(),那么会默认调用父类无参构造函数,这时间父类必须可以提供一个无参的构造函数
this和super

作为第一句出现:
this:在一个类的构造函数内的第一句调用,可以用来调用其他构造函数来初始化部门的字段
super:子类构造函数第一句调用,初始化父类字段
作为一个调用指示词
this:指示当前的对象,可以用来获得当前对象的字段和方法
super:获得父类的字段和方法
多态

指的是一个类型的对象可以引用(指向,指示)多种不同的类型(子类),这种特性称为多态
而在调用方法时可以根据实际指向的对象类型主动选择对应对象的方法,称为动态绑定
c++中的多态需要用virtual关键词,而java中默认的对象赋值行为就是多态的
假如父类对象中的方法是final的,则不允许Override,从而实现动态绑定
继续条理结构

继续同一个父类的不同子类彼此是独立的,并无直接关系
java不支持多继续

c++支持一个类同时继续多个父类,java不支持
继续原则

只有两个类满足 is-a ,才适合用继续。一个类是另一个类,只是更加特殊。
替换原则:is-a还指出:因为子类就是父类,以是任何需要父类的地方,都可以用子类替代,父类可以直接引用(指向)子类
父类可以通过引用子类,来调用对应的方法,实现不同的行为。
其中:

[*]父类只能调用父类中定义的方法,因为这实际上是一个父类指针,只能看见父类的成员
[*]只能把子类赋值给父类,而不能把父类赋值给子类。只能多->少,而不能少->多
[*]举行方法调用时,会从所有的候选方法中选出最佳的调用。(参数匹配->参数类型兼容...),若多个可能匹配则报错
函数签名

函数签名(函数名和参数),返回值不是前面的一部门,只要函数名和参数一致,就判断是雷同方法
一个方法和另一个方法雷同,是说函数名和参数一致。
当子类中定义了一个和父类函数名和参数雷同的方法,就代表覆写了父类的方法,而返回值不一样千篇一律,只要现在的返回值类型和原本父类的类型兼容,也算是合法的方法重写。兼容指的是可以给原本类型赋值的类型,好比子类到父类的兼容
静态绑定和动态绑定

静态绑定:可以直接确定调用的是哪个对象的方法:private,final和static修饰的方法
private,子类中无法访问,以是调用一定是父类的
final:不允许重写的方法
static:属于一个类的方法,因此通过类和对象调用一定是对应类中的方法
动态绑定:调用一个方法是,调用实际指向的哪个对象的方法,假如子类中重写了,那么调用子类的方法逻辑,数据使用子类中定义的字段(相当于子类在调用),假如没有重写,那么调用父类的方法
假如不是private,final,static修饰的方法,都将采用动态绑定的方式,实际调用的方法是实际引用的哪个对象类型的方法
warning

重写父类的方法是,子类中的方法可见性不可以低于父类,只能宽松可见性,而不能设置更严格的可见性
阻止继续

使用final关键字修饰class(放在class前):代表不允许派生子类
使用final关键字修饰方法,代表子类不允许重写这个方法。
final修饰的类的所有方法主动称为final方法。但是不包括字段,因为字段加上final代表是const,不可变,和final用了同一个关键词,但是代表不同的含义

将类或方法声明为final的原因:不渴望子类来捣乱,这样一个类型的对象引用的一定是对应类型的对象,而不会发生多态,调用不一样行为的方法
逼迫类型转换

可以在继续条理结构内举行逼迫类型转换(对象引用变量的逼迫转换)

[*]可以子类自然的转成父类,好比直接赋值使用,但是父类转子类需要逼迫转换,且不一定成功
[*]转换失败会抛出ClassCastException异常,不捕获程序就结束了
[*]举行逼迫类型转换的原因:要使用原本对象的完整功能,如把一个被父类指向的子类还原成子类,从而可以调用子类中新增长的方法
[*]instanceof:用于判断一个对象是否是另一个对象,是否is-a关系?前面的引用变量应该属于背面的类是,继续或举行了接口实现。好比一个父类对象引用指向了一个子类,如Person person = new Student();,那么 person instanceof Student 是true,因为person对象虽然是父类,但是实际上指向子类,以是其是子类的instance,假如其指向父类,判断就会返回falsePerson person = new Person();,person instanceof Student。
父类转子类需要逼迫类型转换,假如其是父类引用到子类,那么将这个对象引用转为子类可以成功。因为子类赋值给父类,父类实际上指向的是子类对象,但是由于类型,它的能力被限制了,只能访问到父类定义的那部门,以是可以逼迫转换成功,恢复全部的能力。
但是假如父类自己指向的是父类,而直接转换为子类,就会报异常,是一个ClassCastException异常,因为父类实际上没有定义子类那部门成员,以是转换失败
instanceof:

[*]子类对象 instanceof 父类,返回true,子类是父类的实例,is-a
[*]父类对象 instanceof 子类,看父类对象的引用对象,假如引用对应的子类,返回true,可以逼迫转换成对应子类恢复全部能力,假如不是,返回false
受掩护访问

protected:一个包下可以访问,或是其他包的子类可以访问。
应当慎用掩护,或是干脆不用。
好比使用protected字段,其他类继续后使用,可以直接访问到类的具体细节,他们的实现就会依赖这个字段,假如你决定重写,那么其他人的代码可能会变得不可用
相比之下,protected修饰方法显得更有意义一些,只让那些很 熟悉父类实现的子类可以访问到这个方法,而其他的类不可以。(但是同一个包下的类照旧可以访问到,以是protected修饰符意义并不大,少用)
Object:所有类的父类

object是所有类的父类
java中,只有数值,字符和布尔类型不是对象,是属于根本类型,primitive type,而其他所有的都是对象,好比数组,无论是根本类型的数组照旧对象数组,都是Object类的子类
c++与之类似的概念是,所有指针都可以转换为void*指针,而没有一个所有类的基类

equals方法

Object的equals方法,比较两个对象的地址是否雷同,很简单,因此很多类都需要重写这个方法来实现比较的逻辑
其中:

[*]一个对象为null,则equals返回fase
[*]两个对象都是null,则返回true
[*]比较对象,需要先调用父类的equals方法,父类的字段相称之后再继续比较子类的字段
其中,java语言规范要求实现的equals方法有以下性质

[*]自反性:任意非null对象x,x.equals(x)应该返回true
[*]对称性:x.equals(y)和y.equals(x)雷同
[*]传递性:x.equals(y),y.equals(z),那么x.equals(z)也为真
[*]非null引用x.equals(null),返回false
当属于同一个类的对象比较,这很自然。但当两个比较的对象不是同一个类时,会变得很贫困

[*]使用getClass,instanceof来判断是否相称,可能会造成对称性被违反,好比父类和子类,互换序次执行getClass,instanceof返回效果是不同的
[*]因此,对于不同类的对象举行equals比较时,很贫困,很多类库API实现都没有做到对称且正确
Override注解

告诉编译器,这里的方法是在重写父类的方法,假如编译器发现其实是在定义新方法而不是重写, 就报错
hashcode方法

假如x.equals(y)为true,那么这两个对象调用hashcode方法返回的因该是雷同的int值。
hashcode:散列码,假如对象不同,那么hashcode值也根本不会雷同
hashcode返回一个int,可以是负数
默认Object类实现的hashcode基于地址算出,假如对象地址雷同,hashcode就雷同
String类重写了hashcode方法,因为equals根据字符串内容判断,假如字符串内容雷同那么雷同,这时间的hashcod也雷同,而不是根据地址判断
Object类提供了一个hash方法,可以接收多个参数,返回这些参数hashcode的组合,得到一个组合所有参数字段后的hashcode
根本数据类型的hashcode:通过其对应的包装类:Double,Integer等类的hashcode方法得到
toString方法

类方法中应该定义一个toString方法,打印对象的状态信息,帮助使用者明白对象状态
当调用println打印对象,就会调用这个类的toString方法,当对象通过+与一个字符串拼接时,java编译器也会主动调用toString方法获得对象的字符串描述
假如不重写, 默认会有一个toString方法,这里本机测试是:类名@hashcode
应该可以通过getClass.getName()方法获得对象的类名
许多类库中定义的类都有toString()方法,帮助我们获得和对象状态有关的信息
猛烈建议每个类定义一个toString,方便自己和使用者
ArrayList,泛型数组列表

一个可变大小的数组,其定义为泛型。
声明:

[*]其中左边的中填入对象类型,不能是根本数值类型,根本数值类型需要用对应的包装类
[*]右边的默认是Object,不用填入内容,填入也会被忽略
[*]()中可以填入容量,这里的容量是可以随着增长删除动态改变,但是容量不够时需要开发空间,然后复制内容,比较耗时,因此尽量选择合适的容量
[*]如ensureCapacity方法,可以指定一个容量,让创建的数组列表可以包罗有这么多的容量,避免背面容量不足的耗时操纵
[*]trimToSize方法,可以减少容量,由垃圾采取器收回多余的存储容量,而只保存现有的元素存储空间
'''
public class Hello {
    public static void main(String[] args) {
      ArrayList<Person> people=new ArrayList<>();
      people.add(new Student());
      people.add(new Employee());
      for(var person:people)
            System.out.println(person.getName());

    }
}'''
使用:

[*]定义一个容量
[*]通过add增长元素,通过set更改已增长元素的值,通过get获得指定索引的值
[*]容量!=size,size是实际包罗的元素数量,set,get也只能改变和获得已经add进来的元素,而不能是其他的元素
留意:
ArrayList类似于C++的vector,但是没有重载[],只能通过get(index)访问元素
其他题目

[*]插入和删除的效率低,如用add(index,e)和remove(index)方法,内部的元素都要移动来保持顺序存储,类似于顺序线性表的性质
[*]支持for each的循环访问
[*]set(index,e)替换内容后返回原本谁人位置的内容
对象包装器与主动装箱

根本类型的数据需要转换为对象是,用到的是其对应的对象包装器类。
有Integer,Long,Double,Float,Short,Byte,Character,Boolean。对应不同的根本数据类型,其中,前面的六个继续了Number公共类。
这些包装器类的性质

[*]不可变类。也就是其中对应的根本类型值确定后就不可以改变,final
[*]final类,不允许派生
[*]ArrayList不允许,因为类型需要是对象,以是要使用包装器类
主动装箱与拆箱

使用根本类型和使用包装类很一致,需要包装类的地方直接填入根本类型也可以,如ArrayList.add方法,可以直接填入ArrayList.add(7),这会主动改写为ArrayList.add(Integer.valueOf(7)),而把一个Integer对象赋值给一个int,会主动拆箱,变成int型。类似于调用了Integer.intValue().
大多数情况下,根本可以以为,根本类型和他们的包装类是一样的
一些例外:

[*]如ArrayList中填类型,一定要是包装类
[*]作比较时,包装器类作为对象比较的是地址,需要调用equals方法才能正确比较数值
一些留意点:

[*]构造包装器对象:调用valueOf方法,来赋值,而不是用new Integer(7)这样的,这种嗲用构造器的方法从version9就被废弃了
[*]装箱和拆箱是编译器的工作,当其产生字节码后,相关的操纵已经被完成了,虚拟机只负责执行这些字节码
[*]一些很有用的方法被放在了包装类中,好比将字符串转为int,调用Integer的parseInt方法就可以,传入一个String可以转为int
[*]包装器的一些方法:
[*]
[*]Integer的static方法:toString(int i,int radix),可以传入两个参数,来将一个数值转为对应进制的字符串,好比传入8,就可以把这个8传唤为2进制的1000字符串
[*]parseInt:可传入两个参数,表示要用多少进制来剖析这个字符串到十进制int值
[*]valueOf:初始化一个Integer,可以是int值,也可以传入String,传入String可以一个参数或者两个参数,两个参数就可以再指定一个进制,表示用多少进制来剖析这个字符串到int

参数个数可变的方法

可以提供可变的参数数量给方法
使用:类型之后加上... ,表示可接受多个此类型的参数,需作为最后一个参数.
public void hello(int i,String... strings){}这里传入多个String之后,会保存在strings[]数组中,用strings[]数组访问传入的数量可变的参数

[*]因为传入的参数会被放入一个数组中,因此使用...可变参数和使用数组作为参数是等价的
[*]传入可变个参数,也可以直接传入一个数组对象,这样进入方法后也可以访问到数组的各个元素,等价于传入了可变个参数
[*]假如一个方法的最后一个参数是数组,那么其就可以直接替换为...可变参数,使用完全等价
[*]如Main函数,就可以声明参数为String... args
#增补
当需要接受对象参数时,如Object[],假如传入根本数据类型,则会主动装箱为对应的包装类
只有实际的数据可以被包装,类型不会主动转换,如ArraryList不会主动变为ArraryList,而add加入参数时会把一个7主动包装为Integer.valueOf(7)
抽象类

将一些公共的字段和方法提取,作为父类,其中可以有一些方法不做实现,作为占位符,等待子类继续后实现。这种父类中不做具体实现的方法称为抽象方法,abstract方法,为了程序清晰,有抽象方法的类必须声明为抽象类,abstract class

[*]抽象类中可以包罗具体的字段和方法
[*]子类中可以实现抽象方法。假如不实现,那么子类也需要声明为抽象的
[*]不含有抽象方法,也可以声明类为抽象类
[*]抽象类不能实例化,不可以创建抽象类的对象,即不可以new,构造出一个真正的对象
[*]可以创建抽象类的引用变量,指向具体实现的子类,从而实现多态
[*]一个经典用法是创建父类数组,其中的值均为子类的对象,体现子类is-a父类关系
密封类(mark,使用场景暂不清晰,项目场景下明白)

java15预览特性,java17最终确定
密封类可以控制哪些类可以继续它:保证自己控制继续体系,保持完整功能,而不被外部随意继续打乱
public abstract sealed class JSONValue
        permits JSONArrary,HSOONNumber
{
...
}这里sealed关键字表示密封类,permits表示允许继续的子类

[*]允许的子类必须可见,可访问,不可是一个类的内部私有类,不允许是一个包内的包内访问类
[*]允许的公共public子类,必须和密封类一个包下
[*]可以不加permits语句,但是所有可以继续的子类都要和密封类一个文件下
允许继续的子类:必须是final,sealed或是non-sealed

[*]final代表子类不允许继续
[*]sealed表示允许指定的类继续
[*]non-sealed表示允许所有的继续
non-sealed:第一个带连字符的java关键字

[*]连字符可能带来一些风险,导致现有代码无法编译,好比定义一个int non和int sealed变量,可以计算non-sealed,相减得到一个效果,而再jdk17版本中这个表达式会被剖析为一个关键字
[*]连字符可能会成为java关键字的一个趋势
反射

暂时略,写java开发工具使用多,关注应用程序开发的使用较少
继续的设计技巧


[*]公共的字段和方法提取作为父类,而不子类中多次重复定义
[*]不适用protected掩护字段
[*]

[*]意义不大,因为并不能提供太多掩护机制
[*]子类是随意派生的,任何人任何地方都可以派生一个子类,访问protected字段,粉碎封装性
[*]同一个包下,纵然不是子类也可以访问protected字段,粉碎封装性

[*]不滥用继续,只有是is-a关系再使用继续,假如不是,将其作为平级的独立类而不是作为继续关系
[*]利用多态实现基于类型的不同动作,而不是用if-else判断类型后指向不同的动作

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: java核心技能卷1 第五章:继续