多态:同样的引用,调用方法,却做了不同的事;
在设计一个方法时,通常希望该方法具备特定的通用性。比如要实现某一类教师教授的课业答方法时,由于每类教师教授的课业都是不同的,因此可以在方法中接收一个教授课业类型的参数,当传入Java讲师类对象时就会教授Java,传入Python讲师类对象时就会教授python。
在同一方法中,由于参数类型不同而导致执行效果不同的现象就是多态。
要有继承关系:
注:多态中必须存在有继承关系的子类和父类;
要有方法重写:
注:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法;
向上转型:
注:在多态中需要将子类的引用赋给父类对象,只有这样才能够具备技能调用父类的方法和子类的方法;
调用格式
Father f = new Son();//向上转型
案例
public class Test1 {
public static void main(String[] args) {
Teacher t1 = new JavaTeacher();
//实现了父类类型变量引用不同的子类对象
Teacher t2 = new PythonTeacher();
//实现了父类类型变量引用不同的子类对象
t1.teach();
t2.teach();
//调用teach()方法时,将父类引用的两个不同子类对象分
//别传入,就打印除了“教授Java”“教授Python”
}
}
class Teacher{
public void teach(){
System.out.println("教书");
}
}
//定义JavaTeacher类继承Teacher
class JavaTeacher extends Teacher{
//实现teach()方法重写
@Override
public void teach() {
System.out.println("教授Java");
}
}
//定义PythonTeacher类继承Teacher
class PythonTeacher extends Teacher{
//实现teach()方法重写
@Override
public void teach() {
System.out.println("教授Python");
}
}
由此可见,多态提高了代码的维护性(继承保证),提高了代码的扩展性(多态保证);
成员变量
编译看左边,运行看左边;
构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化;
成员方法
编译看左边,运行看右边;
静态方法
编译看左边,运行看右边;
(静态和类相关,算不上重写,所以,访问还是看左边)
public class Test1 {
public static void main(String[] args) {
Teacher t1 = new JavaTeacher();
Teacher t2 = new PythonTeacher();
t1.teach();
//t1.playGame(); //会报错,显示无法找到
((JavaTeacher) t1).playGame(); //把Teacher(父类)的引用强制转换为JavaTeacher(子类)的引用,这就是所谓的向下转型
}
}
class Teacher{
public void teach(){
System.out.println("教书");
}
}
class JavaTeacher extends Teacher {
@Override
public void teach() {
System.out.println("教授Java");
}
public void playGame() {
System.out.println("荣耀王者");
}
}
class PythonTeacher extends Teacher{
@Override
public void teach() {
System.out.println("教授Python");
}
}
public abstract class 类名{
}
权限修饰符 abstract 返回值类型 方法名(形参);
eg: public abstract void teach();
public class Test3 {
public static void main(String[] args) {
Employee employee = new Manager();
//用set方法加入经理信息
employee.setName("张经理");
employee.setIdNum(001);
employee.setSalary(5000);
((Manager) employee).setBounds(3000);
//用get方法获取经理信息
System.out.println(employee.getName());
System.out.println(employee.getIdNum());
System.out.println(employee.getSalary());
System.out.println(employee.getSalary());
((Manager) employee).work();
}
}
//员工类
abstract class Employee{
private String name;
private int idNum;
private double salary;
//name
public void name(){
};
//工号
public void idNum(){
};
//工资
public void salary(){
};
public Employee() {
}
//get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIdNum() {
return idNum;
}
public void setIdNum(int idNum) {
this.idNum = idNum;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//抽象类方法
abstract void work();
}
//经理类
class Manager extends Employee{
private double bounds;
public double getBounds() {
return bounds;
}
public void setBounds(double bounds) {
this.bounds = bounds;
}
@Override
void work() {
System.out.println("管理工作");
}
}
抽象类和抽象方法必须用abstract关键字修饰;
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或接口;
注:一个抽象类如果没有抽象方法,是可以定义为抽象类的,这么做是为了不让其他类创建本类对象,抽象方法是交给子类完成的。
抽象类不能实例化,那么抽象类如何实例化呢?
注:按照多态的方式,由具体的子类实例化。
抽象的子类
注:要么是抽象类,要么是重写抽象类中的所有抽象方法
抽象类中可以有构造方法,抽象类不能进行实例化,那么要构造方法有什么作用呢?
注:用于子类访问父类数据时的初始化;
abstract和static
注: 1.被abstract修饰的方法没有方法体;
2.被static修饰的方法可以用类名,调用方法,但是类名调用抽象方法是没有意义的;
abstract和final
注:1. 被abstract修饰的方法强制子类重写;
2. 被final修饰的方法不让子类重写;
abstract和private
注:1. 被abstract修饰是为了让子类看到并强制重写;
2. 被private修饰不让子类访问;
Java中只支持单继承,但是有些定义的功能想让一个子类都可以继承实现,就无法做到;
Java提供了接口的概念,我们可以用一个子类去实现多个接口。去解决单继承问题;
接口用关键字iinterface表示
interface 接口名{
}
类实现接口用implements表示
class 类名 implements 接口名{
}
接口不能实例化,需要按照多态的 方式来实例化;
接口的子类
成员特点
成员变量: 只能是常量,并且是静态的,
默认修饰符 public static final
构造方法:无;
成员方法:只能是抽象的方法;
默认修饰符: public abstract
package day2;
/*
动物类:姓名,年龄,吃饭,睡觉。
动物培训接口:跳高
猫继承动物类
部分猫继承猫类并实现跳高接口
通过抽象类测试基本功能。
通过接口测试扩展功能。
*/
public class Test5 {
public static void main(String[] args) {
Animal cat_ju = new 橘猫();
cat_ju.setName("橘猫");
cat_ju.setAge(10);
System.out.print(cat_ju.getName()+"今年"+cat_ju.getAge()+"岁了,");
cat_ju.eat();
cat_ju.sleep();
((橘猫) cat_ju).catchMouse();
Animal cat_jia = new 加菲猫();
cat_jia.setName("加菲");
cat_jia.setAge(8);
System.out.print(cat_jia.getName()+"今年"+cat_jia.getAge()+"岁了,");
cat_jia.eat();
cat_jia.sleep();
((加菲猫) cat_jia).Jump();
}
}
//动物类:姓名,年龄,吃饭,睡觉。
abstract class Animal{
private String name;
private int age;
public abstract void eat();
public abstract void sleep();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//动物培训接口:跳高
interface JumpInterface{
public void Jump();
}
//猫继承动物类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫睡沙发");
}
}
class 橘猫 extends Cat{
@Override
public void eat() {
System.out.print("喜欢吃大蒜,");
}
@Override
public void sleep() {
System.out.print("睡在桌子底下,");
}
public void catchMouse(){
System.out.println("只抓白色的老鼠");
}
}
class 加菲猫 extends Animal implements JumpInterface{
@Override
public void eat() {
System.out.print("喜欢吃千层面,");
}
@Override
public void sleep() {
System.out.print("睡在狗子的身上,");
}
@Override
public void Jump() {
System.out.println("跳高记录1.5m");
}
}
类与类
继承关系,只能单继承,可以多层继承;
类与接口
实现关系,可以单实现,也可以多实现;
并且还可以在继承一个类的同时实现多个接口;
接口与接口
继承关系,可以单继承,也可以多继承;
参考链接:https://blog.csdn.net/weixin_44547508/article/details/90181964
抽象类 | 接口 | |
---|---|---|
默认的实现方法 | 它可以有默认的实现方法 | 接口完全是抽象的,它根本不存在方法的实现 |
实现 | 子类使用extends关键字来继承抽象类,若子类非抽象类,则需提供抽象类中所有声明的抽象方法的实现 | 类使用关键字implements来实现接口。它需要提供接口中所有声明的方法来实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
与正常Java类的区别 | 除了不能实例化抽象类之外,没有区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口默认修饰符是public,不可以使用其它的 |
main方法 | 抽象方法可以有main方法并且可以运行它 | 接口没有main方法 |
多继承 | 抽象类可以继承一个类和实现多个接口 | 接口可以继承一个或多个其它接口 |
添加新方法 | 往抽象类中添加新方法,可以提供默认实现,不需要改变现在的代码 | 往接口中添加新方法,需要改变实现接口的类 |