java继承的几个特性
1.基类中的方法使用private修饰,就代表该方法仅属于该类,不会被子类继承,调用和重写。
2.基类方法使用final修饰代表此方法不会被子类所重写。
3.使用@Override注解表示重写父类方法,来区分重载父类方法。
4.父类中的变量通常设为private,操作变量的方法设为protected,以此来控制变量的访问权限问题。
5.向上转型
class Amphibian {
public void say() {
System.out.println("Amphibian said");
}
public void done(){
System.out.println("Amphibian done");
}
}
class Frog2 extends Amphibian {
@Override
public void say() {
System.out.println("Frog2 said");
}
@Override
public void done() {
System.out.println("Frog2 done");
}
public void ownMethod() {
System.out.println("Frog2 OwnMethod");
}
public static void main(String[] args){
Amphibian amphibian = new Frog2();
amphibian.say();
amphibian.done();
//amphibian.ownMethod();
}
}
运行main方法,控制台输出:
Frog2 said
Frog2 done
结论:
- 编译器禁止amphibian执行ownMethod()方法,因为Frog2已经向上转型为Amphibian对象,Frog2自身新添的变量,方法都被丢弃。
- 但是Frog2对象重写Amphibian类中方法的方法却可以得到保留。
6.继承中变量的初始化
class Insect {
private int i = 11;
protected int j;
public static int getStaticNumber(String string) {
System.out.println(string+" getStaticNumber");
return 33;
}
private static int k = getStaticNumber("Insect k");
public Insect() {
System.out.println("Insect constructor");
System.out.println("i : "+i+" j :"+j+" k :"+k);
j=22;
}
}
class Mosquito extends Insect{
private int i = getStaticNumber("Mosquito i");
private static int k = getStaticNumber("Mosquito k");
Mosquito() {
System.out.println("Mosquito constructor");
System.out.println("i : "+i+" j :"+j+" k :"+k);
}
public static void main(String[] args){
//执行此方法时 编译器会根据继承类的顺序,从上往下初始化static域
System.out.println("==================");
//创建Mosquito对象时 先初始化基类Insect类的变量,调用其构造器。随后再初始化子类Mosquito类的变量,调用其构造器
//Mosquito mosquito = new Mosquito();
}
}
执行main方法,控制台输出:
Insect k getStaticNumber
Mosquito k getStaticNumber
==================
结论:
当子类中的static变量或方法被访问时,会按照根父类往下的顺序初始化static变量和加载static代码块。包括调用构造器(构造器也是static方法,只不过隐藏起来了)。
没有实例化对象时static的加载顺序是这样的,那么如果实例化对象了,static变量,代码块与对象内的变量,代码块之间的加载顺序会发生什么样的变化呢?更改main方法中的代码如下:
public static void main(String[] args){
Mosquito mosquito = new Mosquito();
}
执行后输出如下:
Insect k getStaticNumber
Mosquito k getStaticNumber
Insect constructor
i : 11 j :0 k :33
Mosquito i getStaticNumber
Mosquito constructor
i : 33 j :22 k :33
结论:
由此可以看出,在子类对象被初次实例化时会优先按照以根基类开头的顺序,自此向下加载static变量和代码块。加载完static后再按照从根基类开始自上而下的顺序,以类为单位初始化类中的变量,调用类中的构造器,直至到当前子类为止。
7.基类有两个方法分别为m1,m2.并且m1调用m2。那么当一个导出类重写m2。创建两个个导出类对象,一个保持不变,另一个向上转型为基类,均调用方法m1。这时候会发生什么样的变化?
public class Exercise10 {
@Test
public void exercise10() {
Rice rice = new Rice();
Food food = new Rice();
rice.eat();
food.eat();
}
}
class Food {
void eat() {
System.out.println("eat "+buy());
}
String buy() {
return "Food";
}
}
class Rice extends Food {
@Override
String buy() {
return "Rice";
}
}
执行exercise10方法,控制台输出:
eat Rice
eat Rice
结论:
基类中方法调用会优先调用被重写的方法
8.有三个类分别是A,B,C。B继承A,C继承B。代码如下:
public class Personal {
@Test
public void test() {
A a = new A();
B b = new B();
C c = new C();
D d = new D();
a.walk();
b.walk();
c.walk();
d.walk();
d.fly();
}
}
class A{
void walk() {
System.out.println("A---walk");
}
void fly() {
System.out.println("A---fly");
}
}
class B extends A {
@Override
void walk() {
System.out.println("B---walk");
}
}
class C extends B {
}
class D extends C {
}
问题:
- 此时c.walk();d.walk();将执行的是类A还是类B中的walk()方法?
- c.fly();方法的执行说明了什么?
控制台输出:
A---walk
B---walk
B---walk
B---walk
A---fly
结论:
在多继承的情况下,子类调用没有重写的方法会先从自己的基类中查找该重写的方法,若有则调用该方法,若没有找到,则会再从此基类的基类中查找该重写的方法,有则调用,没有则继续向上查找(如c.walk();d.walk();的调用),一直到找到某一基类中重写的该方法或者执行该方法在根基类中的根方法。(如fly的调用)。这也从某一方面说明了java调用方法时优先调用重写的方法。
stay hungry stay foolish stay young

浙公网安备 33010602011771号