1、构造函数和析构函数
- 重载构造函数是一个主要的技术,可以允许多种方式初始化一个类
- 构造函数是没有返回值的
- 构造函数代码的执行是从它最老的祖先类开始向下执行调用
1-1、派生类和父类构造函数
- 派生类被构造时一定会先调用父类的构造函数
- 可以选择调用哪一个构造函数,但不能都调用
- 派生类不指定,就会调用无参的构造函数
显式调用父类构造函数必须在派生类构造函数的第一句
普通方法也可以和类名相同,和构造方法的唯一区分是构造函数没有返回值
2、多态的概念
封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块,他们的目的都是代码重用。多态的目的是接口重用。【继承的存在很大程度上是作为多态的基础】
多态性可以简单地概括为,一个接口,多种方法。在程序运行的过程中才决定调用那个函数。多态性是面向对象编程领域的核心概念
多态性是允许将父对象设置成为和它的一个或多个子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。(即允许将子类类型的指针赋值给父类类型的指针)
2-1、重载和重写的区别
- 重载:静态 早绑定【重载是指允许存在多个同名函数,而这些函数的参数表不同】
- 重写(覆盖):动态 晚绑定【覆盖是指子类重新定义父类的虚函数的做法】
Tips:重写遵循三同一小一大原则:
- 三同:同名、同参、同返回类型
- 一小:子类抛出的异常小于父类抛出的异常
- 一大:子类修饰符大于等于父类修饰符
重载并不属于面向对象编程,是一种语言特性;正真和多态有关的是重写
3、继承与接口
3-1、接口:
- 广义:凡是一个类提供给外部使用的部分都可以被称为接口
- 狭义:指特定的函数集合,用interface声明,表示一个方法的集合被命名为接口
广义接口的正真意义是在类的继承中体现多态的功能;接口实际上是结合着多态而来的,它的最大任务是实现多态而多态有事面向对象最精华的部分。
成员函数被重载的特征:
- 相同的范围(在同一个类中)
- 函数名相同
- 参数不同
- virtual关键字可有可无
重写(覆盖)的特征:
- 不同的范围(派生类和基类)
- 函数名相同
- 参数相同
- 基类函数必须由virtual关键字
3-2、继承
继承是指子类对象可以使用仅对父类的对象有效的方法或属性,它使得这些方法和属性就好像是子类自己定义的一样
- 在继承结构中,父类的内部细节对于子类是可见的,所以通过继承的代码复用是一种“白盒式代码复用”
- 组合是指通过对现有代码进行拼装(组合)产生新的更复杂的功能,因为在对象之间,各自的内部细节是不可见的,所以组合是一种“黑盒式代码复用”
例子:
输出为:Father Father 如果没有static修饰 则输出为Father 和Child
package T617;
/**
* Created by Promacanthus on 2017/6/17.
*/
public class T1 {
public static void main(String[] args) {
Father father = new Father();
Father child = new Child();//此处child声明为一个Father的对象
System.out.println(father.getName());
System.out.println(child.getName());//调用Father的类方法
}
}
class Father{
public static String getName(){
return "Father";
}
}
class Child extends Father{
public static String getName(){
return "Child";
}
}
输出为Class B Class B Class A
package T617;
/**
* Created by Promacanthus on 2017/6/17.
*/
public class T2 {
public static void main(String[] args) {
classB ob = new classB();//此处ob实例化为一个classB类型的对象
ob.printValue();
classA as = (classA) ob;//强制类型转换后本质依然是classB类型的对象
as.printValue();//调用classB的方法
as = new classA();
as.printValue();
}
}
class classA {
public void printValue() {
System.out.print("Class A ");
}
}
class classB extends classA {
public void printValue(){
System.out.print("Class B ");
}
}
不能被继承的情况:
- 匿名内部类:是没有名字的内部类,不能被继承
- final修饰的类:不能被继承
3-3、super & this 关键字
super关键字指向超类的构造函数,用来引用超类中的变量和方法
call to super()must be first statement in constructor body
子类的构造函数如果要引用super,必须把super放在函数的首位
在Java中,有事会遇到子类中的成员变量或方法与超类中的成员变量或方法同名的情况,因为子类中的成员变量或方法名优先级高,所以子类中的同名成员变量或方法就隐藏了超类的成员变量或方法,但是如果需要使用超类中的这个成员变量或方法,就需要使用super关键字,具体实例如下:
输出为beijing China
package T617;
/**
* Created by Promacanthus on 2017/6/17.
*/
public class T3 {
public static void main(String[] args) {
new City().value();
}
}
class Country {
String name;
void value() {
name = "China";
}
}
class City extends Country {
String name;
void value(){
name = "Beijing";
super.value();
System.out.println(name);
System.out.println(super.name);
}
}
为了在子类中引用超类中的成员变量和方法,在代码中使用,super、super.name和super.value()
如果需要使用超类的构造函数则调用super(参数列表)
this关键字使用在一个成员函数的内部,指向当前对象(即调用当前正在执行方法的那个对象)
在参数或局部变量名与类成员变量名相同时,由于参数或局部变量的优先级高,这样在方法体中参数名或局部变量将隐藏同名的成员变量,为了指明成员变量,必须使用this显式地指明当前对象
当this在构造函数的第一句,形如this(参数列表),这个构造函数就会调用同一个类的另一个相对的构造函数
Tips:在构造子类对象时,首先调用父类构造函数,如果在调用父类函数时调用了被子类重写的函数,那么此时调用的是子类重写后的函数而不是父类的与该函数同名的函数。因为子类中同名的成员变量和函数的优先级高。
3-4、 抽象类与接口
抽象类注意点:
- 抽象类只能作为基类,可以有构造方法,但是不能直接被实例化(即不能使用new操作符)
- 抽象类如果含义抽象的变量或值,要么是null类型,要么包含了对非抽象类的实例的引用
- 抽象类运行包含抽象成员,但这不是必须的,抽象类中可以有非抽象方法
- 抽象类不能是final的
- 继承一个抽象类,必须覆盖(重写)所以继承而来的抽象成员和抽象方法
- 抽象类可以被抽象类继承,还是抽象的(只支持单继承)
- 抽象类允许被声明
接口的注意点:
public interface A {
public final static int a = 0;
public abstract b();
}
- 接口用于描述系统对外提供的所有服务,因此成员常量和方法必须是public的
- 接口仅描述系统做了什么,因此接口中的方法都是抽象(abstract)的
- 接口不涉及任何具体实例相关细节,因此没有构造方法,不能被实例化,没有实例变量,只有静态(static)变量
- 接口中的变量是所有实现类共有的,肯定是不变的,所有是final类型(即常量)
- 接口不可以定义变量