说到重写我们必然会想到重载,他们都是方法的重写或者重载 接下来我们来区分一下它们的不同
重载:
1.在同一类中
2.有多个方法,方法名相同
3.参数列表不同或者方法签名不同
重写:
1.在不同类中
2.继承或者实现
3.方法签名相同
例子1
public class Test{ public static void main(String[]args){ Father father =new Father(); father.words(); Son son=new Son(); son.words(); } } class Father{ public void words(){ system.out.println("我是你爸爸"); } } class Son extends Father{ public void words(){ system.out.println("我是儿子"); } } 复制代码
大家肯定有以下问题
需求:子类中存在父类中继承的功能,但是子类对功能的实现,与父类不一样,可以对这个功能进行方法的重写
子类对象在调用这个功能的使用,如果有重写方法,就调用重写方法,如果没有重写,就会调用从父类中继承的方法
1)重写方法的左侧存在向上的三角形
2)@Override 在方法上添加注释,强制检查,如果不是重写方法就报错
1.用private修饰的,私有的内容不能被继承与重写
2.被final修饰的方法不能重写
3.static的内容不能被重写.如果子父类中存在方法签名相同的方法,父类中这个方法为static修饰的,子类中的同名方法必须也要被static修饰
说到super,我们常会把它与this进行比较,我们来比较一下它们的不同:
this
1.指代当前创建的对象
2.调用本类中的其他构造器:构造器的行首 this(参数列表)
3.区分同名的变量问题(局部和成员) this
super
1.指代父类对象
2.调用父类构造器(默认调用父类的空构造),调用父类的其他构造器需要显示使用super(参数列表),要使用在构造器的行首,this和super不能同时存在调用构造器
3.区分同名变量问题(子类和父类)
如果出现局部子类成员,父类成员同名问题,调用时候: 1)调用局部,直接写 2)调用子类成员用this 3)调用父类成员,使用super
如果不存在同名问题,相当于省略了this或者super
例子2
public class SuperDemo01 { public static void main(String[] args) { Fu f=new Fu(); Zi z=new Zi(); z.test("小"); } } class Fu{ String name="黄晓明"; public Fu(){ System.out.println("我是空构造 黄晓明"); } public Fu(String name){ this.name=name; System.out.println("我是带参构造 黄晓明"); } } class Zi extends Fu{ String name="儿子"; public Zi(){ System.out.println("我是空构造 儿子"); } public Zi(String name){ super(name); System.out.println("我是带参构造 儿子"); } public void test(String name){ System.out.println(name);//小 System.out.println(this.name);//儿子 System.out.println(super.name);//黄晓明 } } 复制代码
通过this.name我们可以直接调用本类中的属性,super.name我们可以调用父类中的属性.
1.被final修饰的变量为常量
变量的数据类型如果是基本数据类型:存储的数据值不能改变
变量的数据类型如果是引用数据类型:存储对象的地址不能改变,但是对象内存中的属性值可以改变
2.被final修饰的方法不能重写
3.被final修饰的类不能被继承
多态即为一个事物可以展现不同的状态与不同的形态
1.继承:满足多态的前提要有满足继承关系的父类与子类,或者有满足实现关系的接口与子类
2.重写:继承的子类要有父类方法的重写
3.向上转型:还需要把子类的对象赋值给父类的引用,这样这个引用才有了调用父类与子类方法的能力
我们常用的创建对象的方式为
Dog dog=new Dog(); 复制代码
向上转型为
Animal d=new Dog(); 复制代码
就是把我的子类dog的值赋值给了父类animal的引用,向上转型就是这样.
例子3
public class Demo02 { public static void main(String[] args) { Animal d=new Dog(); d.shout(); } } class Animal{ public void shout(){ System.out.println("我是动物类,会打架"); } } class Dog extends Animal{ public void shout(){ System.out.println("我是小狗类,会汪汪"); } } 复制代码
输出:我是小狗类,汪汪
这就是向上转型,父类的引用只能调用子类的重写方法
向上转型之后我们不能使用子类自己的方法,这个时候我们就需要向下转型,当然使用向下转型的前提有使用向上转型.
例3中我们用到的引用d,如果先想把它转为Dog类可以这样做
Dog dog=(Dog) d; 复制代码
格式很像基本数据类型中大数据类型强转小数据类型
但我们也要注意下面的问题
public class CastDemo { public static void main(String[] args) { Animal d=new Dog(); Cat p=(Cat)d; } } class Animal{ String name; int age; public void shout(){ System.out.println("我是动物"); } } class Dog extends Animal{ String name; int age; public void shout(){ System.out.println("我是小狗"); } } class Cat extends Animal{ String name; int age; public void shout(){ System.out.println("我是小猫"); } } 复制代码
这个在编译的过程中 Cat p=(Cat)d;在编译的时候不会报错,但是我们在运行就会出现
java.lang.ClassCastException 复制代码
这个称为数据转换异常,即我们把一个Dog类转为Cat类,为了避免向下转型时出现这样的问题,我们需要使用一个关键字:instanceof
用法:
引用 instanceof 类型 复制代码
判断前面的引用是否是后面类型的一个对象|他子类对象,如果是返回true,不是返回false
if(d instanceof Cat){ Cat p=(Cat)d; } 复制代码
这样子编译运行就不会出现错误
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类.
声明抽象类的唯一目的就是将来对该类进行扩充.
为子类提供统一规范的模板.
格式如下:
修饰符 abstract class 类名{ 成员变量; 成员方法; 抽象方法; } 复制代码
其中抽象方法的声明格式为:
修饰符 abstract 返回值类型 方法名(); 复制代码
不需要写大括号.
抽象类不能实例化对象,除此之外与普通类没有区别,同样具有变量,方法,构造方法.所以抽象类一定要被继承才能使用;
抽象类中可以包含非抽象方法和抽象方法;
abstract关键字不能和final,private,static一起使用.因为final的类不能被继承;private方法不能继承;static类型的方法不能被重写