【第五次JAVA课,java语法基础】课件总结
思索
构造函数是对类的成员变量进行初始化,子类拥有父类的可继承的成员变量,若要用到父类的成员变量,就必须对其初始化,所以在子类构造函数运行前要调用父类构造函数对父类成员变量初始化。
绝对不能反过来。因为特性是优先子类的特性,若调用玩父类构造函数后在调用子类构造函数,会有可能导致子类特性被覆盖,从而产生错误。
“类型转换”
class Mammal{} class Dog extends Mammal {} class Cat extends Mammal{} public class TestCast { public static void main(String args[]) { Mammal m; Dog d=new Dog(); Cat c=new Cat(); m=d; //d=m; d=(Dog)m; //d=c; //c=(Cat)m; } }
在使用继承的过程中,不可避免的会遇到需要通过子类来调用父类方法的情况,所以为了解决父类子类拥有相同方法导致前者方法无法被调用的情况,java就必须拥有多态的特性——可以让一个父类变量引用一个子类对象,而编译器会由引用的对象类型来判断如何编译。但这没解决如何使一个子类对象调用父类方法,所以可以用强制类型转换类解决,把一个子类的类型暂时当做父类来处理。
可以使用instanceof运算符判断一个对象是否可以转换为指定的类型。
在实践中理解把握复杂的知识
public class ParentChildTest { public static void main(String[] args) { Parent parent=new Parent(); parent.printValue(); Child child=new Child(); child.printValue(); parent=child; parent.printValue(); parent.myValue++; parent.printValue(); ((Child)parent).myValue++; parent.printValue(); } } class Parent{ public int myValue=100; public void printValue() { System.out.println("Parent.printValue(),myValue="+myValue); } } class Child extends Parent{ public int myValue=200; public void printValue() { System.out.println("Child.printValue(),myValue="+myValue); } }
上面代码运行结果为:
Parent.printValue(),myValue=100
Child.printValue(),myValue=200
Child.printValue(),myValue=200
Child.printValue(),myValue=200
Child.printValue(),myValue=201
前面两个可以理解,后面就不太一样了。第三个是父类的引用装子类的对象拿前朝的剑斩本朝的官,本朝的当然不会让你斩啊,但编译器还是调用子类方法。第四个有点难,如果调试时查看父类的myValue,可以看到这个myValue是101(加了1),但由于方法调用的是子类的方法所以输出仍然为200且隐形参数为Child,成员变量使用父类变量,方法调用却是子类方法,很奇怪,所以第五个是用强制转换的方式,这样变量也是子类的变量了。关于这种奇怪的现象会在“多态”里总结。
“多态”
不想多说,直接总结:
一、使用父类类型的引用指向子类的对象;
二、该引用只能调用父类中定义的方法和变量;
三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
这样多态是通过父类和继承父类并覆盖父类中同一方法的几个不同子类、接口和实现接口并覆盖接口中同一方法的几不同的类体现的。通过超类对象引用变量引用子类对象但对消息的反应是子类的方式来实现多态。
java为了实现多态性采用了后绑定(动态绑定)的形式。
程序绑定的概念:
绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来。对java来说,绑定分为静态绑定和动态绑定;或者叫做前期绑定和后期绑定
静态绑定:
在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现。例如:C。
针对java简单的可以理解为程序编译期的绑定;这里特别说明一点,java当中的方法只有final,static,private和构造方法是前期绑定
动态绑定:
后期绑定:在运行时根据具体对象的类型进行绑定。
若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对后期绑定的实现方法是有所区别的。但我们至少可以这样认为:它们都要在对象中安插某些特殊类型的信息。动态绑定的过程:
虚拟机提取对象的实际类型的方法表;
虚拟机搜索方法签名;
调用方法。——https://www.xuebuyuan.com/2965081.html
在java中,几乎所有的方法都是后期绑定的,在运行时动态绑定方法属于子类还是基类。但是也有特殊,针对static方法和final方法由于不能被继承,因此在编译时就可以确定他们的值,他们是属于前期绑定的。特别说明的一点是,private声明的方法和成员变量不能被子类继承,所有的private方法都被隐式的指定为final的(由此我们也可以知道:将方法声明为final类型的一是为了防止方法被覆盖,二是为了有效的关闭java中的动态绑定)。java中的后期绑定是有JVM来实现的,我们不用去显式的声明它,而C++则不同,必须明确的声明某个方法具备后期绑定。