一、Java的继承
1、继承简介
继承是面向对象三大特征之一,是Java中实现代码重用的重要手段之一。
Java中只支持单继承,即每个类只能有一个直接父类。
2、继承注意事项
子类可以从父类中继承到哪些“财产”
类型 | 非private修饰 | private修饰 |
---|---|---|
构造方法 | 非私有 不能 | private 不能 |
成员变量 | 非私有 能 | private 能 (需要使用父类中的setter/getter方法) |
成员方法 | 非私有 能 (存在于虚方法表中的可以,否则不能) | private 不能 |
子类可以从父类中继承到哪些“财产”
- 继承public和protected修饰的属性和方法,无论子类和父类是否在同一个包里。
- 继承默认权限修饰符修饰的属性和方法,但是子类和父类必须在同一个包里。
不能被继承的父类成员
- private成员
- 子类与父类不在同包,使用默认访问权限的成员
- 构造方法
3、作用域再说明
作用域 修饰符 | 同一个类中 | 同一个包中 | 子类中 | 任何地方 |
---|---|---|---|---|
private | 可以 | 不可以 | 不可以 | 不可以 |
默认修饰符 | 可以 | 可以 | 不可以 | 不可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
public | 可以 | 可以 | 可以 | 可以 |
4、典型示例(注意注释)
Trys 类
package com.bdqn.ready;
/**
* @authorDesc 收获源于是每一分的努力
* @author Jule_zhou
* @date 2022-07-26 23:09:42
* @version
* @description
*/
public class Trys extends TryFather {
/**
* @description 座位数传递,构造方法
* @author Jule_zhou
* @date 2022-07-27 16:16:57
* @param site 座位数
* @return {@link null}
*/
Trys(int site){
// 这里有个隐藏的父类构造方法super();
// 在执行
setSite(site);
}
}
TryFather 类(父类)
package com.bdqn.ready;
/**
* @authorDesc 收获源于是每一分的努力
* @author Jule_zhou
* @date 2022-07-26 23:09:42
* @version
* @description
*/
public class TryFather {
/**
* 座位数
*/
private int site = 4;
/**
* @description 无参构造方法
* @author Jule_zhou
* @date 2022-07-27 16:18:44
* @param
* @return {@link null}
*/
TryFather(){
System.out.println ("载客量是"+site+"人");
}
/**
* @description
* @author Jule_zhou
* @date 2022-07-27 16:19:29
* @param site 座位数
* @return
*/
public void setSite(int site){
this.site = site;
}
/**
* @description 展示人数
* @author Jule_zhou
* @date 2022-07-27 16:20:00
* @param
* @return
*/
void print(){
System.out.print("载客量是"+site+"人");
}
}
TestTrys 类(测试类)
package com.bdqn.ready;
/**
* @authorDesc 收获源于是每一分的努力
* @author Jule_zhou
* @date 2022-07-23 15:17:31
* @version
* @description Account测试类
*/
public class TestTrys {
public static void main(String[] args) {
Trys trys =new Trys(20);
trys.print();
}
}
5、代码执行顺序
6、继承关系中的构造方法
- 如果子类的构造方法中没有通过super显式调用父类的有参构造方法,也没有通过this显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。
- 如果子类的构造方法中通过super显式调用父类的有参构造,则将执行父类相应的构造方法,而不执行父类的无参构造方法。
- 如果子类的构造方法中通过this显式调用自身的其他构造方法,则在相应构造方法中应用以上两条规则。
7、子类访问父类
- 访问父类构造方法
super();
super(name);
- 访问父类属性
super.name;
- 访问父类方法
super.print();
8、何时使用继承
继承与真实世界类似:
- 只要说“猫是哺乳动物”,猫的很多属性、行为就不言自明了
继承是代码重用的一种方式:
- 将子类共有的属性和行为放到父类中
二、Java的方法重写
1、方法重写的含义
方法重写:在子类中可以根据需求对从父类继承的方法进行重写,称为方法的重写或方法的覆盖。
2、方法重写的规则
方法重写的规则:
- 重写方法和被重写方法必须具有相同的方法名
- 重写方法和被重写方法必须具有相同的参数列表
- 重写方法的返回值类型必须和被重写方法的返回值相同或者是其子类
- 重写方法不能缩小被重写方法的访问权限
3、方法重写与重载的区别与联系
位置 | 方法名 | 参数表 | 返回值 | 访问修饰符 | |
---|---|---|---|---|---|
方法重写 | 子类 | 相同 | 相同 | 相同或是其子类 | 不能比父类更严格 |
方法重载 | 同类 | 相同 | 不相同 | 无关 | 无关 |
4、简述overloading和overriding的区别和联系
overloading是方法重载,重载涉及同一个类中的同名方法,要求方法名相同,参数列表不同,与返回值类型、访问修饰符无关。
overriding是方法重写,重写涉及的是子类和父类的同名方法,要求方法名相同,参数列表不同,返回值类型相同(或是其子类)、访问修饰符不能严于父类。
三、特殊的父类——Object类
1、Object类简述
Object类是所有类的父类。
2、Object类的特点
在定义一个类时,没有使用extends关键字,也就是没有显式地继承某个类,那个这个类直接继承Object类。所有对象都继承Object类的方法。
3、关于Object类中的5个可被继承的方法
Object类的4个常用方法
方法 | 说明 |
---|---|
toString() | 返回当前对象本身的有关信息,按字符串对象返回 |
equals() | 比较两个对象是否是同一个对象,是则返回true |
hashCode() | 返回该对象的哈希代码值 |
getClass() | 获取当前对象所属的类信息,返回Class对象 |
4、关于父类方法重写的再引伸——Object类
public class Student
{
String name = "Mary";
int age = 21;
public static void main(String[] args)
{
Student s = new Student();
System.out.println(s);//直接输出对象信息
System.out.println(s.toString());//调用父类方法输出对象信息
}
}
重写toString();方法
public class Student
{
String name = "Mary";
int age = 21;
public String toString()
{
return "姓名:"+name+",年龄:"+age;
}
public static void main(String[] args)
{
Student s = new Student();
System.out.println(s);//直接输出对象信息
System.out.println(s.toString());//调用父类方法输出对象信息
}
}
5、Object类中方法重载的应用场景
Students 类
/**
* @authorDesc 收获源于是每一分的努力
* @author Jule_zhou
* @date 2022-07-27 16:45:04
* @version
* @description 学生类
*/
public class Students {
/**
* 学号
*/
private String number;
/**
* 姓名
*/
private String name;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Students(){
}
public Students(String number, String name) {
setName(name);
setNumber(number);
}
@Override
public String toString() {
return "学生姓名:" + name + "\n学号:" + number;
}
@Override
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof Students) {
Students students = (Students)anObject;
if ((this.name).equals(students.name) && (this.number).equals(students.number)){
return true;
}
}
return false;
}
}
测试类
/**
* @authorDesc 收获源于是每一分的努力
* @author Jule_zhou
* @date 2022-07-27 17:02:09
* @version
* @description Students测试类
*/
public class TestStudents{
public static void main(String[] args) {
// 第一位学生的
Students students = new Students("00001","张三");
System.out.println( students.toString());
Students students1 = new Students("00001","张三");
System.out.println( students1.toString());
if (students.equals(students1)){
System.out.println("这是同一个学生的信息!!!");
}else {
System.out.println("这不是同一个学生的信息!!!");
}
}
}
四、关于final修饰符
1、内容扩充(一)
在Java中,final修饰符可以用来修饰类、方法和变量(包括成员变量和局部变量)
修饰类:当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
2、内容扩充(二)
使用final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。
下面这段话摘自《Java编程思想》第四版第143页:
“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“
3、内容扩充(三)
final成员变量表示常量,只能被赋值一次,赋值后值不可以改变。
final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
4、内容扩充(四)
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
5、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。