继承
1.继承是从已有类中,派生出新的类,新的类拥有父类的属性和行为,并且还能扩展新的属性和行为
2.Java中只支持单继承,不支持多继承,这样可以让Java中的继承关系比较简单
一个类只能有一个父类,但是一个父类可以有很多子类,易于维护和管理
为了解决单继承功能变弱问题,Java提出了接口,一个类可以实现多个接口
3.继承是可以传递的,比如A继承B,B继承C ,则A也会拥有C的功能
4.私有属性和构造方法是不能被继承
5.如果一个类没有显示继承其他类,则该类提供Object
Java.lang.Object是Java提供的根类(祖宗)
Object中的功能,是所有类对象都有的
解决的问题
提高了代码的效率,避免了代码的重写,提高代码重用性
语法
[修饰符] class 子类名 extends 父类名{ }
public class Extends_01 {
public static void main(String[] args) {
Sub sub = new Sub();
sub.m1();
sub.m2();
}
}
class Sup{
public void m1(){
System.out.println("父类的m1方法");
}
}
class Sub extends Sup{
public void m2(){
System.out.println("子类的m2方法");
}
}
super
1 官方说法是保存了父类型特征
2 在有继承关系的体系中,可以通过super表示父类的数据
能做什么
1 用在成员/构造方法中,区分父类和子类同名的数据(同名后,子类优先级高,想使用父类,就需要使用super.xxx才行)
* 2 用在子类构造方法中,调用指定的父类构造方法
* 语法 : super(参数) ; 必须在子类构造方法第一行
* 如果子类构造方法中 没有使用 this(xxx) 也没有使用 super(xxx) 则有一个 super() 去调用父类的无参构造
* this(xxx) 和 super(xxx) 都必须出现在构造方法第一行,也就意味着 它们两个 不能同时出现
* 3 this和super 都不能出现在静态上下文中
用法
区分父子类同名属性
public static void main(String[] args) {
Sub sub = new Sub();
sub.print();
}
}
class Sup{
int i = 10;
}
class Sub extends Sup{
int i = 20;
public void print(){
int i = 30;
// 局部变量优先级高
System.out.println(i);
// this区分同名局部和成员
System.out.println(this.i);
// super区分父子类同名属性
System.out.println(super.i);
}
}
调用父类指定构造方法
public static void main(String[] args) {
Sub_01 s = new Sub_01();
}
}
class Sup_01{
// 父类实例,父类构造,子类实例,子类构造
{
System.out.println("父类实例语句块");
}
Sup_01(int i){
System.out.println("父类构造方法");
}
}
class Sub_01 extends Sup_01{
{
System.out.println("子类实例语句块");
}
Sub_01(){
// 默认就会有super() 去调用父类的无参构造
super(2);
System.out.println("子类构造方法");
}
}
class Sup_02 {
// 构造方法私有化之后,就不能再被继承了
// 因为子类构造方法中需要调用父类构造方法,一旦私有化,就会因为权限问题访问不了
private Sup_02() {
super();
}
}
override
是什么
Override 是 方法重写/覆写/覆盖 , 覆写特指成员方法,除了成员方法,其他的都不能覆写
应用场景
1 什么时候需要对父类方法进行覆写
* 当父类的功能满足不了子类需求的时候
* 2 覆写条件
* 2.1 有继承关系的体系中
* 2.2 方法名必须一致,如果方法名不一致,就是两个方法了
* 2.3 参数列表必须一致,如果参数列表不一致,这是方法重载,也是两个方法
* 2.4 返回值必须一致
* 2.5 不能有更宽泛的异常(异常只能越来越少)
* 2.6 不能有更低的访问权限
* 3 覆写的意义
* 功能越来越强
* 使用范围越来越广
* 错误越来越少
*
public static void main(String[] args) {
Cat cat = new Cat();
cat.move();
}
}
class Animal{
public void move(){
System.out.println("动物在移动");
}
}
class Cat extends Animal{
// @Override是源码注解,在编译的时候,判断该方法是否是覆写的方法,防止写错,仅此而已,生成class之后该注解就会被去掉
// 如果不加,比如方法名写错了,那么最多也就是两个方法,不会报错,但是加上@Override就会进行校验操作
@Override
// 父类满足不了子类的需求 需要进行重写
public void move() {
System.out.println("猫在跳");
}
}
final
是什么
final : 是修饰符,表示最后的,最终的,不可更改的
*
* 类 : final修饰的类 不能被继承
*
* 变量 : 没有默认值,不能二次赋值,必须显式赋值(不能有不赋值的情况)
*
* 方法 : final修饰的成员方法不能被覆写
*
* final 修饰的静态变量,一般称为常量 , public static final xxxx; 常量名建议全部大写
怎么用
public class Final_01 {
// final修饰 没有默认值
final int age;
public static final String NAME = "xx";
Final_01() {
// 不能二次赋值
// age = 1;
age = 2;
}
public static void main(String[] args) {
}
}
final class A{
}
// 不能从最终A 进行继承
//class B extends A{
//}
class B {
public final void m1(){
}
}
class C extends B {
// final修饰的成员方法不能被覆写
// @Override
// public void m1() {
// }
}
public static void main(String[] args) {
final int age = 1;
// 不能二次赋值
// age = 2;
// final修饰的user
final User user = new User(10);
// 而age并没有加final修饰,我们也并没有更改user的值,所以可以更改age
user.age = 13;
System.out.println(user.age);
// 但是不能再次更改user的值
// user = null;
}
}
class User {
int age;
public User(int age) {
super();
this.age = age;
}
多态
什么是多态
多态就是里氏替换原则的一种体现
* 能使用父类的地方就一定可以使用子类
*
* 多态 就是 父类引用指向子类对象
* 父类引用 : 使用父类类型 创建的引用类型变量
* 指向 : 通过这个引用可以找到谁
* 通过父类创建的一个引用类型变量,找到了子类的对象
* 父类类型 变量名 = new 子类();
* Animal a = new Animal();
* Animal a = new Cat() ; 多态
*
* 有变量的地方,就能发生多态,并且多态发生在赋值的时候
*
* 多态的缺点 : 丢失子类特有的属性
多态的几种形式
1 直接多态 : 父类 变量 = new 子类();
* 2 形参/实参 : 参数列表用父类声明, 调用方法 传递子类对象
* public void m1(Animal a){}
* m1(new Cat());
* 3 返回值多态 : 返回值类型是父类类型,但是返回的对象 是子类对象
* public Animal m2(){
* return new Cat();
* }
* Animal a = m2();
多态进行属性调用
1 父类没有的,都调用不了(因为多态缺点,丢失子类特有的属性)
* 2 父类有的,子类没有的,执行父类
* 3 父类和子类都有,除了成员方法执行子类,其他全部执行父类(因为只有成员方法可以覆写)
public static void main(String[] args) {
// 直接多态
Animal a = new Cat();
// 返回值多态
Animal i = m1();
// 形参实参多态
m2(new Cat());
}
public static void m2(Animal a ){
}
public static Animal m1(){
return new Cat();
}
}
class Animal{
}
class Cat extends Animal{
}
class Dog extends Animal{
}
例子
public class Poly_02 {
public static void main(String[] args) {
Dog_1 d = new Dog_1();
test(d);
Cat_1 c = new Cat_1();
test(c);
}
// 需求 : 编写方法,要求能够接收所有的对象,并调用该对象的move方法
// 如果后续想接收其他动物,就需要改动源码,扩展性不强
// public static void test(Cat_1 cat) {
// cat.move();
// }
//
// public static void test(Dog_1 dog) {
// dog.move();
// }
// 多态形式,只要传递的对象是Animal_1的子类都是可以的
// 所以后续想接收其他动物,这里也不需要改动,更能拥抱变化
public static void test(Animal_1 animal_1) {
animal_1.move();
}
}
class Animal_1 {
public void move() {
}
}
class Cat_1 extends Animal_1 {
public void move() {
System.out.println("猫走猫步");
}
}
class Dog_1 extends Animal_1 {
public void move() {
System.out.println("狗蹦蹦跳跳");
}
}