继承
一些概念:
- 一些名称:父类(基类,超类),子类(派生类)
- 格式:
public class Teacher extends Employee{} //Teacher继承Employee
-
子类可以调用父类的东西,包括方法和变量
-
当父类成员变量于子类成员变量重名时:
- 直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找
- 间接通过成员方法访问成员变量:方法属于谁,就优先用谁,没有则向上找
//可用关键字区别
this.num;//子类
super.num;//父类
重写(override):
方法名一样,参数列表一样。(重载:方法名一样,参数列表不一样)特点:创建的是子类对象。则优先用子类方法。
public class Fu {
public void method(){
System.out.println("父类");
}
}
@Override //注解用于检测是否重写成功,可写可不写
public class Zi extends Fu{
public void method() {
System.out.println("子类");
}
}
public static void main(String[] args) {
fu.method();
zi.method();
}
//结果如下
//父类
//子类
注意:
- 子类方法返回值范围要小于等于父类方法的返回值范围
- 子类方法的权限必须大于等于父类方法权限:public > protected > 留空 >private
public int num;
protected int num;
int num;
private int num;
父与子的构造方法顺序:
先调用父类在调用子类;子类构造方法默认赠送 "super()"调用,所以会先调用父类构造;可用super()重载父类构造
public class Fu {
public Fu(){
System.out.println("父类无参构造");
}
public Fu(int num){
System.out.println("父类有参构造");
}
}
public class Zi extends Fu{
public Zi(){
super(20);
System.out.println("子类构造");
}
}
public class Main {
public static void main(String[] args) {
Fu fu=new Fu();
Zi zi=new Zi();
}
}
//结果如下
//父类无参构造
//父类有参构造
//子类构造
注意:只有子类构造才可以用super()调用父类构造,且必须在构造函数的第一条语句
super()用法
//在子类成员方法中访问父类成员方法
public void Zi_menthod(){
super.Fu_menthod();
}
//在子类成员方法中调用父类成员变量
public void Zi_menthod(int num){
super.num=num;
}
//子类构造调用父类构造
public class Zi(){
super();
}
//补充:子类构造用this调用本类另一个构造
public Zi(){
this(20);//不需要用.构造名
//无参构造调用有参构造
//必须在第一条语句,且唯一
}
public Zi(int num){
System.out.println(num);
}
//在构造函数中this于super无法同时使用
//在成员函数中可同时使用
Java的继承重要特征:
- 单继承:
class D extends A,C (){} //错误
- 多级继承
class A extends B(){}
class C extends B(){}//正确,A与B是C的父类,且B是C的直接父类
- 一个父类可以有多个子类
抽象
抽象类和抽象方法的定义方法:
//抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束
public abstract void eat();
//抽象类:抽象方法所在的类,必须是抽象类;在class前加abstract即可,在抽象类中可以定义普通成员方法
public abstract class Eat{
public abstract void eat();
}
抽象类和抽象方法的使用
//不能直接使用
Eat at=new Eat();//错误
//需要一个类来继承,通过子类来调用,且子类需要重写抽象父类当中的所有抽象方法
Public class Chew extends Eat{
@Override
public void eat(){
System.out.print("咀嚼")
}
}
public class Main{
public static void main(String[] args){
Cat cat = new Cat();
cat.eat();
}
}
注意事项:
- 抽象类不能直接创建对象
- 抽象类可以有构造方法,其构造是为了提供给子类创建对象时,初始化父类成员使用的。在子类构造中会有super()
public abstract class Futher {
int num;
public Futher(){
num =10;
}
}
public class son extends Futher{}
public class Main {
public static void main(String[] args) {
son ss = new son();
System.out.println(ss.num);
}
}
//结果如下
10
-
抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类,抽象类可以为空
-
子类需要重写抽象父类的所有抽象方法,否则子类也必须为抽象类
接口(Interface)
一些概念
- 接口就是一种公共的规范标准
- 接口是一种引用数据类型
接口可以包括的内容
- 常量
- 抽象方法 (需重写)
- 默认方法 (无需重写) (Java8)
- 静态方法 (无需重写) (Java9)
- 私有方法
接口定义
定义接口类
public interface 接口名称{
}
定义抽象方法
//定义抽象方法 public abstract 关键字需要一起写,可以省略但不可以写别的
public abstract void method1();
abstract void method2();
public void method3();
void method4();
定义默认方法
public default 返回值类型(参数列表){
方法体
}
//public 可以省略
静态方法定义
public static 返回值 方法名称(){
方法体
}
//public 可以省略
私有方法定义
//普通私有方法:解决多个默认方法之间重复代码问题
private 返回值类型 方法名(参数列表){
方法体
}
//静态私有方法:解决多个静态方法重复代码问题
private static 返回值类型 方法名(参数列表){
方法体
}
例子:
如上述,最后一个函数可能会被其他不相关的函数调用,不够安全
成员变量(常量)定义
public static final 数据类型 变量名称=数据值;
//从效果上看类似于常量
//在接口中的变量必须赋值,且被赋值后无法更改
//无默认值,不赋值会报错
//不能变的变量名一般用大写且用下划线分隔 形如: NUM
接口的使用
抽象方法的使用
- 接口不能直接使用,必须有一个“实现类”来“实现”该接口
public class 实现类名称 implements 接口名称{
}
//实现类名称建议加Impl
-
接口实现类必须重写接口中所有的抽象方法
-
创建实现类的对象,进行使用
public interface InterFace {
public abstract void method1();
}
public class MyInterFaceImpl implements InterFace{
@Override
public void method1() {
System.out.println("myinterface");
}
}
public class Main {
public static void main(String[] args) {
MyInterFaceImpl myInterFace=new MyInterFaceImpl();
myInterFace.method1();
}
}
默认方法的使用
目的:解决接口升级问题。
默认方法作用:在实现类中不必重写,通过实现类调用
注意:默认方法也可被重写
public interface InterFace {
public default void method2(){
System.out.println("默认方法");
}
}
public class MyInterFaceImpl implements InterFace{
//在实现类中也可直接调用
/*public void method1() {
System.out.println("myinterface");
method2();
}
*/
}
public class Main {
public static void main(String[] args) {
MyInterFaceImpl myInterFace=new MyInterFaceImpl();
myInterFace.method2();
}
}
静态方法的使用
注意:不能通过接口实现类的对象来调用接口的静态方法,只能通过接口类来调用
接口类.静态方法名();
私有方法的使用
作用:解决默认方法和私有方法会被实现类,访问&重写问题和解决接口类默认方法和私有方法重复代码问题
成员变量(常量)的访问
接口类.名称
总结:
- 接口没有静态代码块,也没有构造方法
- 一个类只有一个直接父类,但是一个类可以有多个接口
public class MyInterFaceImpl implments MyInterFaceImpA,MyInterFaceImpB{
//需要重写所有抽象方法
}
-
如果一个实现类所实现的多个接口当中,存在重复的抽象方法,只需重写一次
-
如果一个实现类所实现的多个接口当中,存在重复的默认方法,必须要重写默认方法
-
当一个实现类中的父类方法与接口类方法冲突,优先用父类,继承优先于接口
扩展
跳转到接口类:CTRL+鼠标左键
法会被实现类,访问&重写问题和解决接口类默认方法和私有方法重复代码问题
成员变量(常量)的访问
接口类.名称
总结:
- 接口没有静态代码块,也没有构造方法
- 一个类只有一个直接父类,但是一个类可以有多个接口
public class MyInterFaceImpl implments MyInterFaceImpA,MyInterFaceImpB{
//需要重写所有抽象方法
}
-
如果一个实现类所实现的多个接口当中,存在重复的抽象方法,只需重写一次
-
如果一个实现类所实现的多个接口当中,存在重复的默认方法,必须要重写默认方法
-
当一个实现类中的父类方法与接口类方法冲突,优先用父类,继承优先于接口
扩展
跳转到接口类:CTRL+鼠标左键