extends - 继承
- 概念:
子类/衍生类/扩展类s
父类/基类 - 子类继承父类, 就继承了父类所有的成员变量和方法,不能继承构造方法,只能调用
- 所有的类, 都有唯一的父类
如果没有写父类, 说明父类就是 Object - 子类中还可以定义自己的独特的成员变量和方法
子类的功能一定比父类要强大
public static class A extends Object{}
public static class B extends A {}
public static class C extends A {}
...
特殊情况
- 子类中的成员变量和父类同名
指自己定义的成员变量,不是继承过来的成员变量
结论: 父子类中的成员变量不要同名 - 子类中可以引用父类对象
super
创建子类对象之前, 会先创建父类对象
加载子类之前, 会先加载父类 - 构造方法
父类的构造方法不能被子类继承的
创建子类对象, 会先默认调用父类的无参构造器
原因: 子类构造方法中, 第一行默认 super()
可以手动调用父类其他构造方法
结论: 子类构造方法中, 一定会先调用父类的构造方法
父类中, 建议先写无参构造器,这样不容易出现编译错误 - 通过子类对象调用方法时
先看子类中有没有定义这个方法, 定义了, 调用子类方法
子类中没有这个方法, 调用父类继承的方法
接口
– JDK 1.8以前,接口中的方法默认,也必须是public的(只能用public)
– JDK 1.8时,接口中的方法默认public的,也可以是default的(可以是public和default)
– JDK 1.9时,接口中的方法可以是private的(可以是public和default和private)
特殊的抽象类(可能会存在抽象方法)
接口不是类,是一种引用类型
引用类型:数组、类、接口
public interface InterfaceDemo {
//公开的静态常量
public static final int i = 10;
//接口不是类,是一种引用类型
//引用类型:数组、类、接口
void f();
public void f1();
abstract void f2();
//公开的抽象方法
public abstract void f3();
//默认的
default void f4() {
}
//静态的
static void f5() {
}
//普通的私有方法 - 为了给default方法中的公共代码提取, 实现代码复用
private void f6() {
}
//静态的私有方法 - 给static方法中公共代码提取的
private static void f7() {
}
}
使用接口的步骤
- 定义接口
// 1.定义接口
public interface InterfaceAbstractA {
// 定义抽象方法
void abstractMethod();
// 再添加一个抽象方法
void abstractMethodB();
// 又添加了一个静态方法
static void staticMethodC() {
System.out.println("static MethodC");
}
}
- 接口不能直接new对象, 需要一个实现类来 实现接口
将接口中的所有抽象方法 覆盖重写(实现)
// 2.定义实现类, 实现接口
public class InterfaceAbstractAImpl implements InterfaceAbstractA {
@Override
public void abstractMethod() {
System.out.println("AAAA");
}
@Override
public void abstractMethodB() {
System.out.println("BBBB");
}
}
- 创建实现类对象, 调用方法
注意事项: 实现类没有覆盖重写(实现)所有的抽象方法, 这个实现类必须是抽象的
public class Demo01Interface {
public static void main(String[] args) {
// 3.创建实现类对象
InterfaceAbstractAImpl implA = new InterfaceAbstractAImpl();
// 调用方法
implA.abstractMethod();
implA.abstractMethodB();
// 调用静态方法, 不能用实现类调用, 写法错误
// InterfaceAbstractAImpl.staticMethodC();
// 调用静态方法, 直接通过接口调用
InterfaceAbstractA.staticMethodC();
}
}
类、接口关系
- 类和接口: 1 v n implements 实现
/*
一个类一定有唯一的父类, 可以有多个父接口
1.实现多个接口, 将这些接口中所有的抽象方法都实现掉
2.父类中有抽象方法, 也要实现掉
3.如果多个接口中,有重复的抽象方法,实现一次即可
4.如果多个接口中,有重复的default方法,必须要重写一个
*/
public class Zi extends Fu implements InterfaceA, InterfaceB {
@Override
public void methodAbsC() {
}
@Override
public void methodAbsA() {
}
public void methodZi() {
}
public void methodDefaultA() {
}
}
- 类和类 : 1 v 1 extends 继承
- 接口和接口: 1 v n extends 继承
/*
一个接口可以继承多个接口
*/
public interface InterfaceC extends InterfaceA, InterfaceB {
void methodAbsC();
// 1.InterfaceA 中的抽象方法和默认方法
// 2.InterfaceB 中的抽象方法和默认方法
// 3.自己的抽象方法和默认方法,私有,静态
// 4.如果父接口中有重名的默认方法, 必须重写
default void methodDefaultA() {
}
}
- 接口和类: 没有
例:Zi extends Fu implements InterfaceA
如果父类中的方法和父接口中的默认方法重复了, 优先调用父类中的方法
多态
向上造型:父类型引用 指向 子类型对象
- 父类型 a = new 子类型对象();
public static void main(String[] args) {
// 父类型引用 指向 子类型对象
Fu f = new Zi();
// 无关类 不叫 向上造型, 写法错误
// Fu f1 = new Self();
// 以下两种不叫多态
Fu f1 = new Fu();
Zi zi = new Zi();
}
- 接口类型 a = new 实现类对象();
// 创建了一个接口的实现类对象, 向上造型为接口类型
MyInterfaceA a1 = new MyInterfaceAImpl();
向下造型(强制转换)
Fu f = new Zi();
// 如果想用子类自己的方法, 需要强制转换
Zi zi = (Zi) f;
多态的表现
/*
多态表现方面: 成员变量的调用, 子父类中拥有相同的成员变量
并且都有一对get/set方法
如果通过引用直接调用成员变量 - f.age, 看左边类型
通过方法调用成员变量 - f.getAge(), 看右边对象
优先调用子类重写过的,子类中如果没有重写, 就调用父类的方法
*/
public class Main1 {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.age); // 10
// 子类中重写了getAge()方法, 得到20
// 子类中没有重写getAge()方法, 得到10
System.out.println(f.getAge()); // 20
f.m1(); // 调用子类的m1方法
f.m2(); // 调用父类的m2方法
System.out.println(f.num);
// Fu类中没有声明score变量, 不能直接调用
//System.out.println(f.score);
// m3没有在Fu中声明, 所以不能直接调用
//f.m3(); // error
// 如果想用子类自己的方法, 需要强制转换 向下转换类型
Zi zi = (Zi) f;
zi.m3();
}
}
public class Zi extends Fu {
// 和父类中同名的成员变量
int age = 20;
// 和父类中不同的成员变量 - 子类自己单独声明的
int score = 150;
// 额外继承了父类中的num变量
// 重写父类中的m1方法
public void m1() {
System.out.println("Zi m1方法");
}
// 继承了父类的m2方法
// 子类自己的方法 m3
public void m3() {
System.out.println("Zi m3方法");
}
@Override
public int getAge() {
return age;
}
}
public class Fu {
int age = 10;
int num = 100;
public void m1() {
System.out.println("Fu m1方法");
}
public void m2() {
System.out.println("Fu m2方法");
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
}
ClassCastException(类型转换异常)
//父类Animal 子类Cat、Dog
Animal d = new Dog();
// 想要调用cat中的catchMouse方法
Cat cat = (Cat) d;
cat.catchMouse();
// 编译器看d是Animal类型, 和Dog是父子关系, 所以语法通过
// 运行时, 发现d实际上是Dog, 不能转换成Cat, 提示ClassCastException
//解决办法 关键字 instanceof
if(c instanceof Dog) {
Dog dog = (Dog) c;
dog.watchHouse();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼!");
}
public void catchMouse() {
System.out.println("猫和老鼠的故事!");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头!");
}
public void watchHouse() {
System.out.println("狗看家!");
}
}
public abstract class Animal {
public abstract void eat();
}
多态的运用场景
1、作为返回值类型
2、作为参数
// Animal作为返回值类型, 这个方法就可以返回多种不同种类的对象
public Animal salePet() {
return null;
}
// Animal作为参数, 可以传递多种类型的对象
public static void giveMePet(Animal a){
if (a instanceof Dog) {
((Dog) a).watchHouse();
} else if (a instanceof Cat) {
((Cat) a).catchMouse();
}
a.eat();
}
方法重写\覆盖
- 方法名\参数列表 要与父类中定义的方法完全一致
- 访问权限要大于等于
- 返回值类型要小于等于(引用类型),基本数据类型必须相等
- 抛出的异常要小于等于
void eat() {
//父类
System.out.println("在吃好吃的!");
}
// 重写的父类中的eat
void eat() {
// 子类自己的功能
System.out.println("舔舔小爪子!");
// 和父类中的eat方法一致
super.eat();
// 子类自己的功能
System.out.println("舔舔嘴巴!");
}
重写Override
- 两个类中
- 方法返回值类型\方法名\参数列表完全相同
重载Overload
- 一个类中
- 方法名相同,参数列表不同,与返回值无关
重写Override和重载Overload毫无关系
方法重写的详细规范
/*
1.子类中的方法名和参数列表要和父类中一致
@Override 检测这个方法是不是重写, 方法语法不符合重写, 就会报错
如果语法符合, 没有加@Override, 也属于重写
2.子类中的权限, [大于等于] 父类中的方法权限
3.子类中的返回值, [小于等于] 父类中的返回值类型
引用类型 小于等于
基本数据类型, 只能相同
4.异常
*/
public class Zi extends Fu {
@Override
public int m1() {
return 0;
}
protected long m2() {
return 0;
}
@Override
public ArrayList m3() {
return null;
}
// @Override
// 类方法, 不存在重写的概念
// public static void m5() {
//
// }
}
public class Fu {
public int m1() {
return 0;
}
protected long m2() {
return 0;
}
Object m3() {
return null;
}
}
静态方法属于类,不存在重写的概念
版权声明:本文为DZiXin原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。