本篇介绍了面向对象和面向过程的关系,类的定义,对象的成员(成员变量,成员方法)和对象成员访问,类和对象的关系 对象的初始化,对象的构造(构造方法的定义和使用),对象内的this介绍和用法…
细节较多.建议收藏,看完此篇,踏上面向对象的第一步~
类和对象的学习
- 一.初识面向对象
- 1.什么是面向对象
- 2.面向对象与面向过程的区别
- 3.两种思想的实际应用--五子棋
- 二.初识类和对象
- 1.什么是类?
- 2.类的定义格式
- 3.什么是对象?
- ①.对象的创建(类的实例化)
- ②. 对象成员的访问
- 4.类和对象的关系
- 三.对象的构造及初始化
- 1.如何初始化对象?
- 2.什么是构造方法?
- ①.构造方法的定义
- ②.构造方法的使用
- 四.对象里的this引用
- 1.为什么要有this引用
- 2.什么是this引用
- 3.this引用的使用
一.初识面向对象
1.什么是面向对象
Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。
面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。
用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好
2.面向对象与面向过程的区别
面向过程:
自顶而下的编程模式
就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个按着顺序依次调用就可以了。
注重完成事情的过程,每一步是什么样的该如何按照顺序实现每一步…
优点:效率比面向对象高,面向过程强调代码的短小精悍,善于结合数据结构来开发高效率的程序。
缺点:每个步骤都是独立的 没有面向对象易维护、易复用、易扩展
面向对象:
将事务高度抽象化的编程模式
将问题分解成若干个对象,通过不同对象之间的交互,组合解决问题。就是说,在面向对象进行编程的时候,要把属性、行为等封装成对象,然后基于这些对象及对象的能力进行业务逻辑的实现。
建立对象的目的不是为了完成某一个步骤,而是为了描述整个解决问题的步骤中的属性和行为
优点: 易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低,计算时间和空间的开销都比较大
3.两种思想的实际应用–五子棋
面向过程:
面向过程实现五子棋,分析整个五子棋游戏得出以下步骤:(1)开始游戏->(2)创建棋盘->(3)->白棋下棋->(4)绘制显示棋盘->(5)判断输赢->(6)黑棋下棋->(7)绘制显示棋盘->(8)判断输赢->…黑棋下棋…(从2开始重复)->(9)游戏结束
用函数实现上面一个一个的步骤,然后在下五子棋的主函数里依次按照顺序调用上面的函数
面向对象:
面向过程实现五子棋,将整个五子棋游戏分为四个对象:(1)白棋对象,(2)黑棋对象,(3)棋盘系统,(4)规则系统
(1)黑白棋子对象负责接受用户的输入,(2)分告知棋盘棋子布局的变化,棋盘进行相应的改变,并显示棋盘(3)规则系统通过棋盘的布局来判断输赢
分析对比:
可以看出,面对对象是根据功能来进行划分问题,而不是以步骤解决,
绘制画面这个行为,在面向过程中是分散在了多个步骤中的,可能会出现不同的绘制版本,所以要考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘系统这个对象中出现,从而保证了绘图的统一。
在五子棋游戏中增加悔棋的功能。
在面向过程中,从输入到显示再到最后判断的整个步骤都要改动,甚至函数的调用顺序也要改动,
而在面向对象的设计中,只需在棋盘系统中增加一个回溯的功能就可以了,黑白双方和规则系统的属性和行为都不需改动。
这个例子说明了面向对象程序设计中代码间的相关性低(低耦合特性),使得代码很容易被复用和扩展,同时也说明了面向过程的代码重用性低、扩展能力差。
二.初识类和对象
想要使用面向对象编程思想,就要学习类和对象
1.什么是类?
类也就是一个类类型,是一个我们自己定义的类型,有点类似于C语言中的结构体,但是在Java中的类类型里可以有变量(成员属性)也可以有方法(成员行为)
类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(姓名年龄等),哪些行为功能(用来干啥),描述完成后计算机就可以识别了
所有对象无非是由不能动的部分和能动的部分组成,不能动的称之为属性,能动的称之为行为,在定义一个类时要想好该类如果要创建对象那这个对象应该具有什么属性,具有什么行为(根据实际需求定义)
简单定义一个类:
比如:
人类: 用来描述人对象的,要写一个这个类,你得分析人有什么属性有什么行为
属性:姓名,年龄,体重,身高…
行为:吃饭,睡觉,说话,走路…
简单定义好一个类后,在Java应该如何实现呢?
2.类的定义格式
在java中定义类时需要用到class关键字
// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}
class 后面加类名(自定义标识符){}中为类的主体,主要是成员变量和成员方法
类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类 具有哪些功能,称为类的成员方法
示例(初次定义类时属性和行为前面统一先都加上public):
class Person{ //定义一个人 "类"
public String name; //成员变量 对象属性 在类内 方法外部
public int age; //年龄
public void eat(){ //成员方法 对象行为 类里面其他方法外面不加static
System.out.println(age+"岁的"+name+"在吃饭"); //加上当前对象属性 去在做某事
}
public void sleep(){
System.out.println(age+"岁的"+name+"在睡觉");
}
采用Java语言将人’类’在计算机中定义完成,经过javac编译之后形成.class文件,在JVM的基础上计算机就可以识别了
注意事项:
类名注意采用大驼峰定义(每个单词首字母大写,其余的小写)
成员前写法先统一为public
成员方法是非静态的不加static!
- 一般一个文件当中只定义一个类,有多个类时只会有一个public权限的主类其他的都是默认权限的类
- main方法所在的类一般要使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)
- public修饰的类必须要和文件名相同
- 不要轻易去修改public修饰的类的名称,如果要修改,通过开发工具修改,不能直接修改类名
3.什么是对象?
在Java中,一切皆是对象,在我们生活中也有对象,但此对象非彼对象~~Java中对象就是一个实体,从内存角度来看就是一块内存空间
在上面定义一个的一个人类,仅仅只是一个自定义类型,而对象是跟类对应的,计算机最后操作的是对象,而需要通过类实例化后才能得到对象
有了对象后,可以访问对象的属性,行为,配合各种不同的逻辑关系控制,使计算机操作对象去实现某一个事务
①.对象的创建(类的实例化)
我们定义了一个类后,需要使用到类里的成员变量或者方法则需要实例化类.
创建对象也叫类的实例化,Java创建对象需要搭配new关键字和类名来实现
示例:
.....//定义了个人类
public class Note{
public static void main(String[] args){
Person person=new Person(); //等号左边类类型定义一个 引用变量
// 等号右边通过new 加类名() 实例化出一个对象返回其地址给引用变量接受
}
}
注意事项:
new 关键字用于创建一个对象的实例.
创建对象是在堆区申请一块空间,空间里存放了对象的成员变量,而成员方法是存放在方法区的
创建对象后需要用同类型的引用变量接受其地址
同一个类可以创建多个对象,但是要用不同的引用变量接受不同对象的地址
引用是用来存放对象地址的,表示指向那个对象,引用不能指向引用,只能指向对象或者另一个引用所指向的对象!
②. 对象成员的访问
当我们实例化好一个对象后,可以通过存放该对象地址的引用来访问对象成员属性或者成员变量
示例:
class Person{ //定义一个人 "类"
public String name; //成员变量 对象属性 在类内 方法外部
public int age; //年龄
public void eat(){ //成员方法 对象行为 类里面其他方法外面不加static
System.out.println(age+"岁的"+name+"在吃饭"); //加上当前对象属性 去在做某事
}
public void sleep(){
System.out.println(age+"岁的"+name+"在睡觉");
}
public class Note {
//public修饰的 class为主类 和文件名一致的
public static void main(String[] args) {
Person person=new Person(); //由定义的类 通过new关键字 实例化 出对象 类类型定义的变量为引用变量 用来存储 实例化的对象地址
//类就是一个模板 可以创建多个对象 每个对象都有自己的成员变量 成员方法,独立的
person.name="小明"; //通过引用变量里的地址 访问对象的 成员变量 取名为小明
person.age=18; //对象年龄设置为18
person.eat(); //通过引用访问对象 成员方法 让对象做某事
person.sleep();
通过引用变量. 成员变量 可以访问成员变量给其赋值
引用变量.成员方法 可以访问对象的行为,让对象做某事
使用 . 来访问对象中的属性和方法.
4.类和对象的关系
- 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
- 类是一种自定义的类型,里面可以用来定义不同类型的变量和方法
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东 西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
要多加练习,写出一个合格的类才会创造合格的对象
三.对象的构造及初始化
在对象刚被创建出来后,JVM会给对象成员变量在堆区分配好内存空间,后续我们应该对对象进行合理的构造和初始化
1.如何初始化对象?
所谓初始化对象,就是将对象里的成员变量赋值上具体的值,也就是给成员变量初始化
首先我们知道在Java中的方法内部定义的变量属于局部变量,局部变量未初始化是无法被访问的,强行访问会编译失败,必须在使用前对其赋值初始化!
而当我们实例化一个对象后在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:
检测对象对应的类是否加载了,如果没有加载则加载
为对象分配内存空间
处理并发安全问题 比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突
初始化所分配的空间 即:对象空间被申请好之后,对象中包含的成员已经设置好了初始值
设置对象头信息
调用构造方法,给对象中各个成员赋值
下面是一些数据类型对应的默认值
数据类型 | 默认值 |
---|---|
char | ‘\u0000’ |
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0 |
boolean | false |
reference(引用类型) | null |
然而默认的初始值很少使用,一般我们需要在实例化对象后首先会初始化成员变量.以下是一些初始化成语变量的方法
①.通过.操作符访问成员变量
实例化成员对象后通过引用.成员变量对成员变量赋值
示例:
person.name="小明"; //通过引用变量里的地址 访问对象的 成员变量
person.age=18;
②.通过set get方法访问成员变量
在类中定义set get成员方法 用于在实例化对象后通过引用调用成员方法传参给对应的成员变量赋值
//...某个类
public void setName(String n){
name=n;
}
public void setAge(int n ){
age=n;
}
//
person1.setName("张三"); //访问 set方法传参 给对象成员变量赋值
person1.setAge(18);
③.就地初始化
在定义类成员变量时直接在右边赋值表示就地初始化,这种初始化在最后为对象分配好空间设置完默认值后才会由编译器运行
public String name="张三";
public int age=18;
age=18;//此写法不支持
第一二种方法都需要在实例化出对象后,在通过对象引用访问对象成员变量或成员方法对其成员变量进行初始化,第三种方法在类定义的时候就定死了初始化的值也不怎么实用
而在Java中还提供了一种在写实例化对象语句的时候就可以把要初始化的值传给实例化后的成员对象…那就是构造方法
2.什么是构造方法?
构造方法(也称为构造器)是一个特殊的成员方法,要求名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。
①.构造方法的定义
定义构造方法要求方法名与当前类名一致,不设置返回值,权限按照需求设定(暂时先写为public)
示例:
class Person{
public String name;
public int age; //年龄
public void eat(){ //成员方法 对象行为
System.out.println(age+"岁的"+name+"在吃饭");
}
public void sleep(){
System.out.println(age+"岁的"+name+"在睡觉");
}
public Person(String n){ //一个参数的构造方法
name=n;
System.out.println("调用一个参数的构造方法构造方法");
}
public Person(String n,int a){ //两个参数的构造方法
name=n; //给name成员变量赋值
age=a; //给age成员变量赋值
System.out.println("调用两个参数的构造方法构造方法");
}
上面定义了带一个参数的构造方法和一个带两个参数的构造方法构成方法重载,在创建对象后调用传对应的参数调用对应构造方法会运行此构造方法对应的成员变量赋值…
注意事项:
1.构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间,在构造方法内定义的变量是局部变量
2.构造方法名必须与类名相同
3. 没有返回值类型,设置为void也不行
4. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)
5. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
6. 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的且方法体里什么都没执行。一旦用户定义了构造方法,编译器则不再生成默认的构造方法!!!
7. 绝大多数情况下使用public来修饰,特殊场景下会被private修饰
②.构造方法的使用
仔细看我们实例化对象的语句:
Person person=new Person();
Person后面有个()正是用来调用构造方法的,而此时可以简单的理解为是实例化一个对象后,调用该对象的无参构造方法!
但是既然调用了无参数的构造方法,我们看不到什么效果,正如上面构造方法定义的注意事项第六条,我们自己没有定义构造方法的时候,编译器会自动给我们在类里定义一个无参数的构造方法,并且该构造方法方法体内没有任何语句.
public Person(){ //编译器生成的默认无参构造方法
}
当我们在类中定义了之前上面的构造方法后再执行实例化成员对象的语句:
Person person=new Person(); //调用无参构造方法
Person person2=new Person("张三");//实例化对象后调用1个参数的构造方法
Person person3=new Person("李四",18);//调用两个参数的构造方法
发现此时会报错,这是因为设置了一个参数和两个参数的构造方法,但是没有无参构造方法,编译器也不会给你添加,此时需要自己加一个无参构造方法
public Person(){ //添加的无参构造方法
System.out.println("调用无参数的构造方法");
}
在设置好对应的构造方法后,分别实例化三个对象调用不同的构造方法,在实例化对象后会调用对应的构造方法给成员变量赋值
注意事项:
1.构造方法是在实例化对象后再进行调用的
2.会根据调用构造方法传递的参数找对应参数类型的构造方法
3.当有就地初始化时,是先执行就地初始化再执行构造方法可以理解为就地初始化语句会放在构造方法里的前面
四.对象里的this引用
1.为什么要有this引用
看一下下面代码会有什么输出结果
//类..
public String name;
public int age;
public void setName(String name,int age){ //初始化成员变量的成员方法
name=name;
age=age;
}
//
Person person=new Person();
person.setName("张三",18);
System.out.println(person.name+" "+person.age); //输出结果是什么
这串代码看起来是为成员变量设置了姓名为张三,年龄为18,但是实际输出结果却不是↓
这是因为,形参和成员变量名出现了同名的情况,而在出现name=name这种语句时,编译器会使离作用域最近的变量在等号左边另一个在等号右边,也就是局部变量优先,此时 等号左边的name是局部变量,等号右边的name是成员变量,经过赋值后局部变量原本存放了张三被改为null,而全局变量一直是null没有变化, age变量也是如此…
==========================================
再思考一下,当我们有多个引用变量接受了多个对象的地址,此时分别调用每个对象的成员方法,但是成员方法是在类里面定义的只有一份,在加载时也只有一份被放到方法区,而编译器又是如何知道调用的成员方法是属于具体哪一个对象的呢?
而this引用正是为了解决上面这些问题…
2.什么是this引用
this引用可以看做是一个引用变量,存放的当前对象的地址,表示指向当前对象
它是成员方法中第一个隐藏的参数,
public void setName(Person this,String name){
}
//每个方法前实际隐藏了一个当前类 定义的引用变量 this
//this接受的是当前对象的地址(由编译器自动完成)
当我们调用某个成员方法时,尽管我们没有传当前对象的地址作为参数,编译器会隐式将当前这个成员方法所属的对象地址也会传参过去,最后由成员方法内隐藏的引用变量接受,这个this变量虽然被隐藏,但是我们可以直接使用…
在成员方法中所有成员变量的操作,都是通过该 this引用去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
这也就实现了在成员方法内能够获取到当前对象地址…
3.this引用的使用
现在知道了this引用是一个隐藏的成员方法的形参,它里面存放的是当前对象的地址,其功能和引用变量一样,可以直接访问对象
this.成员变量 this.成员方法 this(构造方法)
this的用法:
this.成员变量 访问当前对象的成员变量
public String name;
public int age;
public void setName(String name,int age){ //初始化成员变量的成员方法
this.name=name; //this.name表示当前对象的成员变量
this.age=age;
}
//
Person person=new Person();
person.setName("张三",18);
System.out.println(person.name+" "+person.age); //输出结果是什么
使用在name前面使用this后能够准确表达是当前对象的成员变量,解决了局部变量与成员变量冲突的问题
this.成员方法 访问当前对象的成员方法
在成员方法内可以通过this.成员方法来调用其他或自身成员方法,但是因为是在类里,可以不加this也能实现调用,但注意不要出现死循环导致栈溢出!
this() 调用其他构造方法
该语句要求写在构造方法的第一行可以调用其他构造方法,括号里写对应的构造方法的参数,
注意:不能调用自身构造方法,每个构造方法都可以用this调用其他构造方法,但是不能踢皮球–来回死循环调用
注意事项:
- this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型
- this只能在"成员方法"中使用(非静态成员方法和构造方法)
- 在"成员方法"中,this只能引用当前对象,不能再引用其他对象
- this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法 对象的引用传递给该成员方法,this负责来接收
5.this引用属于对象地址不能访问静态成员变量和方法