抽象类
定义
- 抽象类:被abstract所修饰的类
- 抽象方法:没有方法体的方法
- 包含抽象方法的类必须是抽象类
注意事项
- 抽象类不能创建对象
- 抽象类中可以有构造方法。供子类创建对象时,初始化父类成员使用
- 抽象类中不一定包含抽象方法,但有抽象 方法的类一定时抽象类
- 继承抽象类的子类必须重写父类的所有抽象方法
抽象类的练习
public abstract class Person {
public abstract void walk();
public abstract void eat();
}
public class Man extends Person {
@Override
public void walk() {
System.out.println("大步流星走路");
}
@Override
public void eat() {
System.out.println("狼吞虎咽吃饭");
}
public void smoke(){
System.out.println("吞云吐雾");
}
}
多态
- 定义:同一行为,具有多个不同表现形式
前提
- 继承父类或者实现接口
- 方法的重写
- 父类引用指向子类对象
多态的体现
- 编译看父类
- 只能调用父类声明的方法,不能调用子类扩展的方法
- 运行看子类
- 一定是执行子类重写的方法体
多态的练习
public abstract class Employee {
private String name;
public Employee(String name) {
super();
this.name = name;
}
public Employee() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract double earning();
public String getInfo() {
return "姓名:" + name + ",实发工资:" + earning();
}
}
public class SalaryEmployee extends Employee {
private double salary;
private int workingDays;//工作日天数,
private double offDays;//请假天数
public SalaryEmployee() {
super();
}
public SalaryEmployee(String name, double salary, int workingDays, double offDays) {
super(name);
this.salary = salary;
this.workingDays = workingDays;
this.offDays = offDays;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getWorkingDays() {
return workingDays;
}
public void setWorkingDays(int workingDays) {
this.workingDays = workingDays;
}
public double getOffDays() {
return offDays;
}
public void setOffDays(double offDays) {
this.offDays = offDays;
}
/*
* 重写方法,public double earning()返回实发工资,
实发工资 = 薪资 - 薪资/工作日天数 * 请假天数
*/
@Override
public double earning() {
return salary - salary/workingDays * offDays;
}
}
public class HourEmployee extends Employee {
private double moneyPerHour;
private double hours;
public HourEmployee() {
super();
}
public HourEmployee(String name, double moneyPerHour, double hours) {
super(name);
this.moneyPerHour = moneyPerHour;
this.hours = hours;
}
public double getMoneyPerHour() {
return moneyPerHour;
}
public void setMoneyPerHour(double moneyPerHour) {
this.moneyPerHour = moneyPerHour;
}
public double getHours() {
return hours;
}
public void setHours(double hours) {
this.hours = hours;
}
/*
* 重写方法,public double earning()返回实发工资,
实发工资 = 每小时多少钱 * 小时数
*/
@Override
public double earning() {
return moneyPerHour * hours;
}
}
public class Manager extends SalaryEmployee {
private double commisionPer;
public Manager() {
super();
}
public Manager(String name, double salary, int workingDays, double offDays, double commisionPer) {
super(name, salary, workingDays, offDays);
this.commisionPer = commisionPer;
}
public double getCommisionPer() {
return commisionPer;
}
public void setCommisionPer(double commisionPer) {
this.commisionPer = commisionPer;
}
@Override
public double earning() {
return super.earning() * (1+commisionPer);
}
}
public class TestEmployee {
public static void main(String[] args) {
Employee[] all = new Employee[3];
all[0] = new HourEmployee("张三", 50, 50);
all[1] = new SalaryEmployee("李四", 10000, 22, 1);
all[2] = new Manager("老王", 20000, 22, 0, 0.3);
double sum = 0;
for (int i = 0; i < all.length; i++) {
System.out.println(all[i].getInfo());
sum += all[i].earning();
}
System.out.println("总额:" + sum);
}
}
父子类之间的类型转换
向上转型
- 多态本身是子类类型向父类类型转换的过程,这个过程是默认的
向下转型
- 父类类型向子类类型转换的过程,这个过程是强制的
为什么要转型
- 多态为了调用子类特有的方法
类型转换异常: ClassCastException
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
}
}
instanceof运算符
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
属性、静态方法没有多态性
属性没有多态性
如果直接访问成员变量,那么只看编译时类型
public class TestField { public static void main(String[] args) { Father f = new Son(); System.out.println(f.x);//只看编译时类型 x=1 } } class Father{ int x = 1; } class Son extends Father{ int x = 2; }
静态方法没有多态性
public class TestField {
public static void main(String[] args) {
Father f = new Son();
f.test();//只看编译时类型
}
}
class Father{
public static void test(){
System.out.println("father");
}
}
class Son extends Father{
public static void test(){
System.out.println("son");
}
}
native关键字
- native:本地的、原生的
- 只能修饰方法,表示这个方法的方法体代码不是用Java语言实现的
修饰符一起使用的问题
不能和abstract一起使用的修饰符
- final:和final不能一起修饰方法和类
- static:和static不能一起修饰方法
- private:和private不能一起修饰方法
static和final一起使用
- 修饰方法:可以,因为都不能被重写
- 修饰成员变量:可以,表示静态常量
- 修饰局部变量:不可以,static不能修饰局部变量
- 修饰代码块:不可以,final不能修饰代码块
- 修饰内部类:可以一起修饰成员内部类,不能一起修饰局部内部类
Object根父类
public String toString():
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// 省略构造器与Getter Setter
}
public final Class<?> getClass():获取对象的运行时类型
public static void main(String[] args) {
Object obj = new String();
System.out.println(obj.getClass());//运行时类型
}
public int hashCode():返回每个对象的hash值
public static void main(String[] args) {
System.out.println("Aa".hashCode());//2112
System.out.println("BB".hashCode());//2112
}
public boolean equals(Object obj):
- 用于判断当前对象this与指定对象obj是否“相等”
- 默认情况下等价于“==”,比较的是对象的地址值
- 可以重写,但一定要一起重写hashCode()方法