目录
1.继承
1.1什么是是继承
Java允许一个类通过extends与另一个类建立父子关系,这就是继承。
1.2继承的格式
子类 extends 父类
public class Consultant extends People{
private int number;
}
1.3继承的核心优点
提高代码的复用性,多个子类的相同代码可以放在父类中,增强了类的扩展性。
1.4继承的设计规范
子类共用属性和行为放在父类,子类独有属性和行为放在子类自己那里。子类能继承父类的成员(成员变量、成员方法),但无法直接访问父类的私有成员
1.5继承的内存原理
子类对象实际上是由子父类这两张设计图共同创建出来的。
1.6继承的三大特点
【1】Java是单继承模式:一个类只能继承一个直接父类。
【2】Java不支持多继承、但是支持多层继承。
public class Test01 {
public static void main(String[] args) {
ZI z = new ZI();
System.out.println(z.zichan);
}
}
//定义了父类
class XTBB{
}
class WSS{}
//1:Java中类的继承是单继承模式 一个类只能继承一个直接父类
// 不支持多继承
class DTEZ extends XTBB{}
//2:Java支持多层继承
class YE{
String zichan="北京前门一套四合院";
}
class FU extends YE{}
class ZI extends FU{}
【3】Java中所有的类都是Object类的子类。
public class Test02 {
// 所有的类直接或间接继承Object,Object定义的方法 所有的类都有!!
public static void main(String[] args) {
People people = new People();
people.toString();//people 类中没有定义 toString()方法
// 但是能够访问? 因为people 默认继承了Object 不写继承就是默认继承Object
Student stu = new Student();
stu.toString();// Student 类中没有定义 toString()方法
// People 类中没有定义 toString()方法
//原因是java支持多层继承 所以 Student 间接继承了Object
}
}
class People{//不写继承 直接继承Object
}
class Student extends People{
}
1.7继承后变量与方法的访问特点
1.7.1遵循就近原则
先子类局部范围找,然后子类成员范围找,最后父类成员范围找,如果父类范围还没有找到则报错。
public class Test03 {
public static void main(String[] args) {
//目标 继承后 子类访问的特点 就近原则
// this. 访问的本类的成员
// super. 访问的父类的成员
Z z = new Z();
z.show();
}
}
class F{
String name = "父的Name";
public void run(){
System.out.println("父run");
}
}
class Z extends F{
String name = "子的Name";
public void show(){
String name = "show方法的name";
System.out.println(name);//就近原则访问局部变量
System.out.println(this.name);//就想访问 子类成员位置name怎么办
System.out.println(super.name);//就想访问 父类成员位置name怎么办?
this.run();//调用本类方法 但是this可以省略
super.run();//调用父类方法
}
public void run(){
System.out.println("子run");
}
}
1.7.2this关键字
this.子类自己的成员变量
1.7.3子类方法如何访问父类成员
super.父类成员变量/父类成员方法
1.8继承后方法重写
1.8.1概念
当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
1.8.2重写后想调用父类方法怎么办
先使用super关键字调用父类同名方法,再继续编写子类独有的方法。
1.8.3@override
重写方法建议加上一个重写校验注解:@Override。要求必须是正确重写的才不报错。这样方法的可读性好。
public class OverrideTest {
public static void main(String[] args) {
Cat c = new Cat();
c.load();
c.sleep();
}
}
class Animal{
public void load(){
System.out.println("动物都会叫");
}
public void sleep(){
System.out.println("安详的睡");
}
}
class Cat extends Animal{
@Override //注解 表示当前这个方法 是重写的方法
public void load() {
System.out.println("喵~~喵~~~喵~~喵喵喵~");
}
// @Override 如果不是重写方法就报错
public void play(){
System.out.println("猫玩毛线~~");
}
}
1.8.4重写的要求
【1】子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限( public > protected > 缺省 )。
【2】重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
【3】私有方法、静态方法不能被重写,如果重写会报错的。
1.9继承后子类构造器
1.9.1特点
子类的全部构造器默认都会先访问父类的无参数构造器,再执行自己的构造器
1.9.2为什么
先有爸爸才有儿子。 先调用它爸爸的构造器初始化父类的数据,再调用自己的构造器初始化自己的数据。
1.9.3代码层面
默认子类构造器的第一行都有一个super(), 访问父类的无参数构造器,写不写都有
1.9.4继承后子类构造器访问父类有参构造器
super(...)调用父类有参数构造器,初始化继承自父类的数据。
/*
在开发中的做法
父类有属性
那么我们就要生成父类的有参构造和无参构造
子类
需要写子类的无参构造 子类的有参构造
子类有参构造
参数
自己类中属性需要的参数
父类中属性需要的参数
里面内容
将父类构造需要的参数 传递父类有参构造--调用父类有参构造
将子类自己需要参数 传递 自己的属性
*/
public class People {
private String name;//外界无法访问
private int age;
//父类无参构造
public People() {
System.out.println("父类无参构造");
}
//父类有参构造
public People(String name, int age) {
this.name = name;
this.age = age;
System.out.println("父类有参构造");
}
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;
}
}
public class Teacher extends People {
private String skill;//技能
//子类无参构造
public Teacher() {
System.out.println("子类的无参构造");
}
//子类有参构造 可以利用 快捷键
public Teacher(String name, int age, String skill) {
super(name, age);//将父类需要的参数进行传递
this.skill = skill;//接收自己属性需要的参数
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
public class Test {
/*
构造--创建对象的时候执行 用来完成成员变量的初始化!!!!
字类构造器特点
子类的全部构造,都会先调用父类的构造器,再执行自己的。
默认语句是 super()表示调用父类的无参构造器
如果父类没有无参构造,必须在子类构造器第一行手写super(...) 调用父类的指定的有参构造
*/
public static void main(String[] args) {
Teacher t= new Teacher("游戏仔",17,"原神启动,王者农药,斗地主");
System.out.println(t.getName()+"---"+t.getAge()+"---"+t.getSkill());
}
}
2.多态
2.1什么是多态
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
//这是本态
Lv lv = new Lv();
//这是多态
Animal a = new Lv();
2.2多态的使用前提
【1】必须有继承或者实现关系
【2】父类类型的变量指向子类类型的对象
【3】存在方法重写
2.3多态的格式
父类类型 变量名称 = new 子类构造器;
Animal a = new Lv();
2.4多态的调用方式
2.4.1调用方法
编译看左边,运行看右边
2.4.2调用变量
编译看左边,运行也看左边(注意)
2.5多态的优势
【1】在多态形式下,右边对象是解耦合的,更便于扩展和维护。
【2】定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利。
2.6使用多态需要注意的问题
多态下不能直接访问子类独有功能
public class Animal {
public void Load(){
System.out.println("动物叫");
}
}
public class Cat extends Animal{
@Override
public void Load(){
System.out.println("我们一起学小卢");
}
public void playMaoXian(){
System.out.println("玩得很开心");
}
}
public class Lv extends Animal{
@Override
public void Load(){
System.out.println("驴叫");
}
public void LaMo(){
System.out.println("懒驴上磨屎尿多");
}
}
public class Test {
public static void main(String[] args) {
Animal animal=new Lv();
// animal.LaMo();报错,父类中没有LaMo方法
}
}
2.7多态的类型转换
2.7.1自动类型转换
从子类到父类
2.7.2强制类型转换
【1】从父类到子类
【2】Java规定,有继承/实现关系的类就可以强制转换,编译阶段不会报错。但是运行时可能出现类型转换异常
【3】Java建议在进行强制转换之前先通过instanceof判断真实数据类型,再强转
【4】强转成子类对象后,就可以调用子类的独有功能了
public class Test02 {
public static void main(String[] args) {
Animal animal=new Cat();
animal.Load();;
if (animal instanceof Cat){
Cat cat=(Cat) animal;
cat.playMaoXian();
}
}
}