继承的本质
图解
看个例子 要按照查找关系来返回信息: 1.首先看子类是否有该属性 2.如果子类有该属性,并且可以直接访问,则返回信息 3.如果子类没有该属性,就看父类有没有这个属性(如果有,并且可以访问,就返回信息) 4.如果父类没有就按照3的规则,继续找上级父类,直到Object
package com.hspedu.extend;
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son();//内存的布局
System.out.println(son.name);
System.out.println(son.getAge());//
System.out.println(son.hobby);
}
}
class GrandPa{
String name = "大头爷爷";
String hobby = "旅游";
// int age =88;//如果下面的不能直接访问,到更上一级这也不行
}
class Father extends GrandPa{
String name = "大头爸爸";
private int age = 35;
public int getAge(){//如果要能访问的话这要用getAge()
return age;
}
}
class Son extends Father{
String name = "大头儿子";
}
运行结果
练习题: 编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息, 编写PC子类,继承Computer类,添加特有属性[ 品牌brand],编写NotePad子类,继承Computer类,添加特有属性[颜色color],在main方法中创建PC和NotePad对象,分别给对象中特有的属性赋值,以及从Computer类继承的属性赋值,并使用方法并打印输出信息。
Computer类:
package com.hspedu.extend;
import sun.plugin2.gluegen.runtime.CPU;
public class Computer {
private String CPU;
private int memory;
private int disk;
public Computer(String CPU, int memory, int disk) {
this.CPU = CPU;
this.memory = memory;
this.disk = disk;
}
public String getCPU() {
return CPU;
}
public void setCPU(String CPU) {
this.CPU = CPU;
}
public int getMemory() {
return memory;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
public String getDetails() {
return "" + CPU + '\t' + "" + memory + '\t' + "" + disk;
}
}
PC子类,继承Computer类:
package com.hspedu.extend;
public class PC extends Computer {
private String brand;
//这里IDEA根据继承的规则,自动把构造器的调用写好
//这里也体现:继承设计的基本思想,父类的构造器完成属性初始化
//子类的构造器完成子类属性初始化
public PC(String CPU, int memory, int disk, String brand) {
super(CPU, memory, disk);
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void printInfo(){
// System.out.println(getCPU() + getDisk() + getMemory());
System.out.println(getDetails() + '\t' + brand);
}
}
NotePad子类,继承Computer类:
package com.hspedu.extend;
public class NotePad extends Computer{
private String color;
public NotePad(String CPU, int memory, int disk, String color) {
super(CPU, memory, disk);
this.color = color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void printInfor(){
System.out.println(getDetails() + '\t' + color);
}
}
测试:
package com.hspedu.extend;
import sun.plugin2.gluegen.runtime.CPU;
public class ExtendsExercise {
public static void main(String[] args) {
Computer computer = new Computer("yyrt",64,757);
computer.getDetails();
PC pc = new PC("yyrt",64,757,"fhg");
pc.printInfo();
NotePad notePad = new NotePad("yyrt",64,757,"red");
notePad.printInfor();
}
}
运行结果
super关键字
1.访问父类的属性,但不能访问父类的private属性 super.属性名; 2.访问父类的方法,不能访问父类的private方法 super.方法名(参数列表); 3.访问父类的构造器: super(参数列表);只能放在构造器的第一句,只能出现-句!
属性和方法是一样的
希望调用父类-A的cal方法, 因为子类B没有cal方法,因此我可以使用下面三种方式 找cal方法时, 顺序是: (1)先找本类,如果有,则调用 (2)如果没有,则找父类(如果有,并可以调用,则调用) (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到0bject类提示:如果查找方法的过程中,找到了,但是不能访问, 则报错,cannot access 如果查找方法的过程中,没有找到,则提示方法不存在
父类:
package com.use;
public class A {
public int n1 = 100;
protected int n2 =200;
int n3 = 300;
private int n4 = 400;
public A(){}
public A(String name){}
public A(String name,int age){}
public void cal(){
System.out.println("A的cal方法");
}
public void test100(){
}
protected void test200(){
}
void test300(){
}
private void test400(){
}
}
子类:
package com.use;
public class B extends A {
public int n1 = 888;
//访问父类的属性,但不能访问父类的private属性 [案例]super.属性名
public void hi() {
System.out.println(super.n1 + "" + super.n2 + "" + super.n3);
}
public void sum() {
System.out.println("B类的sum()");
// 希望调用父类-A的cal方法
// 这时,因为子类B没有cal方法,因此我可以使用下面三种方式
// 找cal方法时,顺序是:
// (1)先找本类,如果有,则调用
// (2)如果没有,则找父类(如果有,并可以调用,则调用)
// (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到Object类
// 提示:如果查找方法的过程中,找到了,但是不能访问,则报错,cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
//caL();
//this.cal(); //等价cal
super.cal();//找cal方法的顺序是直接查找父类,其他的规则一样
System.out.println(n1);//888
System.out.println(this.n1);//888
//找n1 (super.n1) 的顺序是直接查找父类属性,其他的规则一样
System.out.println(super.n1);//100
}
//访问父类的方法,不能访问父类的private方法super.方法名(参数列表);
public void ok() {
super.test100();
super.test200();
super.test300();
//super. test400();//不能访问父类private方法
}
//访问父类的构造器(这点前面用过): super(参 数列表);只能放在构造器的第一句,只能出现一句!
public B(){
//super();
//super("hft",13);
super("yyf");
}
}
package com.use;
public class Super {
public static void main(String[] args) {
B b = new B();
b.sum();
}
}
结果
1.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员; 如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C
2.super和this的比较
3.方法重写也叫方法覆盖,需要满足下面的条件:
4.方法的多态 方法重载体现多态 传入不同的参数,就会调用不同方法,就体现多态 方法重写体现多态
对象的多态(核心,困难,重点)
重要的几句话: (1)一个对象的编译类型和运行类型可以不一致 (2)编译类型在定义对象时,就确定了,不能改变 (3)运行类型是可以变化的. (4)编译类型看定义时=号的左边, 运行类型看=号的右边
例子:Animal animal = new Dog(); [ animal编译类型是Animal,运行类型Dog ] animal = new Cat(); [animal 的运行类型变成了Cat,编译类型仍然是Animal]
package com.hspedu.extend.poly;
public class PolyObject {
public static void main(String[] args) {
//体验对象多态特点
//animal编译类型就是Animal ,运行类型Dog
Animal animal = new Dog();
//因为运行时, 执行到改行时,animal运行类型是Dog,所以cry就是Dog的cry
animal.cry();//Dog中小狗叫
//animaL编译类型Animal, 运行类型就是Cat
animal = new Cat();
animal.cry();//Cat中小猫叫
}
}
package com.hspedu.extend.poly;
public class Animal {
public void cry(){
System.out.println("Animal 中动物叫");
}
}
package com.hspedu.extend.poly;
public class Dog extends Animal {
public void cry(){
System.out.println("Dog中小狗叫");
}
}
package com.hspedu.extend.poly;
public class Cat extends Animal {
public void cry(){
System.out.println("Cat中小猫叫");
}
}
这么理解->
披着羊皮的狼
向上转型代码被我搞丢了找不到了,随便看吧
向上转型调用方法的规则如下: 1可以调用父类中的所有成员(需遵守访问权限) 2但是不能调用子类的特有的成员 因为在编译阶段,能调用哪些成员,是由编译类型来决定的,按照从子类(运行类型)开始查找方法 4最终运行效果看子类(运行类型)的具体实现,即调用方法时,
向下转型 1语法:子类类型 引用名= (子类类型) 父类引用 2只能强转父类的引用,不能强转父类的对象 3要求父类的引用必须指向的是当前目标类型的对象 4可以调用子类类型中所有的成员
属性没有重写之说,属性的值看编译类型:
package com.hspedu.extend.uihy;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Polyhgcv {
public static void main(String[] args) {
//属性没有重写之说,属性的值看编译类型
Base base = new Sub();
System.out.println(base.count);//10
Sub sub = new Sub();
System.out.println(sub.count);//20
}
}
class Base {
int count = 10;
}
class Sub extends Base {
int count = 20;
}
instanceOf比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型