概念
继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展新的属性和行为。
Java继承特点
1)Java是单继承的,不支持多继承。这样使得Java的继承关系很简单,一个类只能有一个父类,易于管理程序。同时一个类可以实现多个接 口,从而克服单继承的缺点。
java 中只支持单继承,并且是链式继承(爹不能再继承儿子)
2)继承关系是传递的
3)private修饰的成员变量或方法是不能被继承的
解决什么问题
提高了代码的效率,避免了代码重写
继承的目的
代码复用
语法格式
[修饰符] class 子类 extends 父类{
//类体
}
public static void main(String[] args){
Cat c = new Cat();
Dog d = new Dog();
Bird b = new Bird();
eat(c);
//输出结果为 猫吃鱼
eat(d);
//输出结果为 狗吃肉
eat(b);
//输出结果为 动物吃东西
}
//创建一个动物类 ,作为父类
class Animals{
public void eat(){
Systeam.out.println("动物吃东西");
}
}
//创建一个猫类继承动物类,作为子类
class Cat extends Animal{
public void eat() {
System.out.println("猫吃鱼");
}
}
//创建一个狗类继承动物类,作为子类
class Dog extends Animal{
public void eat() {
System.out.println("狗吃肉");
}
}
//创建一个鸟类继承动物类,作为子类
class Bird extends Animal{
}
上面的代码中,cat,dog,bird都继承了父类动物类,
cat和dog类进行了覆写 所以输出的是子类的覆写内容,这个后面会提到
bird类继承了动物类,继承了父类的属性,没有进行重写,所以输出的是父类输出的内容
java中的根类 : Object
如果一个类没有显示继承其他类,那么该类默认继承 java.lang.Object
Super
保存了父类型特征,可以理解为是父类的对象引用(错的)
语法
super(参数);
必须在子类构造方法的第一行
如果 子类构造方法中 没有出现 this(xxx) 和 super(xxx)的话 会默认有一个super() 去调用父类的无参构造
this(xxx) 这种写法必须出现在构造方法第一行,所以 this(xxx) 和 super(xxx) 不能同时出现
this和super都不能出现在静态上下文中
用法
1 用在子类成员方法,可以区分子类和父类同名的成员变量/成员方法
2 用在子类构造方法,同上
3 用在子类构造 方法中,用于调用父类构造方法
public class Super_01 {
Super_01(){
//不写,默认会有super()调用父类无参构造
super();
System.out.println("子类构造方法");
}
int i = 2;
public static void main(String[] args) {
Super_01 s = new Super_01();
s.m1();
}
public void m1() {
//子类
System.out.println("i");
//父类
System.out.println("super.i");
//子类
System.out.println("this.i");
}
}
class A{
A(){
super();
System.out.println("父类构造方法");
}
int i = 10;
}
如果构造方法私有化,就不能再有其他类继承该类
因为子类想要实例化对象,必须在构造方法中,调用父类的构造方法
如果父类构造方法私有化,那么子类调用不到,报错
public class Super_02 {
public Super_02() {
super();
}
}
class B{
//private B() {}
public B() {}
}
构造方法可以和静态方法/成员方法重名吗?
静态方法/成员方法的方法名可以和类名相同吗?
可以
如何区分?
看返回值,构造方法 没有返回值,连void都没有
public static void main(String[] args) {
new Super_03();
}
//成员方法
public void Super_03(){
System.out.println("1111111111法");
}
//构造方法
public Super_03(){
System.out.println("22222222222");
}
package _08_Super;
public class Super_04 {
public static void main(String[] args) {
new Sub();
}
}
class Sub extends Sup{
{
System.out.println("子类实例代码段1");
}
static {
System.out.println("子类静态代码段1");
}
Sub(){
//super();
this(2);
//---------
System.out.println("子类构造方法");
}
Sub(int i){
super();
}
}
class Sup{
static {
System.out.println("父类静态代码段1");
}
{
System.out.println("父类实例代码段1");
}
Sup(){
super();
//--------
System.out.println("父类构造方法");
}
}
Override(重写,覆写)
继承之后 子类必须和父类一模一样吗?
不需要
概念
1 子类有特有的属性,比如 父类只有m1 , 子类中 还有 m2 ,这个m2 就是子类特有,父类没有
2 子类和父类拥有相同名字的方法,但是功能不一样,叫覆写/重写/覆盖
覆写 特指成员方法,和其他属性无关
什么时候需要进行覆写?
当父类方法无法满足子类的业务需求时,需要对父类方法进行覆写
前提条件
1 必须有继承关系的体系中
2 不能比原方法有更低的访问权限 >=
3 错误不能越来越多,不能有更宽泛的异常 <=
4 方法名,返回值,参数列表 都必须一致
方法名不一致,说明是俩方法
参数列表不一致,是方法重载
返回值表示方法的功能,必须一样,不能更改方法的本质
继承的目的
代码重用
继承最重要的功能
方法覆写
重写的意义
功能越来越强
使用范围越来越广
错误越来越少
用之前继承举例的代码来解释
public static void main(String[] args){
Cat c = new Cat();
Dog d = new Dog();
Bird b = new Bird();
eat(c);
//输出结果为 猫吃鱼
eat(d);
//输出结果为 狗吃肉
eat(b);
//输出结果为 动物吃东西
}
//创建一个动物类 ,作为父类
class Animals{
public void eat(){
Systeam.out.println("动物吃东西");
}
}
//创建一个猫类继承动物类,作为子类
class Cat extends Animal{
//方法覆写,重写了父类的eat()方法,输出为子类覆写内容
public void eat() {
System.out.println("猫吃鱼");
}
}
//创建一个狗类继承动物类,作为子类
class Dog extends Animal{
//方法覆写,重写了父类的eat()方法,输出为子类覆写内容
public void eat() {
System.out.println("狗吃肉");
}
}
//创建一个鸟类继承动物类,作为子类
class Bird extends Animal{
//未进行方法的覆写,所以继承父类的属性,输出父类的内容
}
Final
被Final修饰的
类 : 不能被继承
成员方法 : 不能被覆写
修饰的变量 : 不能二次赋值,并且没有默认值,在整个程序的生命周期中,值不能被改变
常量
整个程序生命周期中,值不会被更改 / 使用final修饰的变量就是常量, 字面量也是常量
分类
静态常量:(final修饰的静态变量,一般是public static final ,由于是公共的,和对象没有关系,所以应用较多)
所以 一般我们把 final修饰的静态变量 叫常量
成员常量
局部常量
命名规则 建议 全大写,在eclipse中 使用 蓝色、斜体 、 加粗 显示
public class Final_01 {
public static final int C = 2;
final int i =2;
final int a;
//final修饰的变量没有默认值,必须显示赋值
Final_01(int i){
a = i;
}
public static void main(String[] args) {
Final_01 f = new Final_01(2);
//final修饰的变量不能被更改
//f.i = 3;
System.out.println(123);
}
}
//final class A{
class A{
//修饰的成员方法不能被覆写
// public final void m1() {
//}
}
class B extends A{
//class B{
public void m1() {}
}