前言
紧接着上篇 解密继承和多态(上)~
欢迎关注个人主页:逸狼
创造不易,可以点点赞吗~
如有错误,欢迎指出~
目录
前言
protected关键字
在同一包下同一类可以访问
代码理解
在同一包下不同类可以访问
代码理解
在不同包下的子类可以访问
代码理解
再谈访问权限问题
final关键字
final修饰变量
final修饰类
组合
代码举例
多态
动态绑定
发生条件
向上转型
代码理解
直接赋值
方法传参
作为返回值
向下转型
父类和子类 方法的重写
要求
注意
@Override
与代码重载的区别
代码理解
protected关键字
接下来我们谈谈protected关键字
在同一包下同一类可以访问
代码理解
如下的代码,用protected修饰c,在同一个包demo1下的同一类Test1下,func方法可以成功访问c
package demo1;public class Test1 {public int a;protected int c=99;public void func(){System.out.println(c);}
}
在同一包下不同类可以访问
在同一个包demo1下面再建一个类TestProtected1
代码理解
调用Test1产生实例化对象test1,可以通过对象test1访问Test1类下的成员c
package demo1;public class TestProtected1 {public static void main(String[] args) {Test1 test1=new Test1();System.out.println(test1.c);}
}
在不同包下的子类可以访问
被protected修饰,不管同不同包,只要是子类就都可以 通过super 访问
代码理解
新创建另外一个包demo2,再在下面创建一个类Test2
在Test2类中可以通过super成功访问不同包demo2下Test1类中被protected修饰的c
前提:被继承的类是用public修饰的,在代码中体现就是Test被public修饰了才行
(其中类的权限 只有 两种:一个是用public修饰的,另一个是不用public修饰的)
package demo2;import demo1.Test1;//要先导包
//继承Test1
public class Test2 extends Test1 {public void test(){System.out.println(super.c);}public static void main(String[] args) {
// System.out.println(super.c);//会报错,因为main方法中有static修饰,不能用super}
}
再谈访问权限问题
在上一篇我们讲解了private和public的范围,他们是访问权限的两个极端
- private只能在同一包的同一类下访问
- public是 不管是否同包 不管是否同类 都能被访问
我们可以用下图总结
这里的default不是关键字,表示的是在成员变量前不加任何public、private等关键字。
Java不支持多继承
final关键字
final修饰变量
final int SIZE=10;表示SIZE变成常量(不能被修改)
final修饰类
final用于控制继承,被final修饰的类 表示 当前类不可以被继承,此时这个类称为密封类。
组合
组合是代码层面的一种写法,是has-a的关系(例如 汽车中的零部件组合成了一辆汽车),仅仅是将一个类的示例作为另一个类的成员变量。
代码举例
老师类和学生类组合成了学校类
class Teacher{}
class Student{}
class School{private Teacher[] teachers;private Student[] students;
}
多态
同一件事在不同的对象上产生的效果是不一样的
代码理解
当Animal引用的对象不一样(animal1和animal2),调用eat方法,表现出的行为不一样时(Animal1吃狗粮,Animal2吃鸟粮),这就叫做 多态。
class Animal{public String name;public int age;public void eat(){System.out.println(this.name+" 正在吃~");}public Animal(String name, int age) {this.name = name;this.age = age;}
}
class Dog extends Animal{//Alt键 加上 Enter键快速生成子类构造方法public Dog(String name, int age) {super(name, age);}@Override//注解 用于帮助检查方法重写是否正确,若重写的方法有问题,他就会报错public void eat(){System.out.println(this.name+"正在吃狗粮~");//与父类的eat形成 方法的重写}public void bark(){System.out.println(this.name+" 正在汪汪汪~");}
}
class Bird extends Animal{public Bird(String name, int age) {super(name, age);}public void qiqi(){System.out.println(this.name+" 正在吱吱吱~");}public void eat(){System.out.println(this.name+"正在吃鸟粮~");//与父类的eat形成 方法的重写}
}public class Test {public static void func(Animal animal){}public static Animal func2(){return new Dog("旺财",3);}public static void main(String[] args) {
/* Dog dog=new Dog();Animal animal=dog;//向上转型*/Animal animal1=new Dog("旺财",3);//向上转型animal1.eat();Animal animal2=new Bird("小蜂",1);animal2.eat();//animal1.bark();//会报错,因为Animal中没有bark方法,通过父类引用只能访问父类自己的有的}
}
实现多态的前提是动态绑定~
动态绑定
编译的是父类方法,但是调用的是子类方法
代码理解
编译用的父类Animal中的eat方法,但结果是调用的是子类eat方法
Animal animal1=new Dog("旺财",3);//向上转型animal1.eat();
代码结果
发生条件
父类引用子类对象【向上转型】
通过父类引用 调用重写的方法【方法的重写】
向上转型
实际就是创建一个子类对象,将其当成父类对象来使用。
语法格式:父类类型 对象名 = new 子类类型()
- 优点:让代码实现更简单灵活。
- 缺陷:不能调用到子类特有的方法。
发生向上转型的时机有三种,通过以下代码加以理解
代码理解
直接赋值
public static void main(String[] args) {
/* Dog dog=new Dog();Animal animal=dog;//向上转型*/Animal animal1=new Dog("旺财",3);//向上转型}
方法传参
public static void func(Animal animal){}
作为返回值
public static Animal func2(){return new Dog("旺财",3);}
向下转型
Animal animal1=new Dog("旺财",3);//向上转型Dog dog=(Dog)animal1;//向下转型 要将对象animal1强转成Dog类,否则会报错//因为 不是所有的动物都是狗
父类和子类 方法的重写
重写又叫覆盖、覆写
要求
- 方法名相同
- 方法的参数列表相同(个数、顺序、类型)
- 方法返回值相同
注意
- 静态方法 不能 被重写
- 被private修饰的 不能 被重写
- 被final修饰的 不能 被重写
- 如果方法被重写,子类的访问权限要 大于等于 父类的权限
@Override
修饰该方法,说明该方法是重写的
与代码重载的区别
代码理解
//父类Animal中的eat方法public void eat(){System.out.println(this.name+" 正在吃~");}//子类Dog中的eat方法public void eat(){System.out.println(this.name+"正在吃狗粮~");//与父类的eat形成 方法的重写}