目录
一、继承
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,就可以实现重写了。
//子类的@Overridepublic 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)animal1animal1.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. 构造方法没有多态性