-------android培训、java培训、期待与您交流! ----------
面向对象
面向对象是相对面向过程而言的。
面向对象和面向过程都是一种思想。
面向过程:强调的是功能行为。
面向对象:将功能封装进对象,强调了具备功能的对象。
面向对象是基于面向过程的。
面向对象是一种符合人类思维习惯的编程思想,现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
面向对象是一种思想,它能让复杂的问题简单化,能让我们得角度进行转变,从执行者变为指挥者 。
人开门:名词提炼法
人
{ 开门 (门)
{ 门。开};}
门
{ 开() {操作门轴等。}}
面向过程和面向对象图例:
面向对象有三个特征:封装、继承、多态。
面向对象的特点:
以后开发,就是找对象使用,没有对象就自己建立一个对象使用。
找对象,建立对象,使用对象,并维护对象的关系。
类和对象的关系:
类:就是对现实生活中事物的描述。
对象:就是这类事物实实在在存在的个体。
现实生活中的对象:张三、李四
想要描述:提取对象中共性内容,对具体的抽象。
描述时:这些对象的共性有姓名、年龄、性别、学习JAVA的功能。
映射到JAVA中,描述就是class定义的类。
具体对象就是对应JAVA在堆内存中用new建立实体。
例:
需求:描述汽车(颜色,轮胎数),描述事物其实就是描述事物的属性和行为。
成员变量和局部变量:
作用范围:
成员变量:作用于整个类中
局部变量:作用于函数中,或者语句中。
在内存中的位置:
成员变量:在堆内存中,因为对象的存在,才在内存中存在。
局部变量:存在栈内存中。
匿名对象
匿名对象是对象的简化形式。
匿名对象两种使用情况:
1、当对对象方法仅进行一次调用时。
2、匿名对象可以作为实际参数进行传递。
匿名对象使用方法之一:当对对象的方法只调用一次,可以用匿名对象来完成,这样写比较简化。
如果一个对象进行多个成员调用,必须给这个对象起个名字。
匿名对象使用方法之二:可以将匿名对象作为实际参数进行传递。
封装
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
将变化隔离。
便于使用。
提高重用性。
提高安全性。
封装原则:
将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。
Private(私有)关键字
Private是一个修饰符。用于修饰成员(成员变量和成员函数),被私有化的成员只在本类中有效。
常用之一:将成员变量私有化,对外提供对应的set ,get方法对其进行访问,提高对数据访问的安全性。
注意:私有仅仅是封装的一种表现形式。
Private 图例:
构造函数
特点:
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);//用于构造函数间的调用。
例:
这种调用是不允许存在的,是死循环。
静态:static
用法:是一个修饰符,用于修饰成员(成员变量和成员函数)。
当成员被静态修饰后,就多一个调用方式,除了可以被对象调用外,还可以直接被类名调用 类名.静态成员
static特点:
1、随着类的加载而加载
也就是说:静态会随着类的消失而消失,说明它的生命周期最长。
2、优先于的对象存在
明确一点:静态是先存在的,对象是后存在的。
3、被所有对象所共享
4、可以直接被类名所调用
实例变量和类变量的区别:
1、存放位置
类变量随着类的加载而存在于方法区中。
实例变量随着对象的建立而存在于堆内存中。
2、生命周期
类变量生命周期最长,随着类的消失而消失。
实例变量生命周期随着对象的消失而消失。
静态的使用注意事项:
1、静态方法只能访问静态成员。非静态方法即可以访问静态也可以访问非静态。
2、静态方法中不可以定义this、super关键字,因为静态优先于对象存在,所以静态方法中不可以出现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
{
静态代码块中的执行语句。
}
特点:随着类的加载而执行,只执行一次。并优先于主函数执行。
用于给类进行初始化的。
静态代码块图例:
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语句来访问本类中的构造函数,子类中至少会有一个构造函数会访问父类中的构造函数。
例:
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;
千万不要出现这样的操作,就是将父类对象转成子类类型
我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制解除。
多态自始至终都是子类对象在做着变化。
在多态中非静态成员函数的特点:
在编译时期:参阅引用型变量所属的类是否有调用的方法,如果有,编译成功,如果没有,编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
例:
总结:在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
内部类
内部类的访问规则:
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();