面向过程学习
1.基本数据类型学习
在Java中数据有两大类:基本数据类型和引用数据类型。就基本数据类型而言其中又分成了好多小类,其中包含整数类型,浮点数类型(也就是我们传统上的小数类型),字符类型,布尔类型。其中整数类型又分为byte类,short类,int类,long类。浮点数类型又分为float类和double类,他们的本质区别就在于可取到的范围不同。
不同类型的取值范围都在表格中一一列举。
2.运算符学习
(1)运算符基本概念
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
主要有:
算术运算符:“+”(加) “-”(减) ”*“(乘) ”/“(除)”%“(取余数)
赋值运算符:
- ”=“(赋值): a=10 将10赋值给a。
- ”+=“(加后赋值):a+=b 将a+b的值赋值给a。
- ”-=“(减后赋值):a-=b 将a-b的值赋值给a。
- ”/=“(除后赋值):a/=b 将a/b的值赋值给a。
- ”*=“(乘后赋值):a×=b 将a×b的值赋值给a。
- ”%=“(取余数后赋值):a%=b 将a%b的值赋值给a。
逻辑运算符:
1.”&“(逻辑与):”&“的左右两边都为真则结果为真,左右两边都需要进行判断真假
2.”|“(逻辑或):”|“的左右两边全为假则结果为假,左右两边都需要判断真假
3. ”^"(逻辑异或):两边相同则为假,两边不同则为真
4.”!”(逻辑非):取反
5.“&&”(短路与):其左右两边都为真则结果为真,若左侧为假则不需要再对右侧进行判断
6.“||”(短路或):其左右两边都为假则结果为假,若左侧为真则不需要在对右侧进行判断
三目运算符:
(关系表达式)?(表达式1):(表达式2)
若关系表达式为真则执行表达式1,若为假则执行表达式2
(2) 数据转换的两种方式
在Java中有隐式转换和强制转换两种数据转换方式,如果我们要进行数据的基本计算的时候,只有类型相同的数据才可以直接计算,如:byte类和byte类计算,int类和int类进行计算,double类和double类进行计算。那么如果我们想要用int类和double类进行计算时难道就行不通了吗?事实并非如此。要想解决这个问题,首先我们要了解隐式转换。
所谓隐式转换就是Java会自动把取值范围小的类型转换为取值范围大的类型。那么接下来就需要根据取值范围对各种数据类型进行排序:
byte < short < int < long < float < double
因此在对int类和double类进行计算时,计算机就会先把int类的数据自动提升为double类型的数据,再对double类和double类进行计算。
那么我们有什么办法能将int类和double类的计算结果成为int类的呢?这就需要我们了解强制转换。
所谓强制转换就是将取值范围大的数据类型强制转换为取值范围小的数据类型,这需要我们进行手动更改,在需要输出的结果前添加(int)。如代码形式:
输出结果为:
综上所述,隐式转换是计算机自动提升数据类型,将计算结果按所有参与计算的数据类型中取值范围最大的数据类型进行输出。强制转换需要我们手动将取值范围大的数据类型强制转换为取值范围小的数据类型,需要在输出结果前添加(取值范围较小的数据类型)。
(3) 字符串拼接操作
字符串的拼接操作需要用到算数运算符“+”进行拼接。当“+”操作中出现字符串时,计算机会将前后的数据从左到右进行拼接,并产生一个新的字符串:
注意1:只要在”+“运算符的左右出现字符串就是字符串的拼接操作而非运算操作。
注意2:并非输出中只要有字符串就要将所有的数据进行拼接操作,如下:
(4) 自增自减
当我们想要实现+1操作时,不仅可以通过a+=1或a=a+1实现,还可以通过a++实现。
对于自增,我们有a++或++a两种方式,对于a++是先进行运算再实现a+1,而对于++a是先进行a+1操作再将a带入运算中,例如:
对应的,a–和–a实现a=a-1的操作,但a–先将a带入运算再实现a-1的操作,而–a则是先实现a-1的操作再将a带入运算
(5) 赋值运算符
- ”=“(赋值): a=10 将10赋值给a。
- ”+=“(加后赋值):a+=b 将a+b的值赋值给a。
- ”-=“(减后赋值):a-=b 将a-b的值赋值给a。
- ”/=“(除后赋值):a/=b 将a/b的值赋值给a。
- ”*=“(乘后赋值):a×=b 将a×b的值赋值给a。
- ”%=“(取余数后赋值):a%=b 将a%b的值赋值给a。
(6) 关系运算符
1.“==”(相等):判断两个式子是否相等,成立为true,不成立false
2.“!=”(不等):判断两个式子是否不等,若成立则为true,不成立为false
3. ”>“(大于):判断左值是否大于右值,成立为true,不成立为false
4.“>=”(大于等于):判断左值是否大于等于右值,成立为true,不成立为false
5.”<“(小于):判断左值是否小于右值,成立为true,不成立为false
6.“<=”(小于等于):判断左值是否小于等于右值,成立为true,不成立为false
(7) 逻辑运算符
1.”&“(逻辑与):”&“的左右两边都为真则结果为真,左右两边都需要进行判断真假
2.”|“(逻辑或):”|“的左右两边全为假则结果为假,左右两边都需要判断真假
3. ”^"(逻辑异或):两边相同则为假,两边不同则为真
4.”!”(逻辑非):取反
5.“&&”(短路与):其左右两边都为真则结果为真,若左侧为假则不需要再对右侧进行判断
6.“||”(短路或):其左右两边都为假则结果为假,若左侧为真则不需要在对右侧进行判断
(8) 三元运算符
(关系表达式)?(表达式1):(表达式2)
若关系表达式为真则执行表达式1,若为假则执行表达式2
3.判断语句
一、if语句
当我们需要通过不同的条件执行不同的语句的话,那我们就需要用到if语句。其中if语句有3中结构:
-
if(关系表达式){执行语句}:
执行流程:
(1)先判断关系表达式的真假
(2)如果关系语句为真,则执行{}中的执行语句
(3)如果关系语句为假,则不执行{}中的语句 -
if(关系表达式){执行语句}else{执行语句}
执行流程:
(1)先判断关系表达式的真假
(2)如果关系语句为真,则执行if后{}中的执行语句
(3)如果关系语句为假,则执行else后{}中的语句 -
if(关系表达式){执行语句}else if(关系表达式){执行语句}else if(关系表达式){执行语句}…………else{执行语句}
执行流程:
(1)先判断if后关系表达式的真假
(2)如果关系语句为真,则执行if{}中的执行语句
(3)如果关系语句为假,则判断后面else if后的关系表达式的真假
(4)如果关系语句为真,则执行else if{}中的执行语句
(5)如果关系语句为假,则再判断后面else if后的关系表达式的真假
(6)如果else前所有的关系表达式均为假,则执行else后{}中的执行语句
二、switch语句
结构:
switch(表达式)
{
case 值1:
执行语句1
break;
case 值2:
执行语句2
break;
…………
…………
default:
执行语句
break;
}
执行流程:
(1)先对switch后的表达式进行计算
(2)依次将计算结果与case后面的值进行匹配,如果有对应的值,则执行对应的执行语句,遇到break则跳出 整个switch语句执行后面的代码
(3)如果计算结果与case后面的值都不匹配,则执行default后的执行语句。
注意:
break的作用是跳出整个switch语句执行后面的代码,如果没有break语句则会执行后面所有的执行语句直至遇到break或贯穿整个switch语句。
例如:
4.循环语句
当我们需要执行大量的具有一定相同特点的语句时就需要通过循环语句根据相同的特点进行输出。
一、while 循环语句
结构:
初始化语句
while(条件判断语句){
循环体语句
条件控制语句}
执行流程:
1.判断条件判断语句
2.若结果为true,则执行循环体语句和条件控制语句
3.若结果为false,则不执行循环体语句和条件控制语句
4.执行完条件控制语句后再进行条件判断语句的判断,若结果为true则继续重新执行循环体内的语句,若结果为false,则不执行循环体内的语句
5.直到条件判断语句的结果为false时结束循环
二、do……while循环语句
结构:
do{
循环体语句
条件控制语句}
while(条件判断语句)
执行流程:
1.先执行一次循环体语句和条件控制语句
2.判断条件判断语句
3.若结果为true,继续重新执行循环体内的语句,直至条件判断语句的结果为false结束
4.若为false,则结束循环
注意区别while和do……while的区别:
1.while循环语句是先判断条件判断语句的结果是否为true,若是则执行循环语句,若不是则不执行循环语句
2.do……while循环语句 是先执行一次循环语句,再进行判断条件判断语句结果是否为true,若是则继续执行循环语句,若不是则不执行循环语句
三、for循环语句
结构:
for(初始化语句;条件判断语句;条件控制语句)
{
循环体语句
}
执行流程:
1.先执行初始化语句
2.执行条件判断语句,判断结果是否为true,若是则执行循环体语句,若不是则结束循环
3.执行条件控制语句
4.重复第二步,直至条件判断语句结果为false
for循环语句和while循环语句的在使用习惯上的区别与联系:
区别:
1.在使用习惯上,while控制循环的变量一般定义在循环的外部,当结束循环后该变量依旧存在,后面的代码仍可继续使用该变量。for控制循环的变量一般定义在循环的内部,当循环结束时变量消失,后面的代码中不可在使用该变量
2.for循环一般是在明确循环次数的情况下使用,而while循环一般是在不明确循环次数的情况下使用
联系:for循环语句和while循环语句在语法上没有任何区别,在一定情况下可以进行相互改写
四、循环的跳转控制语句
关键字:continue
在循环中遇到continue关键字时将结束本次循环,不再执行循环体内continue后面的代码,重新执行条件控制语句,进行判断条件判断语句并决定是否执行下一次循环
例:
在该代码中执行输出0—4的循环语句,但当i==3时遇到了continue语句,则不再执行后面的输出语句,继续进行下一次循环,因此输出结果为0、1、2、4
注意区别循环语句中continue关键词和break关键词:
1.continue关键词是不在执行本循环体内continue后面的语句,重新执行条件控制语句,进行对条件判断语句的判断进而判断是否执行下一次循环
2.break关键词是直接退出循环,不在执行条件控制语句和重新对条件判断语句的判断
5.数组
1.什么是数组
:
数组就是一种容器,可以用来储存同种数据类型的多个值。(注意是同种数据类型)
2.数组的定义
:
格式:数据类型 【】 数组名
范例:int [ ] arr
3.数组的初始化
:
(1)静态初始化:
格式:数据类型 【】 数组名 = new 数据类型 【】{元素1,元素2……}
范例:int 【】arr=new int【】{1,2,3,4}
简写格式:数据类型【】数组名={元素1,元素2……}
(2)动态初始化:
格式:数据类型【】数组名=new 数据类型【数组长度】
范例:int 【】arr=new int【3】
注意静态初始化和动态初始化的应用场景:
(1)静态初始化是在我们手动指定数组的元素,系统根据元素的个数计算出数组的长度,在定义时有简写形式
(2)动态初始化是我们手动指定数组的个数,由系统给出默认初始化,其没有简写形式
4.数组的地址值
:
数组是一种引用数据类型,在定义时计算机会根据数组的长度在堆区开辟一个连续的内存空间来储存数据,为了能够找到这片空间,计算机就会给这片空间一个地址,其中我们定义的数组名就储存着数组的首地址
5.数组的内存图
:
在计算机内的各种软甲都占据着部分内存空间,Java也不例外。在Java中为了能够更好的管理数据,它将所占据的内存分为了五个部分:
(1)栈:方法运行时使用的内存
(2)堆:储存方法或数组,用new创建出来的空间都在堆中
(3)方法区:储存可以运行的class文件
(4)本地方法栈:JVM在使用操作系统功能的时候使用
(5)寄存器:给CPU使用
数组在创建时所应用的内存流程:
(1)先将相应的class文件加载到方法区中
(2)将,main方法加载到栈中
(3)在栈中创建变量arr
(4)因为定义数组中用到了new关键字,所以在堆空间中创建一个连续的内存空间
(5)将数组中的元素从左到右对应的储存在堆空间中
(6)将堆空间中的内存空间的地址值传给栈中的arr
6.数组的遍历
:
我们创建好数组后该如何应用数组内存储的元素呢,这就需要对数组进行遍历
获取数组中的元素:
格式:数组名 【索引】
(注意:索引是从0开始的,所以当我们定义一个长度为5的数组时,他的索引范围为0—4)
数组的遍历:
7.数组的异常
:
(1)数组的索引越界问题:
当我们定义了一个长度为5的数组时,堆空间内就会开辟一个能储存五个元素的连续内存空间,数组的索引范围为0----4,但当我们访问了数组中不存在的索引时,就会引发索引越界的问题,此时代码便会报错
(2)数组的空指针问题:
数组名储存着数组的地址值,因此数组就是一种引用数据类型,对于引用数据类型,我们可以将null(空)赋值给该变量,此时就会将该变量所储存的地址值变为空,不再引用任何数据,这就容易造成空指针现象:
8.数组的拷贝
:
(1)浅拷贝:由于数组是引用数据类型,那么就存在多个数组名控制同一块内存的现象,当数组A的某个元素发生改变时,拷贝数组B内相应的元素也发生相同的改变,则该拷贝方式为浅拷贝。浅拷贝通常是通过将地址值赋值给新的数组名的方式实现的
(2)深拷贝:当我们在堆区内开辟一个新的内存空间,接着通过数组遍历的方式将数组A拷贝给数组B,使得数组A的某个元素发生改变时,数组B对应的元素不改变,则这种拷贝方式成为深拷贝
6.方法
1.方法的定义和调用
方法在定义时要定义在main方法外面,类的里面。方法在调用的时候要在main方法或其他方法内调用
(1)无返回值无参数方法:
定义格式:public static void 方法名(){方法体}
调用格式:方法名()
范例:
(2)无返回值有参数方法:
定义格式:public static void 方法名(数据类型 变量名){方法体}
调用格式:方法名(参数)
范例:
(3)有返回值有参数方法:
定义格式:public static 返回值类型 方法名(数据类型 变量名){方法体}
调用格式:方法名(参数)
范例:
注意:
(1)方法定义时的参数成为形式参数,方法调用时的参数成为实际参数
(2)形参的个数可以是多个,但是形参和实参在数据类型和个数上都应该一一的严格对应
2.方法的重载:
(1)同一类中,方法名相同,参数不同的方法成为方法的重载。
(2)方法的重载与返回值无关
(3)所谓的参数不同是指形参的个数不同或类型不同或顺序不同
3.基本数据类型和引用数据类型的区别:
(1)基本数据类型包括:整形,浮点型,字符型,布尔类型
(2)引用数据类型:除了基本数据类型外其他的都为引用数据类型,如:数组,字符串等
(3)基本数据类型数据值是存储在自己的空间中,赋值给其他变量也是赋的真实的值
(4)引用数据类型数据值是储存在其他空间中,自己的空间中存储的是地址值,赋值给其他变量也是赋的地址值
面向对象学习
一、封装:
1.面向对象和面向过程的区别:
(1)面向过程在编程过程中对步骤和操作的重视,通过按照特定顺序依次执行一系列函数来完成任务。
(2)面向对象将程序设计建立在对象的概念上。在面向对象编程中,程序被组织为一组相互协作的对象,这些对象通过消息传递来进行交互和处理。
2.类和对象:
(1)概念:
类:是对象共同特征的描述,是对某一类事物根据其共同特征所抽象出来的。
对象:是根据类的模型所具体刻画出来的东西
(2)类的定义:
格式:public class 类名{
1.成员变量
2.成员方法
}
(3)权限修饰符:
对于类中定义的成员变量和成员方法我们通常设置一定的访问属性
1.private(私有权限):
私有访问权限修饰的成员只能在本类内进行访问,在类外不可访问,一般对成员变量设置私有权限
2.public(公有权限):
公有权限修饰的成员可以在各个类中进行访问,一般对于成员方法设置公有权限
(4)构造方法:
在类中可以定义一种方法对类内成员变量进行初始化
1.空参构造方法:
格式:类名 (){}
2.带参构造:
格式:类名(参数){方法体}
(5)对象的定义:
格式:类名 对象名 = new 类名()
范例:teacher a = new teacher()
(6)如何使用对象:
访问属性:对象名.成员名
访问行为:对象名.方法名(参数)
(7)基本数据类型和引用数据类型:
1.基本数据类型包括:整形,浮点型,字符型,布尔类型
2.引用数据类型:除了基本数据类型外其他的都为引用数据类型,如:数组,字符串等
3.由于类的对象在定义的时候用到了new,所以类的对象为引用数据类型,在对象创建时会在堆空间中开辟内存,对象名存储着堆空间中的地址值,在访问对象的成员变量和成员方法时就会根据地址值找到相应的内存进行访问
(8)this关键字:
1.this的作用:区分局部变量和成员变量
为何要区分成员变量和局部变量呢?
如上所示代码中有成员变量age和局部变量age,当我们要打印age的结果时,计算机就会根据就因原则打印最近的一个age,此时的结果就为10;
因此,我们就需要用到this关键字来区别成员变量和局部变量
2.this关键字的本质:所在方法调用者的地址值
(9)局部变量和成员变量:
1.局部变量:定义在方法内的变量称为局部变量
2.成员变量:定义在类内方法外的变量称为成员变量
二、继承:
1.继承的概念:
继承是面向对象的三大特征之一,可以让类和类之间产生父子关系。可以把多个子类中重复的代码抽取到父类中,子类可以直接使用,减少代码的冗余,提高代码的复用性。
2.继承的格式:
public class 子类 extends 父类{ }
3.继承后子类的特点:
(1)子类可以得到父类的属性和行为,子类可以使用
(2)子类可以在父类的基础上新增其他的功能,子类更强大
4.什么时候使用继承:
当类和类之间存在共性内容时,并且满足子类是父类中的一种,就可以考虑使用继承
5.继承的特点:
java只支持单继承,不支持多继承,但支持多层继承
(1)单继承:一个子类只有一个父类
(2)多继承:一个子类有多个父类
(3)多层继承:子类A继承父类B,父类B继承父类C
6.子类可以继承父类哪些内容:
对于子类继承到的父类的私有成员变量不可以直接进行访问,而继承到的父类的公有成员变量和公有成员方法可以直接访问
7.this关键字和super关键字:
(1)this关键字可以调用本类中的成员变量和成员方法
(2)super关键字可以调用父类中的成员变量和成员方法
(3)如果子类A继承父类B,父类B继承父类C,对于子类A中super只能调用父类B中的内容,无法调用父类C的内容
8.成员方法的重写:
(1)概念:
当父类的方法不能满足子类现在的需求是,需要对方法进行重写
(2)书写格式:在继承体系中,子类出现了和父类一样的方法声明,我们就成子类的这个方法是重写的方法
(3)重写注解:
将@Override放在重写后的方法上,校验子类重写的语法是否正确
(4)重写的本质:
重写后的方法会覆盖掉原方法,向下继承的是重写的方法,原方法不再继承
9.继承中构造方法的访问特点:
(1)父类中的构造方法不会被子类继承
(2)子类中的所有构造方法默认先访问父类中的无参构造,再执行自己。因为子类在初始化的时候有可能会使用到父类的数据,如果父类没有完成初始化,子类将无法使用父类的数据
(3)子类构造方法的第一行默认都是super(),不写也存在,且必须在第一行
(4)如果想要调用父类的有参构造,必须手动写super进行调用
三、多态:
1.概念:
通过父类的引用变量来引用子类的对象,从而实现对不同对象的统一操作。
2.多态的表现形式:
父类类型 对象名称=子类对象
例如: Fu f = new Zi()
3.多态的前提:
(1)有继承关系或实现关系
(2)有父类引用指向子类对象
(3)有方法的重写
4.多态调用成员的特点:
(1)变量调用:编译看左边,运行也看左边
例:
父类:
子类:
测试:
结果:
分析:
在编译时,计算机会先在内存中查找person类内是否有name变量,如果有则在运行时打印对象person p的name变量。如果没有则直接报错
(2)方法调用:编译看左边,运行看右边
父类:
子类:
测试:
结果:
分析:在编译时,计算机会先在内存中查找person类内是否有show方法,如果有则在运行时调用对象student的show方法。如果没有则直接报错
5.多态的优势:
定义方法的时候,使用非类型作为参数,可以接受所有子类对象,体现多态的扩展性与便利
四、抽象类:
1.抽象类的概念:
当子类的共性方法抽象到父类后,由于每个子类执行的内容不同,所以在父类中不确定具体的方法体,该方法可以定义为抽象方法,该类定义为抽象类
2.抽象类和抽象方法的定义:
(1)抽象类的定义:在class前加abstract关键字
(2)抽象方法的定义:在方法前加abstract关键字,()内不加内容,无方法体。
注意:
(1)抽象类内可以不定义抽象方法,但是定义抽象方法一定定义抽象类
(2)抽象类不能实例化
(3)抽象类可以有构造方法以便子类继承后可以对成员变量进行初始化
3.抽象类的使用:
当定义好抽象类后当子类继承抽象类后必须要重写抽象方法,若不重写则报错
五:接口:
1.接口的概念:
Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
这是来自官方的解释,以我个人的理解接口就是对方法的抽象。
2.接口的定义和使用:
(1)接口用interface来定义
public interface 接口名 {}
(2)接口不能实例化
(3)接口和类之间是实现关系,通过implements关键字来表示
public class 类名 implements 接口名{ }
(4)接口的子类要重写接口中的所有的抽象方法
3.类和接口之间的关系:
(1)类和类的关系:
继承关系,只能单继承,不能多继承,可以多层继承
(2)类和接口的关系:
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
(3)接口和接口的关系:
继承关系,可以单继承也可以多继承,
4.抽象类和接口的关系和区别:
(1)抽象类和接口都是根据共性进行抽象的结果
(2)抽象类所针对的是所有的子类,接口针对的是所有子类中的一部分有公共特性的部分
六、常用API
1.String:
(1)字符串比较:
equals:
equals可以比较两个字符串内容是否相同,考虑大小写
equalsIgnoreCase:
equalsIgnoreCase可以比较两个字符串内容是否相同,忽略大小写
(2)遍历字符串:
字符串和数组类似也可以通过索引进行遍历
charAt(索引):
2.ArrayList:
特点:
(1)自动扩容
(2)不能直接储存基本数据类型,可以储存引用数据类型
定义:
ArrayLIst<泛型>集合类型 = new ArrayList<>();
ArrayList 成员方法: