class 子类 extends 父类{ }
子类又称派生类
父类又称超类(super class)
java是单继承的(c c++ 多继承)
子类在继承父类时 被private 修饰的类不能被继承
子类对象在构造时 一定会调用父类的构造器(默认无参数构造)
以保证父类对象先实例化 再实例化子类对象
在Java中定义一个类时,让该类通过关键字extends继承一个已有的类,这就是类的继承(泛化)。
被继承的类称为父类(超类,基类),新的类称为子类(派生类)。
子类继承父类的所有属性和方法,同时也可以增加自己的属性和方法。
[修饰符] class 子类名 extends 父类名
继承的好处 使编码更高效 易维护 代码的重用
Java中只支持单继承,也就是说每个类只能有一个父类,不允许有多重继承 一个父类可以有多个子类
子类继承父类所有的属性和方法
super()
作用:调用父类的构造器
只能出现在子类的构造器中,且必须是第一行
super()中的参数,决定了调用父类哪个构造器
如果子类构造器中没有出现super,那么编译器会默认加上super(),即调用父类的空构造器,如果父类没有空构造器,编译器提示错误。
this()
作用:调用本类的构造器
只能写在构造器的第一行
在同一个构造器中super()和this()不能同时出现
子类实例化的过程
使用默认的构造器
在子类中的创建构造器
在子类中创建构造器时,必须调用父类的构造器
子类可以在自己的构造器中使用super关键字来调用父类的构造器
如果使用super关键字调用父类构造器,必须写在该子类构造器的第一行
如调用的是父类中无参的构造器,则可以不写super( )
如果子类中调用了父类无参的构造器,而父类中没有无参构造器则系统编译出错(保证子类与父类参数一致性)
super和this关键字
super.
指向父类的引用。
通过关键字super我们可以指定子类在构造时调用父类的哪个构造器,达到先实例化父类然后实例化子类的目的。
子类的构造器默认的调用父类无参构造器,即子类构造器中没有用super指明调用父类哪个构造器的话,实际上编译器会自动的在子类构造器第一行加入代码super( );
this.
指向本类的引用。
我们知道子类在实例化时必须调用父类的构造器,实际上有的子类构造器也可以先调用本类的其他构造器,然后再通过那个构造器调用父类的构造器
无论是调用父类的构造器还是子类的构造器,最终都是找到最顶级的父类自上而下的实例化。只要中间环节有一个构造器没找到,这个子类就无法完成实例化。
隐藏类的实现细节;
让使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
将方法和属性一起包装到一个单元中,单元以类的形式实现;
便于修改,增强代码的可维护性;
可进行数据检查
不要把封装理解为private,不要误认为不能访问成员才是封装。实际上对成员访问权限的任何控制(包括public)都称为封装机制。
方法的覆盖(Override)重写是对从父类中继承来的方法进行改造,只有在子类继承父类时发生。
重写的规则:方法名 参数列表 返回值 都相同 且 子类覆盖方法的访问权限要不小于父类中被覆盖方法的访问权限
(父类方法是private)此时不能被重写 对于子类而言相当于重新定义了一个方法。为了调用父类中被重写的方法 可以用super.方法来进行访问。
在重写方法上,可以使用@Override注解来标明是重写方法
@Override表示重写(也可以省略):编译器验证@Override下面的方法名是否是父类中所有的,如果没有则报错。
重写与重载的区别:
重载发生在同一个类里,重写发生在继承关系中。
重载的方法名相同 参数个数与类型不同(返回值可以不同)
重写的方法名相同 参数个数 类型 返回值相同
重载没有权限限制 重写被覆盖的方法不能比父类拥有更高的优先级。
在继承中属性的覆盖:子类定义了和父类相同的属性名。
this.属性
super.属性
this 与super有何区别????
this用来调用本类的构造方法,本类方法,本类属性。表示当前对象
super 用来调用父类的构造,父类的方法,父类的属性。
final: 可以修饰类(该类不可被继承) 方法(方法不可被重写) 属性(必须在定义时候设置好内容 并且不可改变)
全局常量:public static final
抽象类不能直接实例化对象,如果一个类继承了抽象类(这个类不是抽象类)那么它必须重写里面所有的抽象方法。
抽象方法是指没有方法体的方法。抽象方法必须使用abstract 进行定义。拥有抽象方法的类一定是抽象类。
抽象类使用abstract声明。
接口{ 里面的修饰符都是public} 接口的对象可以利用子类对象向上转型进行实例化操作。
如果一个子类既要继承抽象类又要实现接口,那么应该先继承后实现的顺序。
抽象类可以继承一个抽象类或者实现若按个接口。
但是接口却不能继承抽象类。但是接口可以继承多个接口。
方法的多态:包括重写与重载。
对象的多态:父类与子类的转换。向上转型(自动)向下转型(强制转换)
多态的必要条件:有继承;重写;父类引用指向子类对象。
一旦满足以上3个条件,当调用父类中被重写的方法后,运行时创建的是哪个子类的对象,就调用该子类中重写的那个方法
在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用相应的方法。
package MoLe;
public class TestDemo {
public static void main(String[] args) {
A a=new B(); //实例化子类对象 对象向上转型
a.print(); //调用子类被重写的方法
B b= new B(); //实例化子类对象 调用子类对象的 输出方法
b.print();
}
}
class A{
public void print(){
System.out.println("A的输出方法AAAA");
}
}
class B extends A{
public void print(){
System.out.println("B的输出方法BBBBBB");
}
}
B的输出方法BBBBBB
B的输出方法BBBBBB
A a= new B(); 实例化子类对象 向上转型
B b= (B)a; 强制向下转型
b.print(); 调用子类被覆盖的方法
注意:强制类型转换是有前提的 必须向上转型之后才能 强制向下转型 否则 会出现异常
A a =new A();
B b= (B)a;出现异常
多态的优点:
简化代码 改善代码的组织性和可读性 易于扩展
package MoLe;
public class TestDemo02 {
public static void main(String[] args) {
fun(new A1());
fun(new B1());
fun(new C1());
}
public static void fun(A1 a){
a.print();
}
}
class A1{
public void print(){
System.out.println("AAAAA的输出方法");
}
}
class B1 extends A1{
public void print(){
System.out.println("BBBBBB的输出方法");
}
}
class C1 extends A1{
public void print(){
System.out.println("CCCCCCC的输出方法");
}
}
本程序的fun()只接受了一个A 类型的 实例化对象 按照对象向上转型的原则,此时fun()可以接受A的所有子类对象
只需要有一个A参数类型 就可以处理A 的所有子类
AAAAA的输出方法
BBBBBB的输出方法
CCCCCCC的输出方法
对象向上转型 在于参数的统一,也是最主要的用法。而对象向下转型是指 调用子类的个性化操作方法。
发生继承关系后,父类对象可以使用的方法必须在父类中明确定义。
如果子类要扩充一个方法,这个类父类对象并不知道。一旦向上转型,该方法父类肯定不知道。
package MoLe;
class A3{
public void print(){
System.out.println("AAAAAAA这里是AAA的输出方法");
}
}
class B3 extends A3{
public void print(){
System.out.println("这里是BBB的输出方法");
}
public void func(){
System.out.println("扩充+这里是B特有的方法");// 增加的方法 该方法只能由子类调用 父类对象不能调用
}
}
public class TestDemo03 {
public static void fun(A3 a){
B3 b=(B3)a;
b.func();
}
public static void main(String[] args) {
fun(new B3());
}
}
扩充+这里是B特有的方法
向上转型:目的是参数统一,但是向上转型中,通过子类实例化后的父类对象只能调用父类定义过的方法。
向下转型:父类对象要调用实例化它的子类中的特殊方法,但是向下转型是需要强制转换的。
instanceof
对象 instanceof 类 (返回值 布尔类型)