黑马程序员——面向对象



-------androidjava培训、期待与您交流! ----------




面向对象

 


面向对象是相对面向过程而言的。

面向对象和面向过程都是一种思想。

面向过程:强调的是功能行为。


面向对象:将功能封装进对象,强调了具备功能的对象。


面向对象是基于面向过程的。 


面向对象是一种符合人类思维习惯的编程思想,现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。


面向对象是一种思想,它能让复杂的问题简单化,能让我们得角度进行转变,从执行者变为指挥者  


人开门:名词提炼法

开门 (门)

门。开};}

开() {操作门轴等。}} 


面向过程和面向对象图例:


黑马程序员——面向对象_第1张图片


 


面向对象有三个特征:封装、继承、多态。


面向对象的特点:

以后开发,就是找对象使用,没有对象就自己建立一个对象使用。

找对象,建立对象,使用对象,并维护对象的关系。

类和对象的关系:

类:就是对现实生活中事物的描述。

对象:就是这类事物实实在在存在的个体。

现实生活中的对象:张三、李四

想要描述:提取对象中共性内容,对具体的抽象。

描述时:这些对象的共性有姓名、年龄、性别、学习JAVA的功能。

映射到JAVA中,描述就是class定义的类。

具体对象就是对应JAVA在堆内存中用new建立实体。

例:

需求:描述汽车(颜色,轮胎数),描述事物其实就是描述事物的属性和行为。

黑马程序员——面向对象_第2张图片


成员变量和局部变量:

作用范围:

成员变量:作用于整个类中

局部变量:作用于函数中,或者语句中。

在内存中的位置:

成员变量:在堆内存中,因为对象的存在,才在内存中存在。

局部变量:存在栈内存中。

 


匿名对象


匿名对象是对象的简化形式。

匿名对象两种使用情况:

1、当对对象方法仅进行一次调用时。

2、匿名对象可以作为实际参数进行传递。

匿名对象使用方法之一:当对对象的方法只调用一次,可以用匿名对象来完成,这样写比较简化。

如果一个对象进行多个成员调用,必须给这个对象起个名字。

匿名对象使用方法之二:可以将匿名对象作为实际参数进行传递。


封装

封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处:

将变化隔离。

便于使用。

提高重用性。

提高安全性。

封装原则:

        将不需要对外提供的内容都隐藏起来。

        把属性都隐藏,提供公共方法对其访问。 


Private(私有)关键字

Private是一个修饰符。用于修饰成员(成员变量和成员函数),被私有化的成员只在本类中有效。

常用之一:将成员变量私有化,对外提供对应的set ,get方法对其进行访问,提高对数据访问的安全性。

注意:私有仅仅是封装的一种表现形式。

Private 图例:

黑马程序员——面向对象_第3张图片


 


构造函数 


特点:

1、函数名与类名相同。

2、不用定义返回值类型。

3、不可以写return语句。

对象一建立就会调用与之对应的构造函数。


构造函数的作用:可以用于给对象进行初始化。

构造函数的小细节:

当一个类中没有定义构造函数时,那么系统会默认给该类加入一个空参数的构造函数。

如果定义了一个构造函数,系统将不会默认定义一个构造函数。

构造函数和一般函数有什么不同:

构造函数和一般函数在写法上有不同。

在运行上也有不同。

构造函数是在对象一建立就运行,给对象初始化。

而一般方法是对象调用才执行,给是对象添加对象具备的功能。

一个对象建立,构造函数只运行一次。

而一般方法可以被该对象调用多次。

什么时候定义构造函数呢?

当分析事物时,该事物存在具备一些特性或者行为,那么将这些内容在构造函数中。 


构造代码块

作用:给对象进行初始化

对象一建立就运行,而且优先于构造函数执行。

和构造函数的区别:

构造代码块是给所有对象进行统一初始化。

而构造函数是给对应的对象初始化。

构造代码块中定义的是不同对象共性的初始化内容。


例:

class Person

{         Stringname;

         intage;

         Person(Stringname,int age) //定义一个带有参数的构造函数

         {

                   this.name= name;

                   this.age= age;

         }

}


 


this关键字 


this:看上去,是用于区分局部变量和成员变量同名的情况。

this为什么可以解决这个问题呢?

this到底代表的是什么呢?

this:就代表本类的对象,到底代表哪一个。

this代表它所在函数所属对象的引用。

简单说,哪个对象在调用this所在的函数,this就代表哪个对象。

this的应用:当定义类中功能时,该函数内部要用到调用该函数的对象时,这时用this来表示这个对象。但凡本类功能内部使用了本类对象都用this来表示。

构造函数间的调用只能用this语句。

注意:this语句只能定义在构造函数的第一行,因为初始化要先执行。

this(name);//用于构造函数间的调用。

例:

黑马程序员——面向对象_第4张图片


这种调用是不允许存在的,是死循环。 


静态:static

用法:是一个修饰符,用于修饰成员(成员变量和成员函数)。

当成员被静态修饰后,就多一个调用方式,除了可以被对象调用外,还可以直接被类名调用 类名.静态成员

static特点:

1、随着类的加载而加载

       也就是说:静态会随着类的消失而消失,说明它的生命周期最长。

2、优先于的对象存在

       明确一点:静态是先存在的,对象是后存在的。

3、被所有对象所共享

4、可以直接被类名所调用


实例变量和类变量的区别:

1、存放位置

       类变量随着类的加载而存在于方法区中。

       实例变量随着对象的建立而存在于堆内存中。

2、生命周期

       类变量生命周期最长,随着类的消失而消失。

       实例变量生命周期随着对象的消失而消失。

静态的使用注意事项:

1、静态方法只能访问静态成员。非静态方法即可以访问静态也可以访问非静态。

2、静态方法中不可以定义thissuper关键字,因为静态优先于对象存在,所以静态方法中不可以出现this

3、主函数是静态的。


静态有利有弊:

利:对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份。可以直接被类名调用。

弊端:生命周期过长。访问出现局限性。(静态虽好,只能访问静态)。 


什么时候使用静态?

要从两方面下手:

因为静态修饰的内容有成员变量和函数。

什么时候定义静态变量(类变量)呢?

当对象中出现共享数据时,该数据被静态所修饰。

对象中的特有数据要定义成非静态存在于堆内存中。

什么时候定义静态函数呢?

当功能内部没有访问到非静态数据(对象的特有数据),

那么该功能可以定义成静态的。 


静态的应用:

每一个应用程序中都有共性的功能。

可以将这些功能进行抽取,独立封装,以便复用。

public static void main(String[] args)

主函数:是一个特殊的函数,作为程序的入口,可以被jvm调用。

主函数的定义:

public:代表着该函数访问权限是最大的。

static:代表主函数随着类的加载就已经存在了。

void:主函数没有具体的返回值。

main:不是关键字,但是是一个特殊的单词,可以被jvm识别。

(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串,字符串类型的数组。

主函数是固定格式的:jvm识别。

jvm在调用主函数时,传入的是new String[0];



虽然可以通过ArrayTool对象使用这些工具方法,对数据进行操作。

发现了问题:

1、对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。

2、操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。

这时就考虑,让程序更严谨,是不需要对象的。

可以将ArrayTool中的方法都定义成static,直接通过类名调用即可。

将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象。

为了更严谨,强制让该类不能建立对象。

可以通过将构造函数私有化完成。

接下来,将ArrayTool.class文件发送给其他人,其他人只要将该文件设置到classpath路径下,就可以使用该工具类。

但是,很遗憾,该类中到底定义了多少个方法,对方却不清楚,因为该类并没有使用说明书。

 


例:开始制作程序的说明书,java的说明书通过文档注释来完成。

/**

这是一个可以对数组进行操作的工具类,该类提供了,获取最值,排序等功能。

@author 张三

@version V1.1

*/

/**

       获取一个整形数组中的最大值。

       @param arr接收一个Int类型的数组

       @return 会返回一个该数组中最大值

       */

生成java说明书

E:\EditPlus\0622>javadoc -d -author -versionArrayTool.java

正在创建目标目录: "-author\"

正在加载源文件ArrayTool.java...

正在构造 Javadoc 信息...

javadoc: 错误 - 找不到可以文档化的公共或受保护的类。

1 个错误

解决方法:类必须是public修饰的。 


一个类中默认会有一个空参数的构造函数。

这个默认的构造函数的权限和所属类一致。

如果类被public修饰,那么默认的构造函数,也没有public修饰。

默认构造函数的权限是随着类的变化而变化的。 


静态代码块:

格式:

static

{

       静态代码块中的执行语句。

}

特点:随着类的加载而执行,只执行一次。并优先于主函数执行。

用于给类进行初始化的。


静态代码块图例:


黑马程序员——面向对象_第5张图片


Person p=new Person("zhangsan",20);

1、因为new 用到了Person.class,所以会先找到Person.class文件并加载到内存中。

2、执行该类中的static代码块,如果有的话,给Person.class类进行初始化。

3、在堆内存中开辟空间,分配内存地址。

4、在堆内存中建立对象的特有属性,并进行默认初始化。

5、对属性进行显示初始化。

6、对对象进行构造代码块初始化。

7、对对象进行对应的构造函数初始化。

8、将内存地址付给栈内存中的p变量。

 


extends:继承关键字

继承:

1、提高代码的复用性。

2、让类与类之间产生了关系,有了这个关系,才有了多态的特性。

java语言中:java只支持单继承,不支持多继承。

因为多继承容易带来安全隐患:当多个父类中定义了相同的功能,当功能内容不同时,子类对象不确定要运行哪一个。

但是java保留这种机制,并用另一种体现形式来完成表示,多实现。

java支持多层继承,也就是一个继承体系。

如何使用一个继承体系中的功能呢?

想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系中共性功能。

通过了解共性功能,就可以知道该体系的基本功能。

那么这个体系已经可以基本使用了。

那么在具体调用时,要创建最子类的对象,为什么呢?

一是因为有可能父类不能创建对象,二是创建子类对象可以使用更多的内容,包括基本的也包括特有的。

简单一句话就是:查阅父类功能,创建子类对象使用功能。

注意:千万不要为了获取其他类的功能,简化代码而继承;

         必须是类与类之间有所属关系才可以继承,所属关系 is a  


子父类出现后,类成员的特点:

类中成员:

1、变量

2、函数

3、构造函数


1、变量:

如果子父类中出现非私有的同名成员变量时,

子类要访问本类中的变量,用this

子类要访问父类中的同名变量,用super

super的使用和this的使用几乎一致。

this代表的是本类对象的引用

super代表的是父类对象的引用 


2、子父类中的函数

当子类出现和父类一模一样的函数时,

当子类对象调用该函数,会运行子类函数的内容。

如同父类的函数被覆盖一样。

这种情况是函数的另一个特性:重写(覆盖)。

当子类继承了父类,沿袭了父类的功能到子类中,

但是子类虽具备该功能,但是功能的内容却和父类不一致。

这时,没有必要定义新功能,而是使用覆盖特殊,保留父类的功能定义,并重写功能内容。 


覆盖:

1、子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。

2、静态只能覆盖静态。

记住:

重载:只看同名函数的参数列表。

重写:子父类方法要一模一样。


3、子父类中的构造函数

在对子类对象进行初始化时,父类的构造函数也会运行。

那是因为子类的构造函数默认第一行有一条隐式的语句super();

super():会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super();

为什么子类一定要访问父类中的构造函数?

因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。

所以子类在对象初始化时,要先访问一下父类中的构造函数。

如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。

注意:super语句一定定义在子类构造函数的第一行。 


子类的实例化过程:

结论:

子类的所有的构造函数,默认都会访问父类中空参数的构造函数。

因为子类每一个构造函数内的第一行都有一句隐式的super();

当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问的构造函数。

当然:子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数。

例:

黑马程序员——面向对象_第6张图片

 


final:最终,作为一个修饰符

特点:

1、可以修饰类、变量、函数。

2、被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。

3、被final修饰的方法不可以被复写。

4、被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。

       当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便于阅读。

       而这个值不需要改变,所以加上final修饰,作为常量:常量的书写规范所有字母都大写,如果由多个单词组成,单词间通过_连接。

5、内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。 


抽象类

当多个类中出现相同功能,但是功能文体不同。

这是可以进行向上抽取,这时,只抽取功能定义,而不抽取功能文体。 


抽象类的特点:

1、抽象方法一定定义在抽象类中。

2、抽象方法和抽象类都必须被abstract关键字修饰。

3、抽象类不可以用new创建对象,因为调用抽象方法没意义。

4、抽象类中的方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用。

       如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

抽象类和一般类没有太大的不同。

该如何描述事物就描述事物,只不过,该事物出现了一些看不懂的东西。

这些不确定的部分,也是该事物的功能,需要明确出现,但是无法定义主体。

通过抽象方法来表示。

抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。

抽象类不可以实例化。 


特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。


练习:

假如我们在开发一个系统时需要对员工进行建模,员工包括3个属性:

姓名、工号以及工资,经理也是员工,除了含有员工的属性外,另外还有一个

奖金属性,请使用继承的思想设计出员工类和经理类,要求类中提供必要的方法

进行属性访问。

思路:员工类:name id pay

      经理类:继承了员工类,并有自己的特有的奖金属性bonus。

需求:

获取一段程序运行的时间。

原理:获取程序开始和结束的时间并相减即可。

获取时间:System.currentTimeMillis();

当代码完成优化后,就可以解决这类问题。

这种方式,叫做模版方法设计模式。 


什么是模版方法呢?

在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分。

那么这时就将不确定的部分暴露出去,由该类的子类去完成。 


接口

初期理解,可以认为是一个特殊的抽象类。

当抽象类中的方法都是抽象的,那么该类可以通过街道口的形式来表示。

class用于定义类

interface用于定义接口 


接口定义时,格式特点:

1、接口中常见定义:常量,抽象方法。

2、接口中的成员都有固定修饰符

       常量:public static final

       方法:public abstract 


记住:接口中的成员都是public的。

接口:是不可以创建对象的,因为有抽象方法。

需要被子类实现,子类对接口中的抽象方法全部覆盖后,子类才可以实例化。

否则子类是一个抽象类。

接口可以被类多实现。一个类可以实现多个接口。也是对多继承不支持的转换形式,java支持多实现。


接口的特点:

1、接口是对外暴露的规则。

2、接口是程序的功能扩展。

3、接口可以用来多实现。

4、类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

5、接口与接口之间可以有继承关系。 


多态

可以理解为事物存在的多种体现形态。


人:男人、女人

动物:猫、狗 


1、多态的体现

       父类的引用指向了自己的子类对象。

       父类的引用也可以接收自己的子类对象。

2、多态的前提

       必须是类与类之间有关系,要么继承,要么实现。

       通常还有一个前提:存在覆盖。

3、多态的好处

       多态的出现大大的提高了程序的扩展性。

4、多态弊端:

       提高了扩展性,但是只能使用父类的引用访问父类中的成员。

5、多态的应用

6、多态的出现代码中的特点(多态使用的注意事项)


如果想要调用猫的特有方法时,如何操作?

强制将父类的引用转成子类类型,向下转型。

例:


Animal a =new Animal();

Cat c=(Cat)a;

千万不要出现这样的操作,就是将父类对象转成子类类型

我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制解除。

多态自始至终都是子类对象在做着变化。


在多态中非静态成员函数的特点:

在编译时期:参阅引用型变量所属的类是否有调用的方法,如果有,编译成功,如果没有,编译失败。

在运行时期:参阅对象所属的类中是否有调用的方法。


简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。


例:

黑马程序员——面向对象_第7张图片


总结:在多态中,成员变量的特点:

无论编译和运行,都参考左边(引用型变量所属的类)。 


内部类


内部类的访问规则:

1、内部类可以直接访问外部类中的成员,包括私有。

       之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:外部类名.this

2、外部类要访问内部类,必须建立内部类对象。

访问格式:

1、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。

可以直接建立内部类对象。

格式:

         外部类名.内部类名  变量名 = 外部类对象.内部类对象;

         Outer.Inner in=new Outer().new Inner();

2、当内部类在成员位置上,就可以被成员修饰符所修饰。

       比如,private将内部类在外部类中进行封装。

       static:内部类就具备了静态static的特性。

       当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。

 在外部其他类中,如何访问静态内部类的非静态成员呢?

       newOuter.Inner().function();

 在外部其他类中,如何访问静态内部类的静态成员呢?

       Outer.Inner.function();

注意:当内部类中定义了静态成员,该内部类必须是静态的。

         当外部类中的静态方法访问内部类时,内部类也必须是静态的。

当描述事物时,事物的内部还有事物,该事物用内部类来描述。

因为内部事务在使用外部事务的内容。


内部类定义在局部时:

1、不可以被成员修饰符修饰。

2、可以直接访问外部类中的成员,因为还持有外部类中的引用。

       但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量。 


匿名内部类:

1、匿名内部类其实就是内部类的简写格式。

2、定义匿名内部类的前提:

       内部类必须是继承一个类或者实现接口。

3、匿名内部类的格式:new 父类或者接口() {定义子类的内容}

4、其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。可以理解为带内容的对象。

5、匿名内部类中定义的方法最好不要超过3个。

例:

Test.function():Test类中有一个静态方法

function.method():function()这个方法运算后的结果是一个对象,而且是一个Inter类型的对象因为只有是Inter类型的对象,才可以调用method方法。

Test.function().method();


 



你可能感兴趣的:(黑马技术博客)