我们都知道Java是一种面向对象程序设计(英语:Object-oriented programming:OOP)的语言,它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。
面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令(面向过程程序设计,例如C语言)。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。目前已经被证实的是,面向对象程序设计推广了程序的灵活性和可维护性,并且在大型项目设计中广为应用。此外,面向对象程序设计要比以往的做法更加便于学习,因为它能够让人们更简单地设计并维护程序,使得程序更加便于分析、设计、理解。
接下来,我们来一一介绍作为面向对象程序设计语言Java的三大特性。
首先是Java语言的封装特性,Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。其基本分类如下:
基本数据类型
- 数值型
整数类型(byte,short,int,long)
浮点类型(float,double) - 字符型(char)
- 布尔型(boolean)
引用数据类型
- 类(class)
- 接口(interface)
- 数组([])
序号 | 数据类型 | 位数 | 默认值 | 取值范围 | 举例说明 |
1 | byte(位) | 8 | 0 | -2^7~2^7-1 | byte b = 10 |
2 | short(短整数) | 16 | 0 | -2^15~2^15-1 | short s = 10 |
3 | int(整数) | 32 | 0 | -2^31~2^31-1 | int i = 10 |
4 | long(长整数) | 64 | 0 | -2^63~2^63-1 | long l = 10l |
5 | float(单精度) | 32 | 0.0 | -2^31~2^31-1 | float f = 10f |
6 | double(双精度) | 64 | 0.0 | -2^63~2^63-1 | double d = 10.0d |
7 | char(字节) | 16 | 空 | 0~2^15-1 | char c = 'c' |
8 | boolean(布尔值) | 8 | false | true、false | boolean b = true |
同时在Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 四种不同的访问权限。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
- default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意: 不能修饰类(外部类)。
- public : 对所有类可见。使用对象:类、接口、变量、方法。
访问修饰符的图如下:
修饰符 | 当前类 | 同包 | 子类 | 其他包 |
private | √ | × | × | × |
default | √ | √ | × | × |
protected | √ | √ | √ | √ |
public | √ | √ | √ | √ |
Java通过使用不同的关键字,让对象私有,防止无关的程序去使用,实现模块的封装。
其次是Java语言的继承特性,继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
生活中的继承如下:
例如我们定义了一个person类:
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
现在,假设需要定义一个Student
类,字段如下 :
class Student {
private String name;
private int age;
private int score;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
public int getScore() { … }
public void setScore(int score) { … }
}
继承是面向对象编程中非常强大的一种机制,它首先可以复用代码。当我们让Student
从Person
继承时,Student
就获得了Person
的所有功能,我们只需要为Student
编写新增的功能。
Java使用extends
关键字来实现继承:
class Person {
private String name;
private int age;
public String getName() {...}
public void setName(String name) {...}
public int getAge() {...}
public void setAge(int age) {...}
}
class Student extends Person {
// 不要重复name和age字段/方法,
// 只需要定义新增score字段/方法:
private int score;
public int getScore() { … }
public void setScore(int score) { … }
}
在OOP的术语中,我们把Person
称为超类(super class),父类(parent class),基类(base class),把Student
称为子类(subclass),扩展类(extended class)。
最后是Java语言的多态特性, 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。下面我们来分别说明:
重写(Override):从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的。
例如,在Person
类中,我们定义了run()
方法:
class Person {
public void run() {
System.out.println("Person.run");
}
}
在子类Student
中,覆写这个run()
方法:
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
重载(Overload):在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
在一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在Hello
类中,定义多个hello()
方法:
class Hello {
public void hello() {
System.out.println("Hello, world!");
}
public void hello(String name) {
System.out.println("Hello, " + name + "!");
}
public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!");
} else {
System.out.println("Hello, " + name + "!");
}
}
}
最后,对本文进行一个总结,java三大特性如下:
封装: 使用private关键字,让对象私有,防止无关的程序去使用。
继承: 继承某个类,使子类可以使用父类的属性和方法。
多态: 同一个行为,不同的子类具有不同的表现形式。