目录
一、继承
1.1. 继承的方式
1.2. final关键字
1.3. 继承与组合
1.4. protected关键字
二、多态
2.1. 多态的概念
2.2. 向上转型
2.3. 重写
2.4. 向下转型
2.5. 多态的优缺点
一、继承
1.1. 继承的方式
猫类可以继承动物类,中华田园猫类可以继承猫类。同样地,在Java当中,可以实现以下几种继承方式:单继承、多层继承、不同类继承同一个类。但是,Java当中不支持多继承。
//单继承
public class A{
}
public class B extends A{
}
//多层继承
public class A{
}
public class B extends A{
}
public class C extends B{
}
//不同类继承同一个类
public class A{
}
public class B extends A{
}
public class C extends A{
}
1.2. final关键字
(1)final关键字修饰变量或字段,表示常量,也就是不能修改。
final int a = 10;
a = 20;//这样会报错
(2)final关键字修饰数组
final int[] array = new int[]{1,2,3};
array = new int[]{10,20,30};//报错
array[0] = 100;//不报错
final修饰的是array这个引用变量本身,也就是array在栈上的地址不能被修改,就不能再去修改array里面的元素,但我们可以通过array的下标来进行访问。
(3) final修饰类
public final class Animal {
public int age;
public String name;
}
public class Dog extends Animal{
public void bark(){
System.out.println("汪汪叫");
}
}
此时Dog子类里面就会报错,继承关系将不会存在。查看Dog类里面String的源码,就可以看到String被final修饰了。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence,
Constable, ConstantDesc {
1.3. 继承与组合
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物 组合表示对象之间是apart-of的关系,比如:轮胎是汽车的一部分。
面向对象中有一个比较重要的原则“多用组合、少用继”或者说“组合优于继承”。组合确实比继承更加灵活,也更有助于代码维护。
1.4. protected关键字
二、多态
2.1. 多态的概念
通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。比如,猫在吃的行为是吃猫粮,而狗吃的是狗粮。但重要的是,我们要理解多态的思想。
2.2. 向上转型
(1)直接赋值:父类引用子类对象
public class Animal {
public int age;
public String name;
public Animal(int age, String name) {
this.age = age;
this.name = name;
}
public void eat(){
System.out.println("在吃饭");
}
}
public class Dog extends Animal{
public void bark(){
System.out.println("汪汪叫");
}
public void wag(){
System.out.println("摇尾巴");
}
public Dog(int age,String name){
super(age, name);
}
}
public class Testdemo {
public static void main(String[] args) {
Animal animal = new Animal(10,"dahuang" );
Dog dog = new Dog("xiao",6);
animal = dog;
//等价于
Aniaml animal = new Dog;
}
}
(2)利用参数的传递
Dog dog = new Dog("大黄",5){
test1(dog);
}
public static void test1(Animal animal){
}
(3)返回值传参
public Animal test1(){
return new Dog("大黄",4);
}
以Animal作为一个接口,可以返回Dog,也可以返回Cat;参数也是一样可以接受Dog里面的形参,也可以接受Cat里面的形参。
向上转型的缺点:不能调用到子类特有的方法。给大家举个简单的例子
public Animal(int age, String name) {
this.age = age;
this.name = name;
}
public void eat(){
System.out.println("在吃饭");
}
}
public class Dog extends Animal{
public void bark(){
System.out.println("汪汪叫");
}
}
public class Testdemo {
public static void main(String[] args) {
Animal animal= new Dog(6,"小黑");
animal.eat();
animal.bark()://这样就会报错
}
}
有了向上转型,就可以进行多态,但还得有另一个条件,就是实现重写。
2.3. 重写
多态实现条件:1. 必须在继承体系下 2. 子类必须要对父类中方法进行重写 3. 通过父类的引用调用重写的方法
重写也可以成为覆盖。重写的好处在于子类可以根据需要,定义特定 于自己的行为。 也就是说子类能够根据需要实现父类的方法。
方法重写的规则:1.方法名相同 2.参数列表相同(个数、数据类型、顺序都相同) 3.返回值相同 4.被重写的方法返回值类型可以不同,但是必须是具有父子关系的
在Dog这个子类,我们不满足于只用父类里的方法,我们就可以通过编译器自动生成一个Override的方法,点击eat,就可以实现重写了。
//子类的
@Override
public void eat() {
super.eat();
}
//父类的
public void eat(){
System.out.println("在吃饭");
}
我们来看一下里面的源码,一直到Object类里面。Object就是所有子类的父类,包括Animal这个父类也是默认继承Object这个类里面。
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体 调用那个类的方法。
所以综上所述,动态绑定可以总结到以下两点:1.父类引用必须引用子类对象 2.子类重写父类的方法,通过父类引用调用被重写的方法
注意:访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为protected父类被static、private修饰的方法、构造方法都不能被重写。
2.4. 向下转型
上面我们讲到了向上转型,子类来调用父类的方法。那么,反过来就是向下转型。
public class Animal {
public int age;
public String name;
public Animal(int age, String name) {
this.age = age;
this.name = name;
}
}
public class Bird extends Animal{
public Bird(int age, String name) {
super(age, name);
}
public void fly(){
System.out.println("正在飞");
}
}
public class Testdemo {
public static void main(String[] args) {
Bird bird = animal;//产生报错
}
}
这里的错误原因就如同基本类型里面的long类型转成int类型,造成数据的丢失。同样在引用类型里面,大的也不能向小的转化。要想实行向下转型,就得强转。
Bird bird = (Bird)animal;
再来看下面一段代码
Aniaml animal1 = new Dog(5,"旺财");
Bird bird1 = (Bird)animal1
animal1.fly();
运行结果如下图所示:
报错的原因为类型转化异常。Bird与Dog不是同一个类,因为强转而骗过了编译器,所以说,向下转型不安全。如果我们要避免这面这种错误,就可以使用下面的方法。
if(animal instanceof Bird){
cat = (Cat)animal;
cat.mew();
}
if(animal instanceof Dog){
dog = (Dog)animal;
dog.bark();
}
}
2.5. 多态的优缺点
public static void eatfunc(Animal animal){
animal.eat();
}
public static void main(String[] args) {
Bird bird = new Bird(2,"金丝雀");
eatfunc(bird);
Dog dog = new Dog(5,"斯派克");
eatfunc(dog);
System.out.println(bird);
System.out.println(dog);
}
以下是运行结果:可以看到Bird和Dog虽然都调用同一个父类里的eat方法,但经过对eat的方法重写之后,就会出现同一行为表现出不同的结果。
优点:1. 能够降低代码的 "圈复杂度", 避免使用大量的 if - else 2.可扩展能力更强。如果要新增一种新的形状, 使用多态的方式代码改动成本也比较低。
缺陷:代码的运行效率降低。 1. 属性没有多态性 当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性 2. 构造方法没有多态性