第1节 类和对象
1.1 认识类和对象
1.1.1 什么是面向对象
传统的开发程序的方式采用过程化的编程方式,即将程序考虑成一个顺序执行的指令串。所以采用过程化开发方式的程序员首先要做的事,就是针对需求,自顶向下、逐步细化,将问题分解成一连串的简单步骤。但是随着用户需求的不断增加和变更,软件规模越来越大,业务逻辑越来越复杂,传统的这种面向过程的开发方式暴露出来许多问题,如软件开发延迟,开发成本难以控制,工程难以维护等。
在面向对象程序设计里,将数据和处理数据的方法紧密地结合在一起,形成类,再将类实例化,形成对象。计算机程序被概念化成协同工作、共同完成所需任务的一组对象集。每一个对象都是程序的一个独立部分,可自行控制并与其他对象进行通信和交互。
1.1.2 什么是对象
对象,是理解面向对象技术的关键。在现实世界中,对象随处可见,如宠物狗,桌子,自行车,树、鸟、鱼等。真实世界对象具有共同的两个特性:它们都有状态和行为。狗有状态(名字,颜色,品种,饥饿)和行为(叫,刨地,摇尾巴),自行车也有状态(当前的齿轮档位,当前的速度)和行为(变速,刹车)。
软件中的对象在概念性上与真实世界中的对象很相似,它们都包括状态和相关的行为。一个对象在属性(在一些程序设计语言中用变量代表)中存储它的状态,并通过方法(在一些程序设计语言中是函数)暴露它的行为。
1.1.3 什么是类
在现实世界中,会经常发现许多单独的对象都是同一类型。例如,也许有成千上万的单个的自行车存在,但它们都是同样的模型,以相同的方式被制造。每一个自行车都是构建于同一模板并因此包含同样的组件。在面向对象术语中,就可以说,某个人的具体的自行车是自行车这个对象类的一个实例。
一个类就是一个模板,从它那里个体对象被创建。由类构造对象的过程称为创建类的实例。
类是一组具有相同属性和行为的对象的抽象。而对象则是类的具体存在。所以,在面向对象的程序设计语言中,类代表一个对象类型,它就像一个模板一样,在代码运行阶段它被创建为一个个对象实例。每个类由两个部分组成:属性和行为。属性通常是一些数据状态值,类通常将数据封装在自己内部,访问这些数据属性必须通过类公开的方法,或者接口。
类的本质是一种自定义的数据类型,可以使用类来定义变量,所有使用类定义的变量都是引用变量,它们将会引用到类的对象。
1.2 类和对象的创建
1.2.1 如何声明类
对于一个类而言,可以包含三种最常见的成员:Field、方法和构造器。Field用于定义该类或该类的实例所包含的状态数据;方法则用于定义该类或该类的实例的行为特征或者功能实现;构造器用于构造该类的实例。
类的声明如以下代码所示:
[类修饰符] class 类的名称 [extends 父类名称] [implements 接口名称] {
//属性、构造函数和方法声明
}
其中class关键字是必需的。类的名称用来标识一个类,它的命名要符合Java标识符命名规范。在这里,用方括号将类修饰符包围起来,它代表的含义是里面的内容是可选的。
在同一个Java源文件中可以有多个类,但不能包含两个或两个以上的带有public修饰词的类。如果某个类的声明前含有public修饰词,那么含有此类的源文件必须与此类的类名相同。
在声明一个类时,还可以提供更多的信息。例如,指明该类的父类(也称为超类)的名称,即该类是从哪个类派生过来的,这需要在类名后面加上关键字extends来实现。还可以在声明一个类时指明该类是否实现接口,这需要在类名后面加上关键字implements来实现。
类的主体简称类体,指的是类名后面大括号中的内容。类体包含所有用于创建自该类的对象的生命周期的代码,包括构造器(用于初始化新对象)、属性声明(用于表示类及其对象的状态)及方法(实现类及其对象的行为)。
1.2.2 如何创建对象
使用new关键字创建对象。
public class Hello{
public static void main(String[] args) {
Hello h1 = new Hello();//创建Hello类的第一个对象
h.sayWorld();
Hello h2 = new Hello();//创建Hello类的第二个对象
h.sayWorld();
}
public void sayWorld(){
System.out.println("Hello world!");
}
}
一个类可以有多个对象。如果创建了多个对象,则每个对象都独立的拥有一套类的属性(非static修饰的),意味着,如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
1.3 类的成员之一:属性
属性的常用叫法:属性=成员变量=field=域=字段。
1.3.1 属性变量的作用域
在程序中有多种类型的变量,这些变量在程序中的位置不同,所起的作用也不相同。
分类如下:
1.3.2 属性变量的特点
参数和局部变量都是演草纸,方法执行完就清除了。
方法里创建的对象是不会随着方法结束被清除的。因为对象是实例,不是变量,对象被创建出来以后,被堆在一起,放在类似公告板的地方,只要有引用指向一个对象,这个对象的数据就可以通过这个引用来访问。
成员变量在类加载时会有初始化值,局部变量在类加载时不会有初始化值,所以所以要使用局部变量时,一定要显式的给它赋值。
1.4 类的成员之二:方法
方法的常用叫法:方法=成员方法=函数=method。
1.4.1 什么是方法
所谓方法,类似于其他语言中的函数,是一个相对独立的代码语句块,通常实现一定的功能。
方法的设计原则:方法的本意是功能块,就是实现某个功能的语句块的集合,我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样利于我们后期的扩展。
1.4.2 如何定义方法
在类中声明成员方法的语法格式如下:
[修饰符] 方法返回值类型 方法名(形参列表)
{
//由零条到多条可执行性语句组成的方法体
}
- 修饰符:修饰符可以省略;
- 方法返回值类型:返回值类型可以是Java语言允许的任何数据类型,包括基本类型和引用类型;
- 方法名:方法名只要是一个合法的标识符即可;
- 形参列表:形参列表用于定义该方法可以接受的参数。一旦在定义方法时指定了形参列表,则调用该方法时必须传入对应的参数值——谁调用方法,谁负责为形参赋值;
- 方法体里是零条或多条可执行性语句。
1.2.3 方法的四种类型
1、无参数无返回值的方法
// 无参数无返回值的方法(如果方法没有返回值,不能不写,必须写void,表示没有返回值)
public void f1() {
System.out.println("无参数无返回值的方法");
}
2、有参数无返回值的方法
/**
* 有参数无返回值的方法
* 参数列表由零组到多组“参数类型+形参名”组合而成,多组参数之间以英文逗号(,)隔开,形参类型和形参名之间以英文空格隔开
*/
public void f2(int a, String b, int c) {
System.out.println(a + "-->" + b + "-->" + c);
}
3、有返回值无参数的方法
// 有返回值无参数的方法 (返回值可以是任意的类型 ,在函数里面必须有return关键字返回对应的类型)
public int f3() {
System.out.println("有返回值无参数的方法");
return 2;
}
4、有返回值有参数的方法
// 有返回值有参数的方法
public int f4(int a, int b) {
return a * b;
}
5、return在无返回值方法的特殊使用
// return在无返回值方法的特殊使用
public void f5(int a) {
if (a>10) {
return;//表示结束所在方法 (f5方法)的执行,下方的输出语句不会执行
}
System.out.println(a);
}
1.4.4 方法的调用
在同一个类中,方法之间的调用语法如下:
方法名( );
在不同的类之间,方法之间的调用语法如下:
对象名.函数名(实参列表)//方法调用要有括号,即使没有参数
1.4.5 方法的递归调用
A方法调用B方法,我们很容易理解。
递归就是A方法调用A方法,就是自己调用自己 。
利用递归可以用简单的程序来解决一些复杂的问题 ,它通常把一个大型复杂的问题层层转化为一个于原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大的减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
递归结构包括两个部分:
-
递归头:什么时候不调用自身方法。如果没有头,将陷入死循环;
-
递归体:什么时候需要调用自身方法。
public class Variable {
public static void main(String[] args) {
System.out.println(new Variable().f(3));
}
//5! 5*4*3*2*1
public static int f(int n){
if(n==1){
return 1;
}else {
return n*f(n-1);
}
}
}
1.4.6 方法重载
方法重载指在同一个类里面,有多个名字相同的方法,但是方法的参数类型或者参数的个数不一致,称之为方法重载,方法的返回类型不作为方法重载判断的依据。方法重载之后,具体要调用哪个重载的方法,由方法的参数类型或个数决定(自动匹配)。
JDK1.5开始,Java支持传递同类型的可变参数给一个方法。
在方法声明中,在指定参数类型后加一个省略号(...)。
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
public class Variable {
public static void main(String[] args) {
new Variable().a(1,3,5);
}
public void a( int... i){
System.out.println(i[0]);
}
}
1.4.7 方法的参数传递
形参,是方法声明时,方法小括号内的参数;实参,是调用方法时,实际传入的参数的值。
那么,Java的实参值是如何传入方法的呢?这是由Java方法的参数传递机制来控制的,Java里方法的参数传递方式只有一种:值传递。所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。
Java里的参数传递类似于《西游记》里的孙悟空,孙悟空复制了一个假孙悟空,这个假孙悟空具有和孙悟空相同的能力,可除妖或被砍头。但不管这个假孙悟空遇到什么事,真孙悟空不会受到任何影响。与此类似,传入方法的是实际参数值的复制品,不管方法中对这个复制品如何操作,实际参数值本身不会受到任何影响。
但是,当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用的一个副本。指向同一个对象,对象的内容可以在被调用的方法中改变,但对象的引用(不是引用的副本)是永远不会改变的。也就是说,在方法的执行过程中,形参和实参的内容相同,指向同一块内存地址,操作的其实都是源数据,所以方法的执行将会影响到实际对象。
1.5 类的成员之三:构造器
1.5.1 声明构造器
类包含有构造器,Java语言通过new关键字来调用构造器,从而返回该类的实例。当创建对象实例时,构造器会被调用以根据类模板创建对象实例。
构造方法是指在一个类里面,方法的名字与类的名字一致,且没有返回值,包括void也没有。简单来说需要满足两个条件:第一,方法名字和类名一致 ;第二,方法没有任何返回值。构造器是一个特殊的方法。
定义构造器的语法格式如下:
[修饰符] 构造器名(形参列表)
{
//由零条到多条可执行性语句组成的构造器执行体
}
- 修饰符:修饰符可以省略;
- 构造器名:构造器名必须和类名相同。
- 形参列表:和定义“方法形参列表”的格式完全相同。
1.5.2 构造器的特点
构造器的声明看上去与方法声明类似,但是构造器有自己的特点。
构造器既不能定义返回值类型,也不能使用void定义构造器没有返回值。实际上,类的构造器是有返回值的,当我们用new关键字来调用构造器时,构造器返回该类的实例,可以把这个类的实例当成构造器的返回值,因此构造器的返回值类型总是当前类,无须定义返回值类型。但必须注意:不能在构造器里显式使用return来返回当前类的对象,因为构造器的返回值是隐式的。
如果没有显式地添加一个构造方法,Java会给每个类默认自带一个无参数的构造方法,如果我们自己添加类的构造方法(无论是否无参),Java就不会再添加无参数的构造方法。这时候,就不能直接new一个对象而不传递参数了。所以我们一直都在使用构造方法,这也是为什么创建对象的时候类名后面要有一个括号的原因。
1.5.3 构造方法的重载与调用
构造方法的重载和普通方法一样。
构造方法不能被普通方法调用,只能通过new语句在创建对象的时候,间接调用。
只有在构造方法里才能调用重载的构造方法,语法为this+(实参列表)
,必须是方法的第一行,后面可以继续有代码。
构造方法不能自己调用自己,这是一个死循环。
在调用重载的构造方法时,不可以使用成员变量,因为在语意上讲,这个对象还没有被初始化完成,处于中间状态。
1.5.4 this关键字
this关键字总是指向调用该方法的对象。this可以用来修饰属性、方法、构造器。
static修饰的方法中不能使用this引用。如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象。所以,static修饰的方法中不能使用this引用。
通常情况下,this可以省略,但如果方法的形参和类的属性同名时,不能省略,表示此变量是属性,而非形参。我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中指定的其他构造器。但构造器中不能通过“this(形参列表)”方式调用自己。规定“this(形参列表)”必须声明在当前构造器的首行。
/***用法有三种:*1.在本类的成员方法中,访问本类的成员变量。
*2.在本类的成员方法中,访问本类的另一个成员方法。
*3.在本类的构造方法中,访问本类的另一个构造方法。
*/
public class Zi extends Fu{
int num = 20;
public Zi(){
this(134); //本类的无参构造,调用本类的有参构造
}
public Zi(int n ){ }
public Zi(int n, int m ){ }
public void showNum(){
int num = 10;
System.out.println(num); //局部变量
System.out.println(this.num); //本类中的成员变量
System.out.println(super.num); //父类中的成员变量
}
}
public class Fu {
int num =30;
}
1.6 类的成员之四:代码块
1.6.1 认识代码块
代码块的作用是用来初始化类或对象的。代码块只能使用static修饰,分为非静态代码块和静态代码块。
public Hello {
{
//代码块
}
}
1.6.2 使用代码块
代码块是随着类加载或创建对象的时候执行的。非静态代码块每创建一次对象执行一次,静态代码块只能执行一次。
先加载静态代码块,再加载非静态代码块。同等的代码块按先后顺序执行。
© 著作权归作者所有
发表评论