在处理复杂事物的时候,用到的一种基本手段就是抽象。抽象的目的就是区别事物之间的本质和不同,面向对象编程(OOP)的实质就是利用类和对象来建立抽象模型。
概述
Java语言最精华的部分自然是其面向对象的部分。接下来我们就结合面向对象编程的基本思想,来学习对应的Java语言特性。
在面向对象的世界观里,客观世界是由对象组成的,对象有其自己的属性和活动规律,对象之间的相互依赖和相互作用,构成了现存的各式各样的系统。
类是Java语言中的核心概念。类是一组具有相同属性、操作、关系和语义的对象的描述,对象则是类的一个实例。
类的定义
创建抽象数据类型是面向对象编程的基本思想。理解类的最重要的事情就是它定义了一种新的数据类型,它定义了某一类对象的性质和行为。
例1 类的定义
class name{
// class body
}
定义一个类非常简单,使用class关键字,加上你想要定义的类的名字在用花括号包起来就可以。
一旦定义了一个类,就可以在类中设置两种类型的元素:
字段(或者成为数据成员、成员变量)
方法(也叫成员方法)
字段可以使基本的数据类型,也可以是任何类型的对象。类中的字段定义了对象的性质,方法定义了对象的行为。
一个类除了可以包含字段外还可以包含:
局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。
类的成员方法
方法定义的格式如下:
访问控制权限 返回值 方法名(参数列表){
//方法体
return value;
}
这是一个具体的例子:
public void show(){
System.out.println("I am is : ....");
}
访问控制权限包括: public、 protected、 private,这涉及到访问控制权限,跟面向对象中封装这个概念紧密相连,它们的语义分别为:
public:其他任何类都可以访问该成员
protected:只有自己的子类才能访问该成员
private:除自己外其他任何类都不能访问该成员
如果没有任何访问控制修饰符,则表示相同包(package)内的类可以访问该成员
返回值可以使任意类型,也可以为空,为空的话就使用void,同时return语句就可以省略掉,或者只写return,不加返回值。
参数列表可以有任意多个参数,也可以为空。
成员变量和成员方法的访问控制遵循一样的规则。
例2 一个完整的类的定义
class Rectangle{
int width;
int height;
public Rectangle(){
}
public Rectangle(int width, int heigth){
this.width = width;
this.heigt = height;
}
int area(int w, int h){
return w * h;
}
}
该类抽象了一个矩形,包含两个字段width和height,同时声明了两个构造方法,一个有参数的,一个无参数的,以及一个成员方法area()用来获取该矩形的面积。
构造方法
每个类都有构造方法,如果没有显示的定义,则java编译器就会自动为该类添加一个默认的构造方法,如例2中的public Rectangle(int width, int heigth),构造方法的形式如下:
Public ClassName {
public ClassName(){
//
}
}
在创建对象的时候,需要调用构造方法,构造方法名称必须与类名相同,同一个类可以包含多个构造方法。构造方法也可以有参数。
例3 显示的定义构造方法
class Rectangle{
int width;
int height;
public Rectangle(){
}
public Rectangle(int width, int heigth){
this.width = width;
this.heigt = height;
}
}
该例子的类包含两个构造方法,一个无参数的和一个有参数的,如果显示的定义无参数的构造方法,则java编译器就不会在提供默认的构造方法。
对象的创建
对象是类的实例,对象是动态的,拥有生命周期,包括创建、运行到消亡的过程。对象与类的关系就像变量和数据类型一样。创建对象包含对象的声明、实例化(或者初始化)。
对象的声明
String str;
Date date;
Rectangle rectangle;
上述声明了三个对象,一个字符串和一个日期对象,它们是java 提供的,rectangle是我们自己定义的。
创建类的实例必须调用类的构造方法,但也有特殊的,像String对象可以直接初始化的。
str = new String("abc");
date = new Date();
rectangle = new Rectangle();
该例子展示创建对象以及实例化对象如何调用方法和成员变量。
public class TestRectangle{
public static void main(String [] args){
Rectangle rectangle = new Rectangle();
rectangle.setWidth(10);
rectangle.show();
System.out.println("My width is: "+ rectangle.width);
}
}
this与super
在Java中,this指当前对象,super则指父类的。
最普遍的使用就是在你的方法中的某个形参名与当前对象的某个字段有相同的名字,这时为了不至于混淆,你需要明确使用this关键字来指明你要使用某个字段,使用方法是this.propertyName,而不带this的那个便是形参。
例4 this的用法
class Rectangle{
int width;
int height;
public Rectangle(int width, int heigth){
this.width = width;
this.heigt = height;
}
public setWidth(int width){
this.width = width;
}
public setHeight(int height){
this.height = height;
}
}
这个例子中的构造方法和两个set方法中都使用了this,它的作用就是区别方法的形参和类本身的字段。
提示
可以用this.propertyName来引用当前对象的某个方法,但这时this 就不是必须的了,你可以直接用方法名来访问那个方法,编译器会知道你要调用的是哪一个。
例5 super的用法
class Graph{
public void show(){
System.out.println("I'm a graph");
}
}
class Rectangle extends Graph{
int width;
int height;
public void show(){
super.show();
System.out.println("at the same time I'm a Rectangle");
}
}
super常用于继承关系的类中,子类需要调用到父类的某个方法,这时就需要用到super这个关键字。如例4所示,Rectangle继承并覆写了父类的show()方法,在show()方法中先调用父类的的show()方法,在执行自己的显示作用。如果父类中的字段可以被子类访问,则可以使用super。类似于this,super.propertyName来使用父类的字段。
例6 this和super的第二种用法
class Graph{
String name;
public Graph(){}
public Graph(String name){
this.name = name;
}
public void show(){
System.out.println("I'm a graph");
}
}
class Rectangle extends Graph{
int width;
int height;
public Rectangle(){
super();
}
public Rectangle(String name){
super(name);
}
public Rectangle(int width, int height,String name){
this(name);
System.out.println("My width is:" + width + "my height is :"+ height);
}
public void show(){
super.show();
System.out.println("at the same time I'm a Rectangle");
}
}
例5中我们在Rectangle中定义了三个构造方法,前两个构造方法中分别使用了super()和super(String name),这和使用"."完全不同,这里是调用父类中的具有相同形式的构造方法,我们在父类中定义了两个构造方法,两个super分别对应到这两个构造方法。在Rectangle的第三个构造方法中出现了this(name),它是调用自身的具有相同形式的构造方法。
this可以作为参数被传递,如下面所示:
class Square{
public Square(){
new Rectangle(this).show();
}
public void show(){
System.out.println("this is Square");
}
}
class Rectangle{
Square square;
public Rectangle(Square square){
this.square = square;
}
public void show(){
square.show();
System.out.println("this is Rectangle");
}
}
在这个例子中,对象Square的构造函数中,用new Rectangle(this)把对象Square自己作为参数传递给了对象Rectangle的构造函数。