- 子类继承父类所有的属性和方法,但不能直接访问私有的属性和方法
- 子类必须要调用父类,才能完成父类的初始化
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况都会调用父类的无参构造器。如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定父类使用哪个构造器完成对父类的初始化工作,否则编译不会通过
- 如果希望指定父类的构造器,则显示调用一下:super()
- super()在使用时,必须放在构造器第一行
- super()和this()都只能放在构造器的第一行,因此这两个方法不能共存在一个构造器中
- java所有类都是Object的子类
- 父类构造器的调用不限于直接父类,将一直往上追溯到顶级父类Object
- java只支持单继承,如果要A继承B的同时又继承C,那只能让A继承B,B继承C
- 继承需满足 is-a 逻辑,例如 Cat extends Animal = > Cat is a Animal
继承原理
public class Son extends Father{
String name = "小头儿子";
public Son(){
System.out.println(name+age+hobby);
}
public static void main(String[] args) {
Son son = new Son(); //小头儿子39旅游
}
}
class Father extends GrandPa{
String name = "大头爸爸";
int age = 39;
}
class GrandPa {
String name = "大头爷爷";
String hobby = "旅游";
int age = 60;
}
-
son对象初始化时,从自身开始,自下而上查找属性,直到Object对象
查找name,存在
查找age,不存在;则向Father类查找,存在
查找hobby,不存在;则向Father类查找,不存在;则向Grander类查找,存在 -
不能越级查找
比如将Father类的age访问修饰符设置为private,此时Son类已经不能获取Father的age属性了,但又不能越级查找GrandFa的age属性,因此会报错
方法的多态
重载
方法名称相同,但参数类型或个数不同而状态不同。在编译期就进行绑定,属于静态绑定。以下是一个子类重载父类方法的例子
import java.util.HashMap;
import java.util.Map;
public class Demo1 {
public static void main(String[] args) {
Father father = new Son();
father.convert(new HashMap());
}
}
class Father{
int age = 20;
public void convert(Map map){
System.out.println("父类被执行了");
System.out.println(age);
}
}
class Son extends Father{
int age = 10;
public void convert(HashMap hashMap){
System.out.println("子类被执行了");
System.out.println(age);
}
}
最终输出是
父类被执行了
20
子类重载了父类的方法。在编译器阶段,father的引用类型是Father,因此编译期就已经绑定了father.convert方法调用的是Father类的convert方法。而属性没有重写之说,其值为编译期的值。
重写
建立在子类继承父类的基础上,方法名、参数类型、个数完全相同。
对象的多态
前提:两个类存在继关系
向上转型
本质:父类的引用指向了子类的对象
特点:
1. 可以调用父类的所有成员(需遵守访问规则)
2. 不可以调用子类的特有成员
3. 最终运行看子类的具体实现
instance of 比较操作符
判断对象的运行类型是否数xx类型或其子类型
public class Demo {
public static void main(String[] args) {
Father father = new Father();
System.out.println(father instanceof Father); //true father的运行类型是否是Father类型或其子类型
System.out.println(father instanceof Son); //false father的运行类型是否是Son类型或其子类型
System.out.println(father instanceof GrandFa); //true father的运行类型是否是GrandFa类型或其子类型
}
}
class GrandFa{
int count = 10;
}
class Father extends GrandFa{
int count = 5;
}
class Son extends Father{
int count = 20;
}
综合例子
//测试Demo
//通过传入不同的对象,打印不同员工的工资和工作
public class PloyDemo {
public static void main(String[] args) {
Worker worker = new Worker("Tom", 2000);
Manager manager = new Manager("Jack", 5000, 2000*12);
showEmployeeAnnual(worker);
showEmployeeAnnual(manager);
testWork(worker);
testWork(manager);
}
public static void showEmployeeAnnual(Employee employee){
System.out.println(employee.getAnnual());
}
public static void testWork(Employee employee){
if (employee instanceof Worker){
((Worker) employee).work();
}else if (employee instanceof Manager){
((Manager) employee).manage();
}
}
}
//父类员工类
public class Employee {
private String name;
private int salary;
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getAnnual(){
return salary * 12;
}
}
//子类普通员工
public class Worker extends Employee{
public Worker(String name, int salary) {
super(name, salary);
}
public void work(){
System.out.println("普通员工" + this.getName() + "正在工作");
}
@Override
public int getAnnual() {
return super.getAnnual();
}
}
//子类经理
public class Manager extends Employee{
private int bonus;
public Manager(String name, int salary, int bonus) {
super(name, salary);
this.bonus = bonus;
}
public int getBonus() {
return bonus;
}
public void setBonus(int bonus) {
this.bonus = bonus;
}
public void manage(){
System.out.println("经理"+this.getName()+"管理员工");
}
@Override
public int getAnnual() {
return super.getAnnual() + bonus;
}
}
动态绑定机制
- 调用对象方法时,该方法会和该对象的内存地址/运行类型绑定,但在重载的情况下使用的是静态绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明哪里使用
例1. 均调用运行类型的方法
class A{
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
class B extends A{
public int i = 20;
public int sum(){
return getI() + 20;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
public static void main(String[] args){
A a = new B();
a.sum(); //40
a.sum1(); //30
}
}
例2. 属性使用静态绑定,即编译期就确定值
B.sum()没找到
调用A.sum()
B中有getI(),调用B.getI(),i 没有动态绑定,用B.i
class A{
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
class B extends A{
public int i = 20;
//public int sum(){
// return getI() + 20;
//}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
public static void main(String[] args){
A a = new B();
a.sum(); //30
a.sum1(); //30
}
}
例3
调用B.sum1(),没找到
调用A.sum1(),用A.i
class A{
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
class B extends A{
public int i = 20;
public int sum(){
return getI() + 20;
}
//public int sum1(){
// return i + 10;
//}
public int getI(){
return i;
}
public static void main(String[] args){
A a = new B();
a.sum(); //40
a.sum1(); //20
}
}
class A{
public int i = 10;
public int sum(){
return getI() + 10;
}
public int sum1(){
return i + 10;
}
public int getI(){
return i;
}
}
class B extends A{
public int i = 20;
public int sum(){
return getI() + 20;
}
public int sum1(){
return i + 10;
}
//public int getI(){
// return i;
//}
public static void main(String[] args){
A a = new B();
a.sum(); //30
a.sum1(); //30
}
}