面向对象01.docx
- 文档编号:8484582
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:40
- 大小:76.13KB
面向对象01.docx
《面向对象01.docx》由会员分享,可在线阅读,更多相关《面向对象01.docx(40页珍藏版)》请在冰豆网上搜索。
面向对象01
3.1、面向对象(了解)
面向对象是一种现在最为流行的程序设计方法,几乎现在的所有应用都以面向对象为主了,最早的面向对象的概念实际上是由IBM提出的,在70年代的Smaltalk语言之中进行了应用,后来根据面向对象的设计思路,才形成C++,而由C++产生了Java这门面向对象的编程语言。
但是在面向对象设计之前,广泛采用的是面向过程,面向过程只是针对于自己来解决问题。
面向过程的操作是以程序的基本功能实现为主,实现之后就完成了,也不考虑修改的可能性,面向对象,更多的是要进行子模块化的设计,每一个模块都需要单独存在,并且可以被重复利用,所以,面向对象的开发更像是一个具备标准的开发模式。
在面向对象定义之中,也规定了其一些基本的特征:
·封装:
保护内部的操作不被破坏;
·继承:
在原本的基础之上继续进行扩充;
·多态:
在一个指定的范围之内进行概念的转换。
对于面向对象的开发来讲也分为三个过程:
OOA(面向对象分析)、OOD(面向对象设计)、OOP(面向对象编程)。
3.2、类与对象(核心)
3.2.1、类与对象的基本概念
类:
是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
对象:
对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
那么可以依靠一句话来总结出类和对象的区别:
类是对象的模板,对象是类的实例,类只有通过对象才可以使用,而在开发之中应该先产生类,之后再产生对象。
类不能直接使用,对象是可以直接使用的。
3.2.2、类与对象的定义
如果要在Java之中定义类的话,可以使用class关键字完成,其语法如下:
class类名称{
属性(变量);
行为(方法);
}
范例:
定义一个Person类
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
那么类定义完成之后,肯定无法直接使用,如果要使用,必须依靠对象,那么由于类属于引用数据类型,所以对象的产生格式如下。
格式一:
声明并实例化对象
类名称对象名称=new类名称();
格式二:
分步完成
声明对象:
类名称对象名称=null;
实例化对象:
对象名称=new类名称();
以后只要是引用数据类型的实例化操作,永远都会存在关键字new(分配空间)。
当一个实例化对象产生之后,可以按照如下的方式进行类的操作:
·对象.属性:
表示调用类之中的属性;
·对象.方法():
表示调用类之中的方法。
范例:
使用对象操作类
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=newPerson();//声明并实例化对象
per.name="张三";
per.age=30;
per.tell();
}
}
以上完成了一个基本的类和对象的操作关系,下面换另外一个操作来观察一下。
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=null;//声明对象
per=newPerson();//实例化对象
per.name="张三";
per.age=30;
per.tell();
}
}
疑问?
给出的两种不同的实例化方式有什么区别呢?
如果要想解释这个问题,那么首先需要解决的就是内存的关系理解(Java是在C++之上开发的,所以本次讲解的时候还是按照C++的理论进行内存关系的讲解),首先给出两块内存空间:
·堆内存:
保存对象的真正数据,都是每一个对象的属性内容;
·栈内存:
保存的是一块堆内存的空间地址,可以把它想象成一个int型变量(每一个int型变量只能存放一个数值),所以每一块保留一块堆内存地址,但是为了方便理解,可以简单的将栈内存之中保存的数据理解为对象的名称(Personper),就假设保存的是per。
按照这样的概念理解,以上的程序就可以变成如下的内存关系图表示出来。
如果要想开辟堆内存空间,只能依靠关键字new来进行开辟。
即:
只要看见了关键字new不管何种情况下,都表示要开辟新的堆内存空间。
范例:
观察产生两个对象的操作
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper1=null;//声明对象
Personper2=newPerson();//声明并实例化对象
per1=newPerson();//实例化对象
per1.name="张三";
per1.age=30;
per2.name="李四";
per2.age=20;
per1.tell();
per2.tell();
}
}
但是在这里需要提醒的是,如果在开发之中出现了以下代码:
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=null;//声明对象
per.name="张三";
per.age=30;
per.tell();
}
}
这个时候的程序发现只声明了Person对象,但是并没有实例化Person对象(只有了栈内存,并没有对应的堆内存空间),则程序在编译的时候不会出现任何的错误,但是在执行的时候出现了以下的错误信息:
Exceptioninthread"main"java.lang.NullPointerException
atTestDemo.main(TestDemo.java:
11)
这个错误信息表示的是“NullPointerException(空指向异常)”,这种异常只会在引用数据类型上产生,此异常会一直伴随着大家,到你不写程序的那一天。
3.2.3、引用传递的初步深入
下面通过若干个程序,以及程序的内存分配图,来进行代码的讲解。
范例:
观察以下程序的结果
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper1=newPerson();//声明并实例化对象
per1.name="张三";
per1.age=20;
Personper2=per1;//引用传递
per2.name="李四";
per1.tell();
}
}
引用传递的精髓:
同一块堆内存空间,同时被多个栈内存所指向,不同的栈可以修改同一块堆内存的内容。
范例:
观察以下程序的运行
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper1=newPerson();//声明并实例化对象
Personper2=newPerson();
per1.name="张三";
per1.age=20;
per2.name="李四";
per2.age=30;
per2=per1;
per2.name="王五";
per1.tell();
}
}
垃圾:
指的是在程序开发之中没有任何对象所指向的一块堆内存空间,这块空间就成为垃圾,所有的垃圾将等待GC(垃圾收集器)不定期的进行回收与空间的释放。
范例:
观察如下的程序(恶心点的)
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper1=newPerson();//声明并实例化对象
Personper2=newPerson();
per1.name="张三";
per1.age=20;
per2.name="李四";
per2.age=30;
Personper3=per1;
per3.name="王五";
per3=per2;
per1=per2;
per2.name=per3.name;
per3.age=per1.age;
per2.tell();
}
}
首先本程序是几乎是不可能在开发之中出现的,如果真的出现也是不可能的。
下面还是通过内存关系分析,但是强调几个代码:
per2.name=per3.name;
per3.age=per1.age;
·“per2.name=per3.name;”:
将per3的name属性的给per2.name属性;
·“per3.age=per1.age;”:
将per1的age属性给per3.age属性。
3.3、封装性(重点)
封装属于面向对象的第一大特性,但是本次所讲解的封装只是针对于其中的一点进行讲解,而对于封装操作由于涉及的内容过多,以后会有完整的介绍。
但是在讲解封装操作之前,首先先要来解决一个问题:
为什么要有封装?
范例:
观察没有封装操作的情况
classPerson{//类名称首字母大写
Stringname;
intage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=newPerson();
per.name="张三";
per.age=-30;
per.tell();
}
}
发现这个时候所设置的人的年龄是“-30”岁,结果从代码编译上不会有问题,但是从实际来讲,一个人的年龄不可能是-30岁,这个是属于业务逻辑出错。
而造成这种错误的关键在于没有检查,用户直接操作。
就好比银行,你自己能直接操作金库?
而检查的第一步是需要让用户看不见操作的东西,那么在这种情况下,就可以使用private关键字,将类之中的属性进行私有化的操作。
classPerson{//类名称首字母大写
privateStringname;
privateintage;
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=newPerson();
per.name="张三";//TestDemo.java:
11:
错误:
name可以在Person中访问private
per.age=-30;//TestDemo.java:
12:
错误:
age可以在Person中访问private
per.tell();
}
}
所以现在属性是安全了,而如果现在外部要想操作私有属性,那么按照Java的开发标准而言,现在需要按照如下形式定义操作方法:
setter、getter:
·setter(privateStringname):
publicvoidsetName(Stringn);
·getter(privateStringname):
publicStringgetName();
classPerson{//类名称首字母大写
privateStringname;
privateintage;
publicvoidsetName(Stringn){
name=n;
}
publicvoidsetAge(inta){
age=a;
}
publicStringgetName(){
returnname;
}
publicintgetAge(){
returnage;
}
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=newPerson();
per.setName("张三");
per.setAge(20);
per.tell();
}
}
以上的代码只是可以访问了,不过没有验证,但是问题是验证在那块加?
应该在setter之中增加检查操作。
classPerson{//类名称首字母大写
privateStringname;
privateintage;
publicvoidsetName(Stringn){
name=n;
}
publicvoidsetAge(inta){
if(a>=0&&a<=250){
age=a;
}
}
publicStringgetName(){
returnname;
}
publicintgetAge(){
returnage;
}
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=newPerson();
per.setName("张三");
per.setAge(20);
per.tell();
}
}
以后在进行开发的时候,如果有需要,则在setter上加入一些验证措施,而getter方法只是简单的将数据返回即可,不需要做任何的验证。
疑问?
为什么现在没有在程序之中使用getter()方法?
现在类之中的getName()和getAge()两个方法虽然被定义了,但是发现并没有被使用,那么这样的定义还有意义吗?
在类之中的属性定义setter、getter操作方法目的就是为了设置和取得属性的内容,也许某一个操作暂时不使用到取得的操作,不过从开发来讲,必须全部提供。
以后在定义类的时候,所有的属性都要编写private封装,封装之后的属性如果需要被外部操作,则编写setter、getter。
3.4、构造方法(重点)
在之前强调过方法和属性的区分,方法之后存在“()”,而属性之后什么都没有,如果要想清楚构造方法,则首先来观察以下的格式:
类名称对象名称=new类名称();
这种操作格式在之前已经使用过了,那么下面可以针对于这个格式每一个出现的标记进行解释:
·类名称(类名称对象名称=new类名称();):
要定义变量的数据类型;
·对象名称(类名称对象名称=new类名称();):
指的是日后进行类属性或方法操作的名称;
·new(类名称对象名称=new类名称();):
开辟堆内存空间;
·类名称()(类名称对象名称=new类名称();):
?
?
?
按照道理来讲,加上“()”都属于方法,但是这个方法稍微特殊一些,属于构造方法,所以这个时候就可以发现,构造方法和普通方法不太一样的地方;构造方法是在实例化对象的时候使用,而普通方法是在实例化对象产生之后使用的。
构造方法本身的定义如下:
·构造方法的名称和类名称保持一致;
·构造方法不允许有返回值类型声明;
·由于对象实例化操作一定需要构造方法的存在,所以如果在类之中没有明确定义构造方法的话,则会自动的生成一个无参的,无返回值的构造方法,供用户使用,如果一个类之中已经明确的定义了一个构造方法的话,则无参的什么都不做的构造方法将不会自动生成,也就是说,一个类之中至少存在一个构造方法。
classPerson{//类名称首字母大写
publicPerson(){//无参无返回值的方法
}
}
·构造方法在对象实例化的时候完成操作,而且一个对象的构造方法只会显式调用一次。
当然,在类之中也可以明确的定义一个构造方法,可以通过构造方法为类之中的属性初始化。
classPerson{//类名称首字母大写
privateStringname;
privateintage;
publicPerson(Stringn,inta){//通过构造方法赋值
name=n;
setAge(a);//调用本类中的setAge()方法,可以检查
}
publicvoidsetName(Stringn){
name=n;
}
publicvoidsetAge(inta){
if(a>=0&&a<=250){
age=a;
}
}
publicStringgetName(){
returnname;
}
publicintgetAge(){
returnage;
}
publicvoidtell(){//没有static
System.out.println("姓名:
"+name+",年龄:
"+age);
}
}
publicclassTestDemo{
publicstaticvoidmain(Stringargs[]){
Personper=newPerson("张三",-20);
per.tell();
}
}
当然,如果现在非要强调所调用的方法是本类之中所定义方法的时候,也可以在方法前增加一个this,例如:
publicPerson(Stringn,inta){//通过构造方法赋值
this.setName(n);
this.setAge(a);//调用本类中的setAge()方法,可以检查
}
这里的this就表示本类之中的方法调用,加与不加结果完全相同。
在实际之中构造方法的主要作用只有一点:
在对象实例化的时候为类之中的属性初始化。
当然,对于构造方法而言,也需要注意,那么可以进行重载,不过构造方法重载的时候只需要考虑参数的类型及个数即可,而方法名称肯定是相同的。
范例:
观察构造方法重载
classPerson{//类名称首字母大写
privateStringname;
private
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 面向 对象 01