前期准备01-2.1
一、程序的流程控制语句
①判断结构(if)
格式:
❶if(条件表达式)
→{条件表达式为true,执行此语句;}
❷if(条件表达式)
→{条件表达式为true,执行此语句;}
→else
→{条件表达式为false,执行此语句;}
❸if中嵌套if或者else中嵌套if
❹if-else结构,有时可以简写为三元运算符,如:变量 = 三元运算符;好处是,可以简化代码;局限性是,运算必须要有结果。
②选择结构(switch)
格式:
switch(表达式)
{
→case 取值1:
→→→→执行语句;
→→→→break;
→case 取值2:
→→→→执行语句;
→→→→break;
→default:
→→→→执行语句;
→→→→break;
}
❶switch语句中的表达式的值只能是四种类型:byte,short,int,char。
当表达式的值满足了某个case的取值时,将在此处一直向下执行,直至遇到break或者switch语句结束。
❷多个case可以共同执行一条语句,如判断季节;case之间也可以没有顺序,可以任意排列,只是先执行第一个。
❸default语句后加了break,就可以放在switch语句的任意位置;如果default语句后没有加break,当它后面还有属于switch语句的代码时,执行到它之后,还会继续向下执行,一直到switch语句结束或者遇到break为止。
❹if的使用范围更广,switch适合判断具体数值不多,且数值属于byte,short,int,char四种类型的情况,效率更高一些,代码更直观。
③循环结构(while,do-while,for)
❶while语句
格式:
while(循环条件表达式)
{循环体(参与循环的语句);}
注意:while()后没有分号,否则while一旦被执行就会进入无限循环。
❷do-while语句
格式:
do
{循环体(参与循环的语句);}
while(循环条件表达式);
注意:while()后有分号。
其特点是:无论条件是否满足,循环体至少被执行一次。也可以在循环体中,再加上条件判断(可以使用if语句),来控制循环体的执行。
❸for语句
格式:
for(初始化表达式;循环条件表达式;循环后要操作的表达式)
{循环体(参与循环的语句);}
当初始化表达式中有多个表达式时,用逗号隔开;循环后要操作的表达式中有多个表达式时,用逗号隔开。
for语句中各表达式的执行顺序:初始表达式只执行一次,然后判断循环条件,为true就执行循环体,然后再执行循环后要操作的表达式,接着继续判断循环条件,一直重复这个过程,直到条件不满足为止,结束循环。
while与for可以互换,区别在于for为了循环而定义的变量在for循环结束后,就在内存中释放了,而while循环使用的变量在循环结束后还可以继续使用。如果参与循环的变量不被外部使用,用for更合适。
最简单无限循环格式:while(ture){},for(;;){}
for的嵌套循环可以控制有规律的二维空间。
④关键字break(跳出)
break可以跳出选择语句(switch),循环语句(while、do-while、for)。
⑤关键字continue(继续)
continue应用于循环语句中(while、do-while、for)。表示只结束本次循环,继续执行下一次循环。
注意:break和continue离开了应用范围,其存在是没有意义的。当这两个语句单独存在时,其下面的语句将执行不到。标号(标记名:)可以让这两个语句能够作用于标号所指定的范围。
二、函数(即方法)
①函数的定义
❶函数就是定义在类中的具有特定功能的一段小程序。
❷函数的格式:
修饰符 返回值类型 函数名(参数类型 形式参数1,...)
{
→执行语句;
→return 返回值;
}
修饰符:限定函数的访问权限;标明函数的状态。
返回值类型:函数运行后所得结果的数据类型,函数可以没有返回值,用void修饰。
参数类型:是形式参数的数据类型。
形式参数:是一个变量,用于存储函数调用者传递给函数的实际参数。函数可以是空参数函数。参数是有顺序的,应用于函数的重载。
实际参数:传递给形式参数的具体数值或引用,参与函数功能的实现。
return:用于结束函数,若需要则传递返回值给该函数的调用者。
返回值:该值会返回给函数的调用者。用void修饰的函数没有返回值。
②函数的特点
❶可以将功能代码进行封装
❷方便功能的复用
❸只有在被调用时才被执行
❹函数的出现提高了代码的复用性
❺对于函数没有具体返回值的情况,返回值类型用void表示,这时该函数的return语句如果是在最后一行,就可以省略不写。
注意:函数只能调用函数,不可以在函数内部再定义函数。
③函数的应用
程序中实现应用功能的最小单元即为函数,函数的功能就是对实际应用的一种抽象和提取,它可以使得对实际应用的操作更加高效。
④函数的重载
在同一个类或子父类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型或者参数的排列顺序不同即可(函数同名,参数不同)。
❶重载的特点:
与返回值类型无关,只看参数列表。参数是有顺序的。
❷重载的好处:
方便于阅读,优化了程序设计。
三、数组
①数组的定义
数组就是一个集合或者容器,用于存放同一种类型的数据。
❶数组的好处:可以自动给数组中的元素从0开始编号,方便对数组中各个元素的操作。数组中的第i个元素为:数组名[i-1]。
❷数组中的元素可以是基本数据类型,也可以是引用数据类型。
②数组的格式:
数据类型[] 数组名 = new 数据类型[元素个数(即数组长度)];
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
对于数组的两种显式初始化方式,定义了数组的长度就不能再罗列数组中的元素,反之亦然。
❶数组名作为一个变量存在于栈内存中,离开其使用范围即被自动释放。
❷数组中的元素,存在于堆内存中,当其不被引用时,只能依靠垃圾回收机制才能被释放掉。
❸数组名的取值,是数组元素在堆内存中存放的首地址,数组名只是一个引用变量,当其离开作用范围或者通过对其赋值null,可以让它结束引用,使得其之前的引用数据变为垃圾(只是在堆中数据被单引用时生效)。
③数组的操作
获取数组中的各个元素的值,要使用遍历,通过循环语句实现。
❶选择排序
从数组的第一个元素开始,将当前位置上的值,同其之后的每一个值进行比较,将符合条件的值换位到当前位置,然后从第二个元素开始再次循环操作,直至数组的最后一个值,完成对数组中各个元素的排序。
对于选择排序,数组中的第一个位置上的值,最先完成排序动作。
❷冒泡排序
从数组的第一个元素开始,将当前位置上的值,同后面的第二个元素的值相比较,符合条件即换位,然后将第二个元素的值同其后面的值相比较,符合条件再次换位,以此类推,一直比到数组的最后一个元素;然后从数组的第一个元素开始,再次循环操作。每次循环都比前一次少比较一个元素的值,即经过前一次比较之后的最后一个元素,直至操作到只剩第一个元素为止。
对于冒泡排序,数组中的最后一个位置上的值,最先完成排序动作。
❸排序相关知识点
排序中都会涉及到换位操作,可以将此操作封装成一个函数。
数组排序:
java.util.Arrays.sort(object[] a)
(['dʒa:və][ju'til][ə'reiz][sɔ:t]['ɔbdʒikt])
根据元素的自然顺序,对指定的对象数组中的元素,按升序进行排序。要保证数组中的所有元素都是可相互比较的。
❹折半查找
通过移动数组中最小角标和最大角标的位置,来判断数组中不断变化的中间角标位的值,是否与所查找的元素相等,从而实现查找的功能。
折半查找返回角标值为-1时,表示数组中没有此元素,因为数组的角标最小是0。
折半查找可以提高效率,但是要求数组必须是有序的。
④二维数组
数组中的元素依然是数组。
格式:
❶元素类型[][] 数组名 = new 元素类型[m][n];
此数组中有m个一维数组元素,每个一维数组中有n个值。
❷元素类型[][] 数组名 = new 元素类型[m][];
此数组中有m个一维数组元素,每个一维数组默认初始化为null。可以分别给每个一维数组进行显式初始化,如:a[i]=new int[j]。
⑤定义数组时需要注意的地方:
一维数组:int[] x;int x[]
二维数组:int[][] x;int x[][];int[]x[]
四、面向对象
面向对象是相对于面向过程而言的。面向过程强调的是功能、行为;面向对象将功能封装进对象内部,强调具备了功能的对象。面向对象是基于面向过程的。
①类与对象的关系:
类是一种描述,是一个概念,是抽象的。
对象是一个实际存在的个体,是类的实现,是物质的。
类决定了对象的属性和功能,对象丰富了类的表现形式。
类中的成员变量决定对象的属性,随着对象的创建而实现(静态成员变量在数据区中,非静态成员变量在堆内存中);类中的成员函数决定对象的功能,需要对象的调用才能实现,存在于方法区(共享区、数据区)中。
②创建对象:
一个类,只有创建了对象,才能实现具体功能,才有其存在的意义。
格式:
类名 对象名(标示符) = new 类名();
❶一个类可以创建无限多个对象,每一个对象的生命轨迹,可以自由书写。
❷对象名是一个引用型变量,属于类类型,它指向该类的一个对象,这个对象的属性(非final型)的取值是可以变化的,功能的实现是可以选择的。
❸匿名对象:当对一个对象只是被使用一次时,可以使用匿名对象;匿名对象可以作为实际参数,进行值的传递。
五、面向对象的三大特征之一:封装
①封装的定义:
封装是指隐藏对象的属性和实现细节,仅对外提供公共访问的方式。
②封装的好处:
将变化隔离,便于使用,提高复用性,提高安全性。
③封装的原则:
❶将不需要对外提供的内容都隐藏起来。
❷把所有的属性都隐藏起来,只对外提供公有方法对其进行访问。
④封装的实现:
对象是对类的实现,是对类中的成员变量和成员函数的实现。把对象的属性和实现细节隐藏,就是把类中的成员变量和成员函数隐藏。对类中的成员甚至类本身进行隐藏,使用的是可以限制访问权限的修饰符。
❶权限修饰符private:
私有的,用于修饰类的成员(包括成员变量、成员函数和内部类),私有之后的成员,只能被本类中的成员所访问。
私有只是一种表现形式,若是私有成员有必要被外部访问,可以向外部提供能够访问内部私有成员的公有的方法。通过该方法,来判断外部的访问是否合理,合理即允许访问,不合理即不允许访问。公有方法的功能,是可以进行逻辑判断,提高了代码的健壮性。
❷其它权限修饰符:public(公有)、protected(保护)
六、构造函数
①构造函数的特点:
函数名与类名相同,不用定义返回值类型,不可以写return语句。
相对于每个不同的对象而言,其自身的构造函数只被执行一次。
②构造函数的作用:
给对象进行初始化,包括对象的属性和对象的功能。对象一被创建,就会调用与之对应的构造函数。
③默认构造函数:
❶若是类中没有定义构造函数,系统会自动添加一个无参数的构造函数,即:类名(){}。
❷若是类中定义了构造函数,则系统就不再自动添加。
❸当类中定义了非空参数的构造函数,一般还要再定义一个空参数的构造函数。因为,当此类被其子类继承时,其子类的所有构造函数中,都会默认包含一个父类的空参数构造函数。
❹默认构造函数的权限和所属类的权限保持一致,其权限随着类权限的变化而变化。当然,可以做显式的修改。
④构造函数的重载:
多个构造函数的存在,是以函数重载的形式完成的。它们决定了不同对象的创建,可以拥有不同的初始化属性。
⑤构造代码块:
❶格式:
{需要执行的代码;}
❷作用:
给对象进行初始化。对象一被创建就会运行,而且优先于构造函数执行。构造代码块中定义的,是不同对象所共性的初始化内容。
❸构造代码块和构造函数的区别:
构造代码块是给所有对象进行统一的初始化,而构造函数是给其所相对应的对象进行初始化;构造代码块的执行顺序在构造函数之前。
⑥构造函数的私有化
❶构造函数是可以被私有化的,当一个类中的所有的构造函数都被私有化后,该类就不能够被外部的程序创建它的对象了。
❷单例设计模式,应用了构造函数的私有化,并在类中自己创建了一个唯一的对象,供外部使用(饿汉式、懒汉式)。
❸工具类中的构造函数都是私有的。工具类中的函数都是静态的,可以由类名直接调用,没有创建对象的必要性。
⑦关键字this:
含义有两个:一是调用当前实例对象;二是调用本类的另一个构造函数。
this的应用:
❶当定义成员函数时,函数内部要用到调用该函数的对象,就用this来代表这个对象。也用于区分同名的成员变量和局部变量。
❷一个类中的成员被使用,都必须要有对象调用才可以。有好多的地方,由于是在本类中的调用,从而省略了this,但它必然存在。尤其是,在多态的应用中,极其重要。
❸在构造函数中调用本类的另一个构造函数时,this一定要放在该构造函数的第一行,被优先执行。
七、静态
①关键字static:
用于修饰类的成员(包括成员变量、成员函数和内部类)。
②静态的特点:
❶被static修饰的成员随着类的加载而加载,优先于对象而存在,被该类的所有对象所共享。
❷当类中的成员被静态修饰后,除了可以被本类的对象调用之外,还可以被类名直接调用。
❸静态成员只能访问静态成员。
❹静态方法只能覆盖静态方法。
③类变量和实例变量的区别:
❶存放位置不同
类变量(即静态的成员变量),存储在方法区(共享区、数据区)中,实例变量(即非静态成员变量),随着对象的创建而存在,存储在堆内存中。
❷生命周期不同
类变量的生命周期最长,随着类的消失而消失;实例变量的生命周期,随着对象的消失而消失。
④静态修饰符使用的注意事项:
❶静态方法只能访问静态成员;非静态方法既可以访问静态成员,也可以访问非静态成员。
❷静态方法中不可以使用this、super关键字,因为静态优先于对象而存在。
⑤静态的利弊:
❶好处
将对象的共享数据进行单独存储,节省内存空间;可以被类名直接调用。
❷弊端
对于成员变量,生命周期过长;对于成员函数,其内部只能访问静态成员,访问有局限性。
⑥静态的定义规则:
❶对于类变量,当所有的对象中出现共有数据时,该数据应该被静态修饰,存储于方法区(共享区、数据区)中。而实例变量,是每个对象特有的数据,要定义成非静态,存在于堆内存中。
❷对于成员函数,当功能内部没有访问到非静态数据(对象的特有数据)时,该方法可以定义为静态的。若是访问到了非静态数据,就不可以定义为静态的。
⑦静态代码块:
格式:static{需要执行的语句;}
特点:随着类的加载而执行,只执行一次,并且优先于主函数。
作用:用于给类进行初始化。
⑧静态的应用-工具类:
工具类,即为了完成某些特定的功能,而将这些作用相同的功能进行封装的类。
❶工具类中的方法都是静态的,可以通过类名直接调用。工具类中的构造方法都是私有的,因为用类名就可以实现对象所具有的功能,没有创建对象的意义。
❷将工具类中的构造函数私有化,可以统一工具类的调用方式,更加严谨。
八、主函数:
主函数是一个特殊的函数,是静态的。作为程序的入口,被JVM识别并调用。
①主函数的定义:
public:代表着主函数的访问权限是最大的。
static:代表主函数随着类的加载已经存在了。
void:代表主函数没有具体的返回值。
main:不是关键字,但作为一个特殊的单词,可以被JVM识别。
(String[] args):主函数的参数列表,参数的类型是一个字符串类型的数组,该数组中的元素是字符串。
②主函数的识别:
❶主函数的格式,是固定的。
❷JVM只识别固定参数列表的主函数,将其作为程序的入口。
❸拥有不同参数列表的其它同名函数,能够以函数重载的方式与主函数同时存在,但不能被JVM识别。
③主函数的调用:
❶JVM在调用主函时,传入的是一个字符串类型的数组(new String[0])。
❷因为主函数是静态的,可以在程序运行的同时,向主函数中传值。
❸主函数会将收到的数据,封装和存储进其自身的数组中,并以数组角标的形式,为每一个传入的元素进行标号。主函数的数组长度,由所传入的数据决定,其格式为:java 函数名 字符串 字符串 ...
④对象的初始化过程:
当用new关键字创建了一个对象之后,系统会对其进行相应的初始化。
类名 对象名 = new 类名();
❶先在内存中加载其对应的类的字节码文件(类名.class)
❷执行该类的static代码块,给类进行初始化
❸在栈内存中给对象名变量分配空间
❹给栈内存中的对象名进行默认初始化,赋值null
❺在堆内存中开辟空间,分配内存地址
❻在堆内存中建立对象的特有属性,并进行默认初始化
❼给对象的特有属性进行显示初始化
❽执行该类的构造代码块,给对象进行共有属性的初始化
❾给对象进行其所对应的构造函数初始化
❿将对象在堆内存中的首地址,赋值给栈内存中的对象名,实现引用
⑤对象的调用过程:
❶对象调用的过程,是在栈内存中完成的
❷对象调用的实现,是在堆内存中完成的
❸对于静态成员变量,对象在栈内存中的引用,指向对象在堆内存中的实体,堆内存中的实体有相应的引用,指向方法区中的目标数据,从而实现调用。
❹对于非静态成员变量,对象在栈内存中的引用,指向对象在堆内存中的实体,堆内存中的实体直接调用,存在于堆内存中的自身的相应的变量,从而实现调用。
❺对于成员函数,与静态成员变量的调用方式相同。
❻每一个线程都会有一个方法调用栈,用来跟踪该线程运行中的一系列的方法调用过程。栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候,就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。
九、Java文档注释的编写:
Java中的注释有三种:
//:单行注释
/*(被注释的信息)*/:多行注释
/**(被注释的信息)*/:Java文档注释专用
注释的特性:多行注释只可以嵌套单行注释,不可以嵌套多行注释。
①Java注释文档的制作前提:
若要制作一个类的注释文档,则该类必须是共有的,才能够向外暴露其内部的功能。
②Java文档注释的作用:
对程序的功能进行说明,方便程序开发者使用该程序的功能。
③Java文档注释的格式:
❶将该程序的所有功能,作者信息,版本信息等放在类的前面。
@author:作者信息
@version:版本信息
❷将该类中各个方法的具体功能,所需要传递的参数列表的形式,返回值类型等放在方法的前面。
@param:各个参数的说明
@return:返回值说明
④注释文档的生成方法:
运行:javadoc -d 指定文件的存放目录 类的源文件全名
❶如果需要生成作者和版本信息,需要在-d后面单独添加-author、-version,各个字段间用空格隔开。
❷如果磁盘中没有指定的目录,则系统会自动新建一个。
⑤注释文档的生成规则:
❶在程序中编写的注释文档,系统只会抽出被public和protected修饰的部分,其它部分不会被抽取。
❷默认构造函数的权限和所属类的权限保持一致,其权限随着类权限的变化而变化。
十、单例设计模式
设计模式的意义:解决某一类问题最行之有效的方法。
Java中有23种设计模式。
①单例设计模式:
解决一个类在内存中,只存在一个对象的问题。
②单例设计的规则:
❶将构造函数私有化。
❷在类中创建一个静态的本类对象。
❸提供一个公有并且静态的方法,可以让外部获取到这个对象。
③单例设计的实现方法:
❶饿汉式
该类一被加载,就创建一个对象。
特点:安全,方便。
❷懒汉式
当该类的方法被外部调用时,才创建对象,也叫做对象的延时加载。
特点:在多线程时,为了解决安全问题,要使用双重判断,并且在第二次判断之前,加上同步。效率比较低,因为判断即会消耗资源。
④单例的好处:
❶内存中只有一个对象,节省系统开销。
❷实现了本类对实例化的有效控制。
十一、面向对象的三大特征之一:继承
①继承的由来:
对类的描述的不断抽取,可以形成更加抽象的类;反之,对类的描述的不断扩展,可以形成更加具象的类。
②继承的特点:
❶提高了代码的复用性。
❷让类与类之间产生了关系,实现了程序的多态性。
❸不能为了获取其它类的功能,为了简化代码而继承。必须是类与类之间有所属关系,才可以继承。所属关系即is a。
③关键字extends:
继承,表示一个类是另一个类的子类。
❶Java只支持单继承,也支持多实现。
❷Java支持多层继承,也就是一个继承体系。
❸若要使用某个体系,应先查阅父类的描述,因为父类中定义的是该体系中的共性功能。在使用这些功能时,要创建最子类的对象,原因有两个:一是有可能父类不能创建对象;二是创建子类对象可以使用更多的功能,包括共性的功能,也包括特有功能。(即查阅父类功能,创建子类对象使用功能)
④关键字super:
含义有两个:一是表 示父类对象的引用;二是调用父类的构造函数。
❶子类中的所有的构造函数都默认包含一个父类的空参数构造函数,即super()。
❷使用super调用父类的构造函数时,一定要放在子类构造函数的第一行,被优先执行。
❸在子类构造函数中,super与this不能同时存在。
❹若要子类构造函数调用父类的非空参数构造函数,需要显式指定。
⑤函数的覆盖(重写):
子父类中出现了同名函数,子类直接调用自身的方法,父类的方法就被隐藏了起来,如同父类的方法被覆盖(重写)。
❶覆盖的意义:
子类拥有父类的功能,却有与父类不同的实现方式,这时就保留父类功能的定义,重写父类功能的内容。
❷覆盖的应用:
可以用于功能的扩展。
❸覆盖的前提:
子类覆盖父类,必须保证子类权限不小于父类权限;静态只能覆盖静态。
❹覆盖的格式:
子父类函数的定义要一模一样,包括修饰符、函数名、参数列表。
⑥子类的实例化过程:
❶系统在加载子类之前会先加载其父类,并逐级上溯。
❷子类对象在创建时,会先加载父类的内容,再加载自己的内容,包括静态代码块、构造代码块、构造函数。子父类的内容同时存在。
⑦关键字final:
含义是最终,可以修饰变量(包括成员变量和局部变量)、函数和类。表示变量只能被赋值一次,之后以常量的形式存在;表示方法不能被重写;表示类不能有子类。
❶内部类被定义在局部位置上时,只能访问被final修饰的局部变量。
❷final的应用:
当描述事物时,有一些数据的值是固定的,为了增强阅读性,都会给这些值起个名字,然后用final修饰,如:final PI=3.1415926;。
⑧抽象类:
❶关键字abstract:
抽象方法、抽象类的修饰符。抽象的方法没有方法体,直接以分号结尾。只要该类中有一个抽象的方法,则该类必须声明为抽象类。抽象类不能用new创建对象。抽象类中可以没有抽象的方法,只是用来限制该类不能够创建对象。
❷抽象类中功能的实现方式:
抽象类只有被其子类继承,并且将其所有的抽象方法都覆盖之后,通过创建其子类的对象,来调用子类自身的方法,从而实现该抽象类的功能。
❸抽象类的应用:
当在描述事物时,如果出现了有明确的功能,却拥有不确定的实现方式时,就可以通过定义抽象类来进行描述。
抽象类可以强制其子类必须覆盖它的抽象方法,否则无法创建对象。
❹模板设计模式:
当定义功能时,功能的一部分是确定的,但是有一部分是不确定的,而且确定的部分在使用不确定的部分。那么,就可以将不确定的部分以抽象的方式暴露出去,由该类的子类去完成。
⑨接口:
可以理解为,接口是一种特殊的抽象类。接口中的所有方法都是抽象的,同时,接口中只有常量。
❶关键字interface:
用于定义接口,功能同class。接口中的常量(全局常量)和方法都有固定的格式,若是修饰符出现空缺,系统会为其自动补齐。
常量:public static final 数据类型 常量名=常量值;
方法:public abstract 返回值类型 方法名(参数列表);
❷关键字implements:
用于实现接口,功能同extends(is a)类似,可以理解为:like a。
一个类可以多实现,也可以在继承的同时再多实现,多实现时各个接口间以逗号隔开。若是子类中没有将接口中的抽象方法全部覆盖,则此类是一个抽象类。
接口与接口间是继承关系,可以多继承。接口的多继承会有风险,有可能会包含返回值不同的同名函数,此时编译会失败。
❸实现与继承的区别:
继承表示子类必须是父类中的一员,实现表示子类可以拥有接口的功能,不是必须的。继承是一个体系,接口是一种扩展。
❹接口的特点:
接口是对外暴露的规则(降低了耦合性);接口是程序的功能扩展;接口可以被多实现;接口间可以多继承。
十二、面向对象的三大特征之一:多态
多态,可以理解为事物的存在拥有多种表现形态。
由于继承的存在,可以让事物从属于一个体系。这个事物本身既是一个特殊的个体,又是其所属体系中的一个成员,从而可以拥有多种表现形态。
①多态的体现:
❶将父类的引用指向子类的对象,或者说父类的引用可以接收子类的对象。
❷函数中也存在多态,函数的重载和重写(覆盖),就是同名函数拥有不同的表现形式,也是一种多态的体现。
②多态的前提:
类与类之间有关系,要么继承,要么实现。
③多态的好处:
提高了程序的扩展性和后期的可维护性。
④多态的弊端:
❶父类的引用只能访问父类的成员。
❷调用时,对于成员变量和静态成员函数,指向的是父类的数据;对于非静态成员函数,调用的是子类的非静态成员函数(存在函数覆盖的就调用子类的成员函数,没有被覆盖的成员函数子父类共享)。
⑤多态中对象的类型转换:
❶当父类引用指向子类对象时,子类对象会被系统自动提升为父类的类型,即向上转型。
❷若想将被提升了类型的子类对象还原成自己的类型,需要进行强制转换,即向下转型。
❸引用数据类型的转换方式,与基本数据类型的转换方式相同。
❹不能够将一个父类对象强制转换成它的子类的类型。
❺不能够将一个非本类类型的对象,转换成本类的类型。
❻对于多态而言,其时自始至终都是子类对象在做类型的转换。
⑥关键字instanceof:
测试一个对象是否是某个类的实例。
❶当判断一个对象是否属于某个类时,若是需要多重判断的话,应将最抽象的类(该体系中最父类的类)写在最后面。
❷instanceof一般应用于两种情况下:一是子类的类型是有限的;二是只使用有限的子类类型。
⑦多态中的非静态成员函数的特点:
❶在编译时期,参阅引用型变量所属的类中,是否有被调用的方法,如果有则编译通过,如果没有则编译失败。
❷在运行时期,执行对象所属的类中,该对象自己的方法。
❸非静态成员函数在多态中调用时,编译看左边,运行看右边。也就是说,编译看父类,运行用子类。
⑧多态中的静态成员函数的特点:
无论编译还是运行,都看左边。因为,静态随着类的加载而加载,只要父类的引用还在,则必指向父类的静态成员函数。
⑨多态中成员变量的特点:
无论编译还是运行,都看左边(引用型变量所属的类,即父类)。
⑩多态的应用:
当接口实现多态时,既可以实现接口自身的功能扩展,又可以实现其调用者的程序扩展。
⑪Object['ɔbdʒikt]类:
Object类是类层次结构的根类。每个类都使用Object作为超类。所有对象(包括数组)都可以实现这个类的方法。
调用Object类中的方法,也是多态应用中的一种。
❶equals['i:kwəlz]方法:
public boolean equals(Object obj)
比较其它某个对象是否与此对象相等,对于引用对象比较的是地址值。
通常一个类会对Object类的equals方法进行覆盖,但是,如果比较中用到了该类中的特有数据,那么就需要进行类型判断以及类型转换(向下转型)才可以继续比较。
❷toString['tu:ˌstriŋ]方法:
public String toString()
返回该对象的字符串表示形式(类名@哈希值)。
其另一表现形式为:
getClass().getName()+’@’+Integer.toHexString(hashCode())
(['getˌkla:s]['getˌneim][æt]['intidʒə]['tu:ˌheks][striŋ]['hæʃˌkəud])
通常一个类会对Object类的toString方法进行覆盖,返回自己定义的表示信息,便于理解。
❸getClass方法:
public final Class<?> getClass()
返回此对象运行时该类的Class对象。该类的Class对象是由表示该类的static synchronized方法锁定的对象,即该类的字节码文件。
返回形式为:Class 类名
Class<T>:T表示由此Class对象建模的类的类型,即类名。
例如:String.class的类型是Class<String>。如果将被建模的类未知,则使用Class<?>。
❹hashCode方法:
public int hashCode()
返回该对象的哈希码值。一般是通过将该对象的内部地址转换成一个整数来实现的。
❺wait方法(只用于同步)
public final void wait()
throw InterruptedException([intə'rʌptid][ik'sepʃn])
当前线程等待,一直持续到到其它线程调用此对象的notify()方法或者notifyAll()方法。
如果当前线程在等待通知之前或者正在等待通知时,任何线程中断了当前线程,抛出中断异常。
当前线程必须拥有此对象监视器(即同步锁)。
❻notify(['nəutifai])方法(只用于同步)
public final void notify()
唤醒在此对象监视器(同步锁)上等待的单个线程。如果所有线程都在此监视器(同步锁)上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。
❼notifyAll方法(只用于同步)
public final void notifyAll()
唤醒在此对象监视器(同步锁)上等待的所有线程。