多态
多态概述
多态概述:
某一个事物,在不同时刻表现出来的不同状态。
多态的前提
多态的前提
- 要有继承关系
- 要有方法重写,如果没有方法重写,多态就没有意义。
- 要有父类引用指向子类对象。
举例说明多态的前提:
public class MyTest {
public static void main(String[] args) {
Animal an=new Cat(); //父类引用执行子类对象
an.eat();
}
}
class Animal{
public void eat(){
System.out.println("吃饭");
}
}
class Cat extends Animal{ //有继承关系
@Override //方法重写
public void eat() {
System.out.println("猫吃饭");
}
}
多态成员访问特点
Fu fu=new Zi();等号左边和等号右边
- 访问成员变量,编译看左边,运行看左边
- 访问成员方法,编译看左边,运行看右边
- 访问静态方法,编译看左边,运行看左边(静态算不上重写,访问还是左边的)
- 访问构造方法,创建子类对象时,会先访问父类构造方法,对父类进行初始化。
可以使用案例:孔子装爹,表示编译和访问看那边
public class MyTest{
public static void main(String[] args) {
孔子爹 k=new 孔子();//向上转型
System.out.println(k.age);//编译看左边,运行看左边--------50
k.teach();//编译看左边,运行看右边-------讲论语
孔子 k1= (孔子) k;//向下转型
System.out.println(k1.age);
k1.teach();
}
}
class 孔子爹{
int age=50;
public void teach(){
System.out.println("讲学习知识");
}
}
class 孔子 extends 孔子爹{
int age=30;
@Override
public void teach() {
System.out.println("讲论语");
}
}
多态的好处
- 提高代码的维护性(由继承保证)
- 提高了代码的扩展性(由多态保证)
多态的弊端以及解决办法
弊端:不能使用子类特有的功能
由多态的弊端引出多态向上转型和向下转型
public class MyDemo {
public static void main(String[] args) {
Fu fu=new Zi(); //向上转型
fu.eat();
//fu.show(); //由父类引用直接调用子类独有的方法会出现类型转换异常,ClassCastException 类型转换异常
Zi zi= (Zi) fu; //向下转型,可以调用子类独有的方法
((Zi) fu).show(); //快捷调用子类独有的方法,和向下转型一样,
zi.show();
}
}
class Fu{
public void eat(){
System.out.println("父吃饭");
}
}
class Zi extends Fu{
@Override
public void eat() {
System.out.println("子吃饭");
}
public void show(){
System.out.println("子类特有的方法");
}
}
多态的内存图
抽象类
在Java中一个没有方法体的方法定义为抽象方法,类中如果有抽象方法,该类必须定义为抽象类。
抽象类特点
- 抽象类和抽象方法必须用abstract关键字修饰
abstract class 类名 {}/ /抽象类格式
public abstract void eat() ;//抽象方法格式
- 抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类
- 抽象类中可以有构造方法,但是抽象类不能实例化,构造方法是用于子类访问父类数据时的初始化
- 抽象类不能直接实例化,要按照多态的方式,由具体的子类实例化
- 抽象类的子类要么是抽象类,要么重写抽象父类中所有的抽象方法
抽象类的成员特点
- 成员变量可以使变量,也可以是常量
- 可以有构造方法,创建子类对象时对父类进行初始化
- 成员方法既可以是抽象的,也可以是非抽象的
案例演示抽象类的成员特点
public class MyTest2 {
public static void main(String[] args) {
}
}
abstract class AA{
int num=30;
public final int NUM=20; //final修饰的称为常量
public abstract void show(); //abstract修饰的抽象方法
public void test(){} //非抽象方法
}
抽象类的成员方法特性
抽象方法:强制子类做的事情
非抽象方法:子类继承的事情,提高代码的复用性
由具体的员工案例体现抽象类特点
public class MyTest3 {
public static void main(String[] args) {
Person person=new Employee();
person.name="张三";
person.age=30;
person.salary=5000;
System.out.println(person.name+"==="+person.age+"==="+person.salary);
person.work();
Person person1=new Manager();
person1.name="李四";
person1.age=40;
person1.salary=20000;
((Manager) person1).bonus=5000;
System.out.println(person1.name+"=="+person1.age+"=="+person1.salary+"=="+((Manager) person1).bonus);
person1.work();
}
}
abstract class Person{
String name;
int age;
int salary; //工资
public abstract void work();
}
class Employee extends Person{
@Override
public void work() {
System.out.println("一线工作");
}
}
class Manager extends Person{
int bonus; //奖金
@Override
public void work() {
System.out.println("管理工作");
}
}
abstract与private、final矛盾,与static不能共存,没有意义。
接口
接口就是一个类本身并不具备的功能,可以来定义一些扩展额外的共能,哪些事物,想要具备这些功能,可以去实现这个接口。
接口的特点:
- 接口用关键字interface表示
interface 接口名 {}
- 类实现接口用implements表示
class 类名 implements 接口名 {}
- 接口不能实例化,但是可以用多态的方式来实例化
- 接口的子类,可以使抽象类,但意义不大。也可以是具体类,要重写借口中的所有抽象方法。
可以用案例来表示借口的特点:
//接口用interface表示
interface Myinterface{
void jump();
}
class Animal{
public void eat(){
}
}
//类实现接口用implements实现
class Cat extends Animal implements Myinterface{
@Override
public void eat() {
System.out.println("猫吃饭");
}
//子类必须重新接口的抽象方法
@Override
public void jump() {
System.out.println("调高");
}
}
接口的成员特点
- 成员变量只能是常量,而且是静态的
public static final int num=30;//其中public static final是默认的,建议手动写出来
- 接口中没有构造方法
- 成员方法只能是抽象方法
public abstract void();//其中public abstract是默认的,建议手动写出来
类与接口两两关系
- 类与类的关系,是继承关系,只能是单继承,但可以是多层继承
class Fu{}
class Zi extends Fu{ }
- 类与接口的关系是实现关系,可以是单实现,也可以是多实现
class Fu2 implements Myinterface,Myinterface2{}
interface Myinterface {}
interface Myinterface2{}
- 接口与接口是继承关系,可以单继承,也可以多继承
interface inter{}
interface inter2{}
interface inter3 extends inter,inter2{}
接口与抽象类的区别
- 抽象类可以有变量,也可以有常量。接口只能是公共的静态常量。
- 抽象类有构造方法,接口没有构造方法。
- 抽象类可以有抽象方法,也可以有非抽象方法,接口只能有抽象方法(在JDK1.8之后接口中提供了用default修饰的方法,可以给出功能的具体实现,子类可以继承下去用)
- 抽象类被继承体现的是is a的关系,接口被实现体现的是like a的关系。
- 抽象类与接口共同点是都不能被直接实例化
用猫狗案例加入跳高功能分析及代码实现:
public class MyTest {
public static void main(String[] args) {
Tom tom = new Tom();
Cat cat=tom;
cat.name="Tom";
cat.age=4;
System.out.println(cat.name+"=="+cat.age);
cat.eat();
cat.sleep();
((Tom) cat).show();
Myinterface myinterface=tom;
myinterface.jump();
System.out.println("----------------");
Bigdog bigdog = new Bigdog();
Dog dog=bigdog;
dog.name="旺财";
dog.age=5;
System.out.println(dog.name+"=="+dog.age);
dog.eat();
dog.sleep();
((Bigdog) dog).test();
Myinterface myinterface1=bigdog;
myinterface1.jump();
}
}
public abstract class Animal {
String name;
int age;
public abstract void eat();
public abstract void sleep();
}
public class Cat extends Animal{
@Override
public void sleep() {
System.out.println("猫睡觉");
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
@Override
public void sleep() {
System.out.println("狗睡觉");
}
}
public class Tom extends Cat implements Myinterface{
@Override
public void eat() {
System.out.println("Tom吃饭");
}
@Override
public void sleep() {
System.out.println("Tom睡觉");
}
public void show(){
System.out.println("Tom独有的方法");
}
@Override
public void jump() {
System.out.println("Tom学会了跳高");
}
}
public class Bigdog extends Dog implements Myinterface{
@Override
public void eat() {
System.out.println("BigDog吃饭");
}
@Override
public void sleep() {
System.out.println("Bigdog睡觉");
}
@Override
public void jump() {
System.out.println("Bigdog学会了跳高");
}
public void test(){
System.out.println("Bigdog独有的方法");
}
}
public interface Myinterface {
void jump();
}