面向对象程序设计(OOP)是当今主流的程序设计范型,与C语言等面向过程的语言不同的是,Java是完全面向对象的,我们必须熟悉面向对象才能够编写好一个Java程序。
面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及行为,以解决这些对象面临的一些实际问题,面向对象设计实质上就是对现实世界的对象进行建模操作。
例如,如果我们需要制造一把椅子,面向对象首先关注的是这个椅子应该多高,能够承受多少重量,具有什么样的外部特征。而面向过程首先关注的是我们有哪些工具,怎么样去做一把椅子。
类与对象
类是对一类事物的统称,是对对象的一种抽象。类中定义了对象的具体属性和行为(方法),是封装对象的属性和行为的载体,反过来说具有相同属性和行为的一类实体被称为类。
对象是类实例化出来的一个实例,每一个对象都有主要的三个特性:对象的行为、对象的状态和对象的唯一标识。
对象的行为也就是对象的方法,表示我们可以对对象施加哪些方法;对象的状态就是指,我们对对象施加方法后,对象会如何响应;并且每个对象都有唯一的标识,我们可以区分同一个类的不同对象。
封装
封装是面向对象编程的核心思想。
将对象的属性和行为封装起来,其载体就是类,类通常向用户隐藏其实现的细节,这就是封装的思想。例如我们使用电视,只需要开启电源,使用遥控器控制电视,不需要知道电视机内部是怎么实现的。
继承
类与类之间,一般有三种关系:依赖(“use-a”)、聚合(“has-a”)和继承(“is-a”)。
继承主要是利用特定对象之间的共有属性和方法,从一个包含其他对象共有属性和行为的类派生出其他类。
具有其他类共有属性和行为的类叫超类或者是父类,从父类派生出来的类叫子类。子类中包含父类所有的属性和方法,同时也可以定义自己特有的属性和方法。
类的继承用extends来声明。
注意:子类会继承父类所有的成员(包括成员变量和成员方法)。
多态
多态(Polymorphism)按字面的意思就是“多种状态”,指同一个实体同时具有多种形式,例如我们可以通过父类的引用来指向不同子类的对象来实现多态。
多态是是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。
例如:
public class Test {
public static void main(String[] args) {
People people2 = new People();//父类引用可以指向父类自己的对象
People people = new Student();//父类引用也可以指向子类对象
Student student = new Student();
people.age = 12;
people.height = 150;
people.weight = 40;
//people.num = 01;不能通过父类的引用来访问子类中父类没有的属性和方法
//子类的引用访问子类中与父类同名的属性
System.out.println("age:" + student.age);
System.out.println("age:" + people.age);//父类的打印的是父类中的age
System.out.println("height:" + people.height);
System.out.println("weight:" + people.weight);
people.speak();//访问的是子类中的speak方法
student.speak();//访问的是子类中的speak方法
people.walk();
}
}
class People {
protected int age;
protected int height;
protected int weight;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public void speak() {
System.out.println("人类能够说话");
}
public void walk() {
System.out.println("人类能够行走");
}
}
class Student extends People{
int age;
private int num;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public void speak() {
System.out.println("学生能够讲话");
}
}
运行结果:
上面的实例中定义了People类和一个继承于People类的Student类,以及一个测试类。从实例中我们可以看到:
1、父类引用可以指向父类本身的对象,也可以指向子类的对象。
2、如果将一个父类的引用指向子类的对象,我们可以通过这个引用来访问子类对象中父类含有的属性和方法,但是不能访问子类对象特有的属性和方法。
3、当子类中有和父类同名的属性和方法时,通过父类引用访问同名的属性时,访问的是父类中的属性;通过父类引用访问同名的方法时,访问的是子类的方法。
4、当子类中有和父类同名的属性和方法时,通过子类的引用访问同名的属性时,访问的是子类的属性;通过子类引用访问同名的方法时,访问的是子类的方法。
注意:
1、当子类中有和父类同名的属性和方法时,父类的属性和方法会被覆盖;
2、引用类型变量有两种类型,一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给它的对象类型决定。
3、对于一个引用类型的变量而言,当通过该变量访问它所引用的对象实例变量时,该实例变量的值取决于该引用的编译时类型(静态绑定);当通过该变量访问它所引用的对象方法时,该方法取决于该引用的运行时类型(动态绑定)。
4、静态绑定:是指在程序编译过程中,把函数(方法或者过程)调用与响应调用所需的代码结合的过程称之为静态绑定。
5、动态绑定:是指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。程序运行过程中,把函数(或过程)调用与响应调用所需要的代码相结合的过程称为动态绑定。