继承
- 继承性严格来讲就是指扩充一个类已有的功能。
- 子类实际上是将父类定义的更加具体化的一种手段。
继承的限制
- Java不允许多重继承,但是允许多层继承。(但是也别太多层)
- 对于所有的私有操作属于隐式继承,而所有的非私有操作属于显示继承。
- 在子类对象构造前一定会先调用父类的构造(默认使用无参构造),以保证父类的对象先实例化,子类对象后实例化。
当父类中有无参构造时 super() 语句加与不加无区别,但是如果父类中没有无参构造方法,则必须明确使用 super() 调用父类指定参数的构造方法。
一个简单Java类一定要保留一个无参构造方法
覆写
继承性的主要特征是子类可以根据父类已有的功能进行功能的扩展,但是在子类定义属性或方法时,有可能出现定义的属性或方法与父类同名的情况,这样的操作就称为覆写。
- 当子类定义了和父类的方法名称、返回值类型、,参数类型以及个数完全相同的方法时,就称为方法的覆写
class A{
public void fun(){
System.out.println("A类中的fun()方法。");
}
}
class B extends A{
public void fun(){
System.out.println("B类中的fun()方法。");
}
}
public class TestDemo {
public static void main(String args[]){
B b = new B();
b.fun();
}
}
-
覆写代码执行结果的分析要素
· 观察实例化的是哪个类
· 观察这个实例化的类里面调用的方法是否已经被覆写过,如果没被覆写则调用父类。
这一原则直接与后续的多态息息相关! -
什么时候会用到方法的覆写呢?
如果发现父类中的方法名称功能不足,但是又必须使用这个方法的名称时,就需要采用覆写实现。被子类所覆写的方法不能拥有比父类更严格的访问控制权限。
-
NO 区别 重载 覆写 1 英文单词 Overloading Override 2 发生范围 发生在一个类里面 发生在继承关系中 3 定义 方法名称相同、参数的类型及个数不同 方法名称、参数的类型、个数相同、返回值相同 4 权限 没有权限的限制 被覆写的方法不能拥有比父类更为严格的控制权限
一旦有了覆写之后,默认情况下子类所调用的一定是被覆写过的方法,为了能够明确的由子类调用父类中已经被覆写过的方法,可以使用super.方法() 来进行访问。
- 属性的覆盖
如果子类定义了和父类完全相同的属性名称时,就称为属性的覆盖。
class A{
String info = "Hello"; //定义属性,暂不封装
}
class B extends A{
int info = 100; //名称相同,发生属性覆盖
public void print(){
System.out.println(super.info);
System.out.println(this.info);
}
}
public class TestDemo {
public static void main(String args[]){
B b = new B();
b.print();
}
}
属性覆盖在实际开发中没有意义,因为属性都需要进行封装。
final关键字
在Java中final称为终接器,在Java里面可以使用final定义类、方法和属性。
- 使用final定义的类不能再由子类,即:任何类都不能继承以final声明的父类。
例如 : String 是final定义的类,所以String类不允许被继承。
一般用在系统架构的代码开发中。 - 使用final定义的方法不能被覆写。
- 使用final定义的变量就成为了常量,常量必须在定义的时候设置好内容,并且不能修改。
代码中定义常量的最大意义在于 : 使用常量可以利用字符床(常量名称)来更直观的描述数据。
final double GOOD = 100.0; // GOOD 就代表了 100.0 这个数据
在定义常量中还有一个更为重要的概念------全局常量,所谓的全局常量就是利用了“public” “static” “final” 3个关键字联合定义的常量。 例如:
public static final String MSG = "YOOTK";
多态
多态在开发中可以体现在以下两个方面:
- 方法的多态性:重载和覆写
|- 重载:同一个方法名称,根据不同的参数类型及个数完成不同的功能
|- 覆写:同一个方法名称,根据实例化的子类对象不同完成不同的功能 - 对象的多态性:父子类对象的转换
|-向上转型:子类对象变为父类对象
|-向下转型:父类对象变为子类对象
对象的多态性是和方法覆写紧密的联系在一起的。
向上转型:
下面是代码演示:
class A{
public void fun(){
System.out.println("A类中的fun()方法。");
}
}
class B extends A{
public void fun(){
System.out.println("B类中的fun()方法。");
}
}
public class TestDemo {
public static void main(String args[]){
B b = new B();
b.fun();
}
}
执行结果为:
对以上程序的主方法进行修改:
public class TestDemo {
public static void main(String args[]){
A a= new B();
a.fun();
}
执行结果为:
执行结果与之前方法覆写的执行原则是完全一样的。
不要看类名称,而要看实例化对象的类。实际上通过以上程序可知,整个过程中不必关心对象的声明类型,关键在于实例化新对象时所调用的是哪个子类的构造。
如果方法被子类所覆写,调用的就是被覆写过的方法,否则就调用父类中定义的方法。
向下转型:
向下转型必须在向上转型的基础之上完成,否则会出现“ClassCastException”错误。
A a= new B();、
B b = (B)a;
对象多态的意义难道就是为了无聊的转型吗??
NO
在实际的开发中,对象向上转型的主要意义在于参数的统一,也是最为主要的用法。而对象的向下转型指的是调用子类的个性化操作的方法。
例:
class A{
public void fun(){
System.out.println("A类中的fun()方法。");
}
}
class B extends A{
public void fun(){
System.out.println("B类中的fun()方法。");
}
}
class C extends A{
public void fun(){
System.out.println("C类中的fun()方法。");
}
}
public class TestDemo {
public static void main(String args[]){
print(new B()); // 对象向上转型, 等价于:A a = new B();
print(new C()); // 对象向上转型, 等价于:A a = new C();
}
public static void print(A a){
a.fun();
}
}