【Java基础】接口与继承
接口与继承
interfaces and inheritance
接口
接口就是约定一些方法,而这些方法的具体方法体由实现接口的类实现,形成一套规范的统一的方法体系
接口声明由修饰符、关键字接口、接口名称、以逗号分隔的父接口列表(如果有的话)和接口体组成
接口体包括:
常量值
接口体中的常量值都是 public static final ,因此可以省略
方法
接口体中所有的方法都是公共的,因此可以省略public
抽象方法
不能有方法体
可以省略abstract
默认方法
可以有方法体
不可以省略default
静态方法
可以有方法体
不可以省略static
public interface Interface01 implements InterfaceFather{
public static final int a = 10;
//在接口中,可以不写public abstract,是默认的,隐式抽象可以写abstract ,但是没必要
public void func();
//jdk8及之后,可以有默认方法,也就是说可以有方法体,但是必须用default修饰
default public void func2() {
System.out.println("默认方法");
}
//jdk8及之后,可以有静态方法,也就是说可以有方法体,但是必须用static修饰
public static void func4(){
System.out.println("静态方法");
}
}
接口可以作为类型
如果想要升级接口
- 把新方法设为默认方法
- 创建一个中间接口,在中间接口中添加新方法 eg public interface DoItPlus extends DoIt
实现接口
一个类可以同时实现多个接口,用逗号分割
public class Test01 implements Interface01,Interface02{
}
当实现多个接口,有相同的抽象函数时,只用实现一次;当有相同的默认函数时,编译器或程序员要决定用哪一个
@Override
public void print() {
Animal2.super.print();
}
一个接口可以继承另一个接口,用extends
public interface List<E> extends Collection<E>
继承
构造器,代码块不能被继承
属性,方法,嵌套类可以被继承
所有的类都似乎Object的子类
子类只能访问父类的public或protected
- 子类是否能访问父类的default,取决于子类和父类是否在同一个包中
关于父类的private 成员
官方解释:A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.
父类的私有属性到底可不可以继承?_青云啊的博客-CSDN博客_私有属性能被继承吗- 如果父类有访问private成员的public/proeteced方法,则子类可以通过它们访问父类的私有成员
- 父类的嵌套类可以访问父类的所有成员,因此子类可以通过public/protected嵌套类访问父类的私有成员
- java的继承是单继承机制
- super.属性/方法 访问父类的属性或方法 ;符合访问修饰权限
重写与隐藏
- 子类的属性和父类同名,隐藏父类的属性
- 子类的方法和父类同名,覆盖父类的方法
普通方法叫覆盖override(重写),静态方法叫hide隐藏
重写方法的“两同两小一大”
- 函数名,参数完全一样
- 返回类型和父类一样或者是父类返回类型的子类;(如果是void或基本类型,则不可修改)
抛出异常和父类一样或是父类的子类 - 子类重写函数不能缩小父类函数的访问权限,可以扩大
重写与重载的比较
关于构造器
- 子类不会继承父类的构造器
子类默认情况下会隐式调用父类的无参构造函数 也可以显示调用super()
虽然构造器,代码块不能被继承,但是在创建子类实例的时候,会调用父类的代码块和构造器
- 如果父类没有无参构造函数,需要手动调用父类的有参构造函数
- super()语句只能用于构造器,且放在构造器的第一行,不能与this()同时使用
- this()指当前类的构造函数
- 多层继承的构造器的执行顺序:从最高层开始依次执行
要按照查找关系来返回信息
(1)首先看子类是否有该属性
(2)如果子类有这个属性,并且可以访问,则返回信息
(3)如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息…;如果父类有该信息,但是不可以访问,就会报错,不会再继续向上查找)
(4)如果父类没有就按照(3)的规则,继续找上级父类,直到Object…
转换对象
判断对象的运行类型是不是该类型或者该类型的子类型
编译看左,运行看右
Father person=new Son();
System.out.println(person.getClass());//class single.Son
if(person instanceof Son){
Son person2=(Son)person;
System.out.println(person2.getClass());//class single.Son
}
方法冲突
当继承的方法和接口的默认方法相同时,调用继承的方法
定义与超类方法具有相同签名的方法
超类实例方法 | 超类静态方法 | |
---|---|---|
子类实例方法 | 重写 | 生成编译时错误 |
子类静态方法 | 生成编译时错误 | 隐藏 |
多态
方法的多态
- 重载/重写
对象的多态
向上转型
(1)可以调用父类中的所有成员(需遵守访问权限)
(2)但是不能调用子类的特有的成员
(3)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
(4)最终运行效果看子类(运行类型)的具体实现,即调用方法时,按照从子类(运行类 型)开始查找方法
向下转型
java的动态绑定机制
- 当调用对象方法的时候,该对象会和该对象的 运行类型(内存地址) 绑定
当调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用
public class MyClass {
public static void main(String[] args) {
A a=new B();
//如果子类没有该方法,则向上查找父类
System.out.println(a.sum1());//结果200,i+100;根据动态绑定机制,属性不和运行类型绑定,哪里声明,哪里试用
System.out.println(a.sum2());//结果201,getI()+200;根据动态绑定机制,方法和运行类型绑定,即调用子类的getI()
}
}
class A{int i=100;
public int sum1(){
return i+100;
}
public int sum2(){
return getI()+200;
}
public int getI() {
return i;
}
}
class B extends A{int i=1;
@Override
public int getI() {
return i;
}
}
多态的应用
- 数组:声明为父类的类型,存放的数据为子类的类型
- 参数:形参参数定义为父类的类型,实参可以是子类的类型
抽象
- 只能修饰类和方法
- 关键字:abstract
- 当一个方法不确定要干什么时,可以将其设计为抽象方法;一般会在继承中重写
- 当一个类中有抽象方法的时候,必须将这个类声明为抽象类
- 抽象类的作用更多是在设计,让子类继承并实现
- 抽象方法不能有方法体
- 抽象类不能被实例化
- 抽象类可以没有抽象方法
- 如果一个类的父类是抽象类,则它必须实现抽象类的所有抽象方法,除非他自己也是抽象类
- abstract不能和static ,final,private一起用,因为他们不能被重写
抽象类和接口的比较
相似点:都无法实例化,都可能有尚未实现的方法
不同点:
- 抽象类可以声明非public static final的属性,声明public/protected/private的方法,也可以有方法体
- 只能实现一个类,无论他是不是抽象类
使用场景
如果以下情况,考虑使用抽象类:
- 您希望在几个密切相关的类之间共享代码。
- 您希望扩展抽象类的类具有许多共同方法或字段,或者需要公共以外的访问修饰符(如受保护和私有)。
- 您希望声明非静态或非常量字段。这使您能够定义可以访问和修改它们所属对象的状态的方法。
如果以下情况,考虑使用接口:
- 您希望不相关的类能够实现您的接口。
- 您希望指定特定数据类型的行为,但不关心谁实现了其行为。
- 您希望利用类型的多重继承。
还没有评论,来说两句吧...