java面向对象——包+继承+多态(一)-1
https://developer.aliyun.com/article/1503989
protected关键字(重点)
1 在同一个类中
public class time { protected int val = 99; public static void main(String[] args) { time time=new time(); System.out.println(time.val); } }
此时代码能够正常执行
2 在同一个包中在不同的类
可以看到test与time是在同一个包底下的不同的类,test是可以访问到protected修饰的val
3 不同包底下的子类
在不同包底下,我们要在子类中导入父类,在进行继承,由于是父子类关系,我们要用super关键字对父类中的实例进行访问(super关键字是不能出现在静态方法中的,因为super是对父类对象的引用,是依赖于对象的,而静态方法是属于类的,不依赖于对象)
4 不同包底下的非子类
很明显这是不能进行访问的
访问权限的总结
结合之前我们前面所讲过的public,private,以及包访问权限,现在所学的protected,我们进行一个总结
private:只能在类的内部使用,外部不能进行访问
public:类的外部与内部,同一个包或者不同包下都能进行访问
default(包访问权限):只能在同一个包中进行访问
protected:同一个包,同一个类,不同包的父子类之间都可以进行访问,在父子类中要利用super关键字进行访问,不同包的非子类是不能进行访问的
更复杂的继承关系:(了解)
我们刚才所例举的动物中,对于猫也分为很多种,比如国内的猫种以及国外的猫种,国内的猫种又可以分为那几种等还可以继续细分下去,这种继承关系必须要有逻辑上的联系,不能仅仅为了继承而继承。一般而言我们对于这种复杂的继承关系,一般最好不要超过3层
多态:
向上转型(重点)
具体可以看下下列代码
bird bird=new bird(“heihei”,20);
在上面的例子中我们我们知道bird是bird的一个引用,它可以写成下列这种形式
bird bird=new bird(“heihei”,20);
animal bird2 = bird;
//或者写成这个样子
animal bird2 = new bird(“heihei”,20);
此时这种写法就被称作向上转型,也就是父类的引用去引用了子类的对象。
向上转型发生的时机:
1 直接赋值法
这个方法其实就是我们刚才在介绍向上转型的时候所介绍的那个例子。
2 作为返回值
public static void main(String[] args) { animal animal=func(); } public static animal func(){ bird bird=new bird("gas",39); return bird; }
3 方法的参数
public static void main(String[] args) { bird bird =new bird("aio",39); func(bird); } public static void func(animal animal){ animal.eat(); }
动态绑定(重点)
发生的条件:
1 发生了向上转型(父类引用引用了子类的对象)
2 通过父类的引用,调用父类与子类同名的覆盖方法
动态绑定也被叫做运行时多态(至于具体什么是多态,在下文会具体介绍),也就是在运行时才确定调用的是子类的eat方法
class animal{ public String name; public int age; public void eat(){ System.out.println(name+"eat()"+age); } public animal(String name,int age){ this.name=name; this.age=age; } } class bird extends animal{ public bird(String name,int age){ super(name,age); } @Override public void eat() { System.out.println(name+"吃"); } public void fly(){ System.out.println("fly()"); } } public class blos { public static void main(String[] args) { animal animal=new bird("hsd",34); animal.eat(); } }
我们首先可以从main函数入手,可以看到,animal调用用eat方法,可以看到并没有执行父类中的eat方法,而是调用了子类中同名且参数相同,返回值相同的eat方法,此时我们就说发生了动态绑定,而eat方法也被称作覆盖方法,在这个过程我们就说eat发生了重写,并且可以用@override进行标注
静态绑定:
与动态绑定不同,静态绑定在编译时就确定调用了子类的eat方法
public class blos { public static void main(String[] args) { duck duck=new duck(); duck.fun("haha"); } } class duck{ public void fun(){ System.out.println("无参"); } public void fun(String name){ System.out.println("一个参数"); } public void fun(String name,int age){ System.out.println("两个参数"); } }
当duck调用fun方法时,给fun传了几个参数,就对应调用那个方法,这个时候我们就说发生了静态绑定,可以知道静态绑定则需要发生在重载的情况下,而动态绑定则需要先发生重写。
重写的注意事项
1 被final修饰的方法不能发生重写
2 被private修饰的方法不能重写
3 被static修饰的方法不能重写
4 子类方法的修饰限定符要大于父类的修饰限定符
重写与重载的区别
1 重写的返回值要一样(这里有个特殊情况,就是可以是协变类型也是可以的),重载是与返回值无关的
2 重写与重载的方法名都要相同的
3 重写的方法参数要一致,重载的方法参数要不同(这里的方法参数包括含参种类以及含参的个数)
结语:
在后面的一篇文章中,我们会继续详细的讲解什么是多态,什么是抽象类,什么是接口。希望本篇文章能够对于你有所帮助!