java se
特点: 一次编译,到处运行
解释: java语言代码编写一次,代码就可以在不同操作系统中运行,并且还能得到相同的运行结果
java语言的使用可以无视操作系统之间的差异性
jvm : java虚拟机,理解成一个软件,模拟计算机实现过程, 一个虚拟机就像是一个小型的计算机,主要功能就是可以运行标准的java代码, jvm虚拟机为java代码营造出相同运行环境
简介:
jvm (java virtual machine): java虚拟机,是运行所有java程序的假想计算机,是java程序的运行环境,是java 最具吸引力的特性之一.我们编写的java代码,都运行在 jvm 之上.
jre (java runtime environment): 是java程序的运行时环境,但是单独的jvm虚拟机不能自己运行,需要支持jvm运行的功能代码,jre包含 jvm 和运行时所需要的 核心类库。
核心类库:很多功能代码, 代码太多, 为了便于管理, 因此将代码放置到一个库中管理.
jre = jvm + jvm运行时需要的核心类库功能;
runtime表示运行的概念
jdk (java development kit): 是java程序开发工具包,包含 jre 和开发人员使用的工具,例如 javac.exe(编译器) 和 javadoc.exe(可以自动为java的代码生成说明文档)
jdk : 全称java开发工具包, 主要功能就是可以进行java代码的编译(编写), 还有运行
jdk = jre + 开发时需要工具包(核心类库);
三个组件之间的关系
下载官网:https://www.oracle.com/java/technologies/downloads/#java8-windows
当安装jdk成功之后, jdk有bin文件夹, 包含了所有的可以直接转换成命令运行的应用程序, 未来java代码编译和运行,都需要从jdk的bin中找到命令, 执行代码;
问题 : 目前, jdk的bin文件夹路径下的命令只能在bin路径下使用, 有很大的局限性, 真正环境应该是可以在设备的任意路径都可以使用的
如何解决问题, 可以配置环境变量.
实现bin目录下的java相关命令可以在任意目录下使用
注意事项:
整数类型中字面值常量的默认类型是int类型
long类型的变量在定义的时候,当字面值超过int范围需要在字面值后加 l / l,建议 l
小数(浮点)类型
小数类型的字面值常量默认类型是 double类型
float 类型变量在定义的时候,需要在字面值后加 f / f,建议f
double 类型的变量在定义的时候,可以在字面值后加 d / d,也可以不加.
浮点型存储的数据是不精确的数据,所以在运算过程中,其结果也有可能不精确.
字符类型
字符类型变量的赋值方式:
(1) 通过 '' 形式赋值
案例:
char c = 'a';
(2) 通过ascii码表赋值, 但是如果直接使用整数给char类型赋值, 那么整数范围必须在0-65535之间, 因为人类的语言文字, 放在一起, 一共有65535个字符可以表示, 超出范围,无法对应编码表, 代码报错
char c = 65;
编码表存在的解释说明:
人类语言文字,需要被计算机识别, 而计算机底层全部都是二进制, 也就是数字; 因此需要将人类的语言文字与数字形成对应关系, 目的就是为了让计算机以数字的形式将字符存储下来, 于是最早期, 美国人形成了一张表, 简称ascii编码表;
ascii编码表中存储了所有的字母大小写, 英文符号以及数字与整数的对应关系
a : 0100 0001 // a在计算机中实际存储的是二进制的0100 0001
注意 : 比较常见编码需要记住:
常用的ascii码表值
ascii编码表:
中国有自己的编码表, 兼容了ascii, 同时咱们编码表中, 包含所有中文文字
gbk : 中国标准信息交换码表
utf-8 : 国际标准码表, 包含了各个国家语言文字
布尔类型
引用数据类型
string 类是字符串,在定义string类型的变量的时候,使用 "" 括起来表示字符串常量内容
举例 : string str = “写任意字符序列”;
(1) 转换原因: java是强类型语言,数据类型之间不能随意转换,但运算时数据类型不匹配,所以需要转换.
(2) 数据类型转换分类:
a : 自动类型提升
b : 强制类型转换
范围小的数据类型可以直接转换为范围大的数据类型
举例 : 50ml水杯, ---> 小数据类型
500ml水瓶---> 大数据类型
将水杯中水倒入到水瓶中, 可以, 容量完全符合
数据类型范围大小排序:
boolean类型不参与大小排序
(1) 大范围数据类型的变量/常量 赋值 给一个小范围数据类型的变量,需要进行强制转换.
举例 : 50ml水杯, ---> 小数据类型
(2) 格式:
目标数据类型 变量名 = (目标数据类型)原数据类型变量名或原常量值;
(3) 注意事项:
强制类型转换可能会损失精度,得到错误的数据.
小数类型强制转换为整数类型时,直接舍去小数部分,只保留整数部分.
(4) 常量优化机制: 在编译时,整数常量的计算会直接算出结果,并且会自动判断该结果是否在该数据类型取值范围内
1.元的概念: 可以操作的数据或者表达式.
2.三元运算符: 别名三目运算符,同时可以操作三个数据或者表达式的运算符.
3.格式: (典型的两种情况选择其中一种)
表达式1 ? 表达式2 : 表达式3;
4.说明:
1)表达式1必须是boolean类型的表达式,计算结果只能是true、或者false
2)表达式2和表达式3可以是任意类型的表达式
5.运算流程:
1)计算表达式1的值,要么为true,要么为false
2)如果表达式1计算结果为true,就选择表达式2作为三元表达式的计算结果
3)如果表达式1计算结果为false,就选择表达式3作为三元表达式的计算结果
<<:左移
空位补0,被移除的高位丢弃
>>:右移
被移位的二进制最高位是0,右移后,空缺位补0;最高位是1,高位补1。
>>>:无符号右移
被移位二进制最高位无论是0或者是1,空缺位都用0补。
位运算符的小技巧:
1、判断奇偶性
按位与: &1(0000 0001) 等于 0 为偶数, 等于 1 为奇数,因为偶数末位一定为0,其他位都是在 &0 结果都是0
2、判断是否是2的幂次方
return num & (num -1)== 0
比如4 100 & 011 = 0,是2的幂次方
3、按位或: x | 0 等于 x
将两个值(x,y)拼在一起作为新的值z
z = x << 32 | y
说明:上面的前提是z的类型是64位,这样z的前32位代表的是x,后32位代表的y。想要再通过z获取x,则
x = z >> 32
4、按位与: x & 1 等于 x
5、常用操作
& = 取交集
| = 取并集,比如 x | y = x 中再加 y
& ~x : 将x去掉(跟x的反取交集,相当于去掉x)
流程控制 : 代码的执行顺序, 分为三大类: 顺序结构, 分支结构, 循环结构
分支结构: 当代码执行到某种情况下, 接下来可以有多种选择, 挑选最符合当下场景的其中一种逻辑运行, 多选一, 实现,主要就是if语句, switch语句
1.方法定义注意事项:
1)方法不能嵌套定义,每一个方法都是独立的
2)方法的先后没有区别,都是平级关系
3)方法可以嵌套调用,甚至可以自己调用自己
栈内存概念:
jvm虚拟机运行代码: jvm虚拟机就是运行java代码的容器,jvm本身就是个软件,运行时就需要在内存中开辟空间,jvm将其占有的内存空间划分成5块空间区域,其中一块空间,称为栈内存
栈内存: 代码中的方法运行, 需要在栈内存中开辟空间运行; 方法调用时进入栈内存中开辟空间, 方法运行完毕, 出栈内存, 占有空间释放(方法弹栈死亡)
方法的重载: overload,超载单词
方法重载的概念记住 : 有时笔试题中, 会出现 “什么是overload(重载), 什么是override(重写)”
在同一个类中,方法名相同,参数列表不同,与返回值类型无关的多个方法,称为重载
数组含义: 集中存储相同类型数据的容器
数组特点:
1)存储数据长度固定的容器, 数组是一个定长容器, 当定义一个数组时, 必须指定数组的长度(可以存储的数据的个数)
2)存储数据的数据类型要一致
索引访问数组中的元素:
数组名[索引] = 数值; //为数组中的元素赋值
变量 = 数组名[索引]; //获取出数组中的元素
当定义出一个数组时, jvm虚拟机会默认为数组中的每一个元素进行默认的赋初值动作, 根据不同数组中存储的数据类型不同, 初值也不同
整数 : 0
浮点类型 : 0.0
char类型 : ‘ ’
boolean类型 : false
引用数据类型 : null, null表示引用数据类型为空
1.含义: 在创建数组时,直接将元素确定的定义方式
2.格式:
数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, ..., 元素n};
注意事项:
1)在第二个方括号中,不能写数组元素个数
2)元素值的罗列,元素和元素之间,使用逗号分隔
3)罗列出来的元素值,数据类型必须和声明数组时数据类型一致
3.简化格式:
数据类型[] 数组名 = {元素1, 元素2, ..., 元素n};
注意事项: 不能分成两行写
1.异常(exception): 表示在java代码编译和运行过程中,出现了不正确的,不正常的,不符合实际场景的情况,统称为异常
2.数组中常见的异常有两种:
a: 数组索引越界异常
b: 空指针异常
数组索引越界异常
1.索引越界异常:
arrayindexoutofboundsexception
数组 索引 超出 边界 异常
2.发生索引越界异常原因:
使用的索引在数组中不存在
3.代码分析:
观察一下代码,运行后会出现什么结果
public static void main(string[] args) {
int[] arr = {1,2,3};
system.out.println(arr[3]);
}
创建数组,赋值3个元素,数组的索引就是0,1,2,没有3索引,因此我们不能访问数组中不存在的索引,程序运行后,将会抛出 arrayindexoutofboundsexception 数组越界异常.在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码.
4.越界异常避免方案
不要访问不存在的索引,使用索引时,验证索引在"0--数组长度-1"范围
5.数组的长度属性: 每个数组都具有长度,java中赋予了数组一个属性,用于获取数组的长度,语句为:数组名.length
空指针异常
1.空指针异常
nullpointerexception
空 指针 异常
2.发生空指针异常原因:
当引用数据类型值设置为null(前提),证明这个变量引用没有指向任何堆内存地址,但仍然想通过这个变量引用访问堆内存中数据,就会报出空指针异常
注: null,即为空,用于表示在栈内存的引用中,不记录任何堆内存的地址
观察一下代码,运行后会出现什么结果
int[] arr = {1,2,3};
arr = null;
system.out.println(arr[0]);
}
arr = null这行代码,意味着变量arr将不会再保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出nullpointerexception 空指针异常.在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码.
jvm的内存划分:
数组在内存中的存储
一个数组的内存图
数组引用的输出的结果是地址,是数组在内存中的地址.new出来的内容,都是在堆内存中存储的,而方法中的变量arr保存的是数组的地址.
两个数组的内存图
引用数据类型每次new,都在内存中开辟新的空间地址.
多个引用指向同一个数组空间
任意一个引用修改了数组中的内容,其他引用访问到的就是修改后的数据.
遍历数组元素
数组获最值
数组元素交换
数组的反转
冒泡排序
面向对象概述:
面向过程 : 有一个需求实现,思想, 我怎么去实现, 强调的是做事的步骤,需要自己一步一步的去操作实现。
面向对象的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。
面向对象区别于面向过程思想,有一个需求实现思想, 谁来帮我实现, 强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
面向过程是面向对象的基础, 面向对象基于面向过程实现的, 但是代码思想层面上, 面向对象时更高级的设计思想
面向对象的特征:
1、封装
2、继承
3、多态
类的概述
类是一组相关属性和行为的集合
属性 : 一个事物的特征(成员变量或者全局变量)
行为 : 一个事物可以做功能(方法)
对象的概述
java是一类事物的具体体现。
对象是类的一个实例,必然具备该类事物的属性和行为。
类与对象的关系
类是对一类事物的描述,是抽象的。
对象是一类事物的实例,是具体的。
类是对象的模板,对象是类的实体。
类中的内容:
属性:
对事物特征的描述体现 java代码中使用变量体现 被称之为成员变量。
【和以前定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外。】
行为:
对事物功能【能干什么】的描述 java代码中使用方法体现 被称之为成员方法。
【和以前定义方法几乎是一样的。只不过把static去掉,static的作用在后面课程中再详细讲解】
对象的使用
创建对象: 类名 对象名 = new 类名(); // 类本身就是一种引用数据类型
成员的使用:
获取成员变量值:
变量 = 对象名.成员变量;
修改成员变量值:
对象名.成员变量 = 新值;
访问成员方法:
对象名.成员方法(实参);
成员变量的默认值
一个对象创建的内存图
两个对象的内存图
两个对象引用指向同一个内存空间
匿名对象的使用
概述 : 没有名字的对象
格式 : new 类名(实参);
特点 : 只能使用一次
使用场景: 如果某个成员或方法只使用一次, 就可以使用匿名对象
优势: 在内存中存在时间短, 相对节省内存
成员变量和局部变量的区别
定义位置不同
成员变量: 类中方法外
局部变量:方法中
内存位置不同
成员变量:堆空间
局部变量:栈空间
生命周期不同
成员变量:随着类对象的创建而创建,随着对象的消失而消失
局部变量:随着所在方法的执行而创建,随着方法的执行完毕而消失
默认值不同
成员变量:有默认值
局部变量:没有默认值
封装的原则:
将属性隐藏起来
使用时对外提供公共的访问方式
封装的好处:
隐藏了事物的实现细节
提高了代码的复用性
提高了代码的安全性
private : 是一个关键字, 是私有的的意思, 是一个修饰符
修饰内容:
修饰成员变量(最常用)
修饰成员方法
修饰构造方法
修饰内部类
修饰效果:
只能在本类中使用,其他所有外类不能直接使用private修饰的成员
getter方法和setter方法是对属性封装后对外提供的统一访问属性的访问方式
作用:
getxxx():获取封装属性的值
setxxx(参数列表):修改封装属性的值
注意:xxx代表的是封装属性的名称,首字母大写
把封装后对相关操作的修改操作称之为封装的优化
变量的访问原则
总体原则:就近访问原则
就近访问:
当在访问某个变量名称的时候,会先寻找最近的该变量名称的定义,如果寻找到了,就使用该变量,如果没有找到,才到更远的位置寻找该变量名称的定义。
比如:
this关键字含义:代表所在类的当前对象的引用(地址值),即对象自己的引用。
this关键字作用:
当成员变量和局部变量重名, 带有this关键字的变量表示成员变量的使用
开发中, setter方法中局部变量和成员变量同名赋值失败的问题就可以使用this关键字来解决
哪个对象调用了带有this关键字的方法, this关键字就表示哪个对象本身
cat c = new cat();
类名 对象名 = new 类名(); // 对象创建过程中, 最后的小括号就表示构造方法调用
构造方法概述: 当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。构造方法有自己独有的方法格式。
解释 : 创建对象,构造方法必须调用,既然必须要调用构造,就要让这个构造方法发挥最大价值, 因此可以在创建对象的同时, 就给对象中成员变量进行赋值
构造方法分类: 有参构造, 无参构造
构造方法定义格式:
构造方法特点:
方法名必须和类名一致
没有返回值类型,连void都不写
不需要返回值类型
默认被jvm调用使用, 构造方法调用时机:
在创建对象同时, 被jvm虚拟机主动调用,并且创建一次对象, 构造方法只调用一次, 因为构造方法无法手动通过对象名调用
注意事项:
如果你不提供构造方法,系统会给出无参数构造方法。
如果你提供了构造方法,系统将不再提供无参数构造方法。
构造方法是可以重载的,既可以定义参数,也可以不定义参数。
如果代码中即定义了空参数构造, 也同时定义了有参数构造, 那么创建对象时, 可以从多个构造中选择其中任意一个调用即可
如果代码中定义有参数构造, 请一定要加上空参数; 代码中必须要有一个空参数构造,面向对象中的很多使用, 都是空参数构造的调用. 或者自己不定义构造, 使用系统默认生成的空参构造就可以
方法重载 : 定义在同一个类中, 方法名字相同, 参数列表不同的多个方法之间, 称为方法重载, 与方法是否有返回值无关
javabean是java语言编写类的一种标准规范。符合javabean 的类,要求
类必须是具体的和公共的
所有属性使用private修饰
提供用来操作成员变量的set 和get 方法
并且具有无参数的构造方法(建议有)
静态就是 static , 主要用来修饰java的变量和方法的关键字。
没有静态与有静态的场景对比:
a : 没有静态
如果某个类型的所有对象,都具有一个相同的属性值,那么这个属性值就没有必要在所有对象中,都存储一份。还有坏处:浪费内存空间;维护难度大,一旦需要修改,就得修改所有的对象。
b: 有静态
如果某个类型的所有对象,都具有一个相同的属性值,那么就在这个属性的定义上,加一个static静态关键字。让该变量存储在方法区字节码的静态区中,避免了所有对象都存储相同数据的问题,节省了内存空间,将来维护容易(只需要修改一次)
没有静态内存图:
有静态的内存图:
静态变量属于类, 不属于对象
加载时机:
随着类.class文件的加载而加载
静态变量随着类的加载进方法区,就直接在静态区给开辟了存储静态变量的内存空间
静态变量优先于对象而存在
静态变量被所有该类对象所共享
调用方式:
类名调用 或者 创建对象调用
扩展 : 类型中的静态成员变量, 或者是静态方法, 都可以直接使用类名调用, 而不需要创建对象
总结: 静态方法不能直接访问非静态资源(变量,方法,this关键字)
1、静态方法:在方法声明上,加上了static关键字的方法,就是静态方法
2、静态方法不能访问非静态的变量
原因:
静态方法可以在没有创建对象的时候调用,而非静态的变量只有在对象创建之后才存在。如果静态方法可以访问非静态的变量,那么就相当于在对象创建之前,就访问了对象创建之后的数据。明显不合理。
3、静态方法不能访问非静态的方法
静态方法可以在没有创建对象的时候调用;非静态的方法可以访问非静态的变量。如果静态方法可以访问非静态的方法,就相当于静态方法间接的访问了非静态的变量,和第2点矛盾。
4、静态方法中不能存在this关键字
this关键字表示本类当前对象。静态方法可以在对象创建之前调用。如果静态方法可以访问this关键 字,相当于在创建对象之前,就使用了对象本身---矛盾
概念上,所属不同:
非静态变量属于对象
静态变量属于类,类变量
内存空间不同,存储位置不同
非静态变量属于对象,所以存储在堆内存中
静态变量属于类,存储在方法区的静态区中
内存时间不同,生命周期不同
非静态变量属于对象,所以生命周期和对象相同,随着对象的创建而存在,随着对象的消失而消失
静态变量属于类,所以生命周期和类相同,随着类的加载而存在,随着类的消失(内存管理)而消失
访问方式不同
非静态变量只能使用对象名访问
静态变量既可以使用对象访问,也可以通过类名访问:
类名.静态变量名 或者 对象名.静态变量
类名.静态方法名()
继承的优势:
能提高代码的复用性
提高代码的可维护性
为多态提供了前提
继承中弊端:
继承让类与类之间产生了关系,类的耦合性增强了(关联程度太高),当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
实际java开发中:
高内聚 : 类中功能进行尽量多
低耦合 : 少与外类发生密切关联
1、私有的成员不能被继承
父类中有一些私有成员,不能在子类中直接使用
其实在子类对象中,仍然包含了父类中定义的私有成员变量
只不过在子类中,不能直接访问父类中定义的私有成员变量
2、父类中的构造方法,不能继承
原因:
父类的构造方法需要和父类的类名一致、子类的构造方法需要和子类类名一致,父类和子类的类名不一样。因此无法继承,名称有冲突。
父类的构造方法用于给父类的成员变量赋值,子类的构造方法用于给子类的成员变量赋值,子类的成员变量较多,使用父类的构造方法无法将子类中所有的成员变量都进行赋值,因此不继承父类的构造方法
解决:
1、java支持单继承,不支持多继承,java支持多层继承
2、原因:
子类可以继承并且使用父类中的所有非私有的成员变量
父类中定义了成员变量,子类中没有定义,那么子类可以直接使用父类中非私有成员
父类中没有定义成员变量,子类中定义了,子类可以自己调用自己的变量,父类不能调用子类特有变量
总结: 子类可以自己和父类的成员变量,父类只能使用自己的成员变量
父类中定义了变量,子类中重新定义了这个变量,在子类中调用的就是子类的变量
原因: 变量的访问就近原则
方法内部,自己定义了变量,使用方法内部变量
方法内部没有定义,找当前类中成员变量
类中成员变量也没有定义,找父类中的成员变量
父类中没有定义变量,再继续找父类的父类,直到找到最后(object类,所有类的直接或者间接的父类,object是一个最顶层的类,也没有找到,才报错
如果子父类中成员变量重复定义, 想调用父类成员变量, 那么使用关键字 super
super : 关键字, 表示当前类型父类引用(super使用于子类类型中)
使用 : super.父类成员变量名;
注意 : super关键字第一种使用场景, 区分子类和父类重名成员, 带有super.成员表示父类成员使用
1、this和super:
this表示本类当前对象的引用
super表示本类当前对象父类的引用
2、继承关系的内存理解:
如果zi类类型需要进入到内存中使用, zi类对应的父类fu.class字节码文件先进入到方法区中, 然后zi.class字节码文件才进入到方法区中
创建子类类型对象, 在堆内存中开辟了空间之后, fu类中的成员先进入到内存中, 由jvm虚拟机先为父类中成员进行赋值
子类成员后进入到堆内存中
使用成员, 优先使用子类中定义成员, 如果子类中没有对应成员或者使用super关键字, 调用父类中继承到成员使用
总结 : 父类优先于子类进入到内存中, 父类先为子类将可继承数据准备好, 自己进入到内存中才能继承使用
父类中私有方法不能被子类继承使用
子类中定义的和父类中继承到方法不同, 子类可以调用自己特有方法功能, 可以调用从父类继承来的功能
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容, 子类重写是为了让方法越来越好
重写override注意事项:
重写需要与父类原方法 返回值类型, 方法名 ,参数列表相同
私有方法不能被重写(父类私有成员子类是不能继承的)
子类方法访问权限不能更低(public > 默认 > 私有)
在子类重写方法上, 通常使用注解 @override, 标识和验证方法是重写方法
子类重写了从父类继承来的方法功能, 子类重写方法优先调用和运行
如果子类父类中有相同方法定义, 使用super关键字,区分子父类中重名方法功能
super.父类方法名(需要实际参数);
注意 : 重写的方法本身还是属于父类,只是在子类中重新实现了这个方法的内容。
笔试题:
什么overload(重载)? 什么override(重写)?
重载 : 定义在同一个类中, 方法名相同,参数列表不同, 与方法返回值类型无关的多个方法之间, 称为重载
重写 : 在子父类关系中, 子类重写从父类继承来的方法功能, 要求方法参数列表, 返回值类型, 方法名与父类方法一致, 方法内容可以修改
重写注意事项:
私有方法不能重写
重写后方法的权限大于等于父类原有权限
重写方法通常使用@override注解进行标识
父类中构造无法被子类继承, 但是子类构造方法中可以调用父类构造; 在子父类继承关系中, 父类优先于子类进入到内存, 父类中数据优先于子类进行初始化(赋值)
如果子类构造方法中, 没有手动调用任何构造(本类, 父类),系统会默认在子类构造方法第一行调用super(); 目的是为了让父类中成员优先于子类进入内存中赋值
super() : 表示调用父类空参数构造方法
如果子类构造方法中, 手动调用本类或者父类构造, 那么系统不会再默认调用任何过构造, 一律以手动调用构造为准
super() : 父类构造调用. 必须写在构造方法第一位置上, 直接保证父类构造优先于子类进入内存运行
1、含义:
this关键字表示本类当前对象的引用
super关键字表示本类当前对象的父类的引用
2、super和this都可以访问成员变量
super只能访问父类中定义的成员变量
this既可以访问子类中定义的成员变量,也可以访问父类中定义的成员变量
3、super和this都可以访问成员方法
super只能访问父类中定义的成员方法
this不仅可以访问子类中定义的成员方法,也可以访问父类中定义的成员方法
4、super和this都可以访问构造方法:this语句和super语句
实际代码中this和super的使用:
this : 当前类型对象的使用
可以区分成员变量与局部变量的重名问题, 带有this关键字的变量表示成员变量的使用
super : 当前类型对象的父类引用
子父类定义重名成员变量, super.成员变量表示父类成员的使用
子父类定义重名成员方法(子类重写), super.方法() 父类中的方法功能
子类构造方法第一行, 一定要调用父类构造, 为了保证父类成员优先于子类进入到内存中 super(父类构造实际参数);
1、使用大括号包起来的一段代码。放在不同的位置,有不同的名称,有不同的作用,有不同的执行时机。
2、分类:
局部代码块
构造代码块
静态代码块
同步代码块(多线程)
1、格式:使用大括号包起来的一段代码
2、位置:方法中
3、作用:
限定变量的生命周期
在局部代码块中【声明】的变量,只能在局部代码块的范围内使用,一旦出了局部代码块的大括号,变量就不能继续使用了。
某个变量一旦不能使用了,就会被回收,节省内存空间
4、注意事项:
如果是在局部代码块中声明了变量,会减少变量的声明周期,出了局部代码块就无法继续使用局部代码块中声明的变量。
如果是在局部代码块中修改了局部代码块外声明的变量,局部代码块结束之后,并不会消除局部代码块对这个变量的修改。
2、位置:类中方法外
用于给成员变量初始化赋值
4、构造代码块的执行说明:
1、在创建对象的时候执行,由jvm默认调用
2、在构造方法执行之前,执行
3、任意一个构造方法执行之前,都会执行一次构造代码块的内容
4、如果每个构造方法都会执行的内容,提取到构造代码块中
1、格式:
用于给静态的成员变量初始化赋值
用于执行那些只需要执行一次的代码,例如驱动加载等
4、执行特点:
1、随着类的加载而执行
2、类只加载一次,所以静态代码块只执行一次
3、执行的时机最早:早于所有的对象相关内容
封装 : 隐藏事物实现细节, 多外提供公共访问方式, 方法, private关键字, 提高代码安全性, 提高代码的复用性
继承 : 类与类之间发生子父类继承关系, extends关键字, 子类可以直接继承使用父类中的成员(私有,构造除外), 提高代码的复用性, 可维护性, 为多态提供了前提条件; 弊端: 类与类之间的耦合度过高
多态 : 事物的多种形态, 要求有继承关系(或实现关系), 子类重写父类中方法, 父类的引用指向之类的对象; 多态的表达式中, 对于方法调用, 编译看左, 运行看右; 多态好处就是可以极大提高代码的扩展性
多态概述
事物的多种表现形态就是多态;
java中的多态就理解为对象的不同数据类型的体现也就是子类对象充当父类类型对象
多态的发生前提:
必须要有继承或实现关系
有方法的重写
父类引用指向子类的对象
格式:
父类类型 变量名 = new 子类名(实参);
原则:
编译看左边,运行看左边
1、编译的时候,要看【=】左边的引用所属的类型中,是否有该变量的定义,如果有,就编译成功,如果没有,就编译失败
2、运行的时候,也是使用等号左边类型中的变量
person p = new teacher();
当有了一个多态的表达式, 需要通过变量p调用成员变量
编译代码时(写代码时), 检查, 等号左边的person类中,是否定义了该成员变量, 如果没有定义代码报错
当person类中定义了该成员, 实际调用成员变量时, 调用的仍然还是等号左边的person类型中的成员变量
编译看左,运行看右
编译的时候,要看【=】左边的引用所属的类型中,是否有该方法的定义,如果有,就编译成功,如果没有,就编译失败。
运行的时候,要看【=】右边的对象所属的类型中,是如何实现这个方法的。最终运行的是子类重写过的方法实现。
1、向上转型:
使用子类的引用指向子类的对象(正常情况)
多态中,使用父类的引用指向子类的对象(向上转型)
person p = new teacher();// 向上转型
本质:缩小了对象本身的访问范围,减少了访问的权限(只能访问父类中定义的内容)
2、向下转型:
类比性记忆 : 子类想成年轻人, 年龄小; 父类想成老年人, 年龄大; 向下就是老年人, 回复成年轻人, 年龄向下
概念:
让指向子类对象的父类引用,【恢复】成子类的引用
格式:
子类类型 引用名称 = (子类类型)父类类型的引用;
本质:
【恢复】子类类型原本就有的访问范围
3、缺陷: 向下转型的时候有可能转为其他子类的类型,编译不会报错但是运行时会发生类型转换异常
4、解决方案:
转之前判断一下要转换的类型是不是多态对象之前的类型。使用一个关键字 instanceof 来判断向下转换类型是不是自己的类型
多态对象 instanceof 指定的数据类型 , 返回值为布尔类型的数据
提高了代码的可扩展性(灵活性)
在方法的参数列表中,形式参数是父类类型的引用,将来调用方法的时候,父类类型的任意子类对象,都可以作为方法的实际参数。
1、抽象:抽取像的、相同的、相似的内容出来
2、抽象方法:java中只有方法声明没有方法实现并且被关键字abstract修饰的方法就是抽象方法
3、格式:
修饰符 abstract 返回值类型 方法名(参数列表);
4、注意:
抽象方法只能定义在抽象类中和接口中
1、抽象类: 可以定义抽象方法的类,就是抽象类。
2、java中被关键字abstract修饰的类就是抽象类
3、定义格式:
1、抽象类和抽象方法都需要使用abstract关键字修饰
抽象类:abstract class {}
抽象方法:public abstract void test();
2、抽象类和抽象方法的关系:
抽象方法所在的类必须是抽象类
抽象类中未必一定都定义抽象方法,抽象类中未必存在抽象方法
3、抽象类的实例化(抽象类如何创建对象)
抽象类不能直接实例化
定义抽象类的子类,由子类创建对象,调用方法
注意 : 抽象类存在意义就是为了有子类继承, 重写抽象方法
4、抽象类子类的前途
在子类中,将父类所有的抽象方法全部重写(实现),子类就成了一个普通类,就可以创建对象
在子类中,没有将父类中所有的抽象方法全部实现,子类就还是一个抽象类,还需要使用abstract关键字修饰子类。
普通类中可以定义成员 + 抽象方法 = 抽象类中成员
1、成员变量:可以定义变量,也可以定义常量,但是不能被抽象
2、构造方法:有
虽然本类无法创建对象,但是抽象类一定有子类,子类会访问父类的抽象方法。
是否有构造方法,不取决于是否可以创建对象,而是取决于是否可以定义成员变量。如果可以定义成员变量,那么就需要初始化成员变量,就是构造方法来完成的。
3、成员方法:
既可以是抽象方法:强制子类重写
也可以是非抽象方法:用于给子类继承,提高代码的复用性
接口是java用来描述多种不同规则的集合体;
规则在java中就是抽象方法,接口就是存放了不同的抽象方法的集合体
java中使用关键字interface表示,接口和类同级别的
好处:
一旦将命名规则定义出来,【方法的调用】和【方法的实现】就分离开了,可以提升开发效率,降低代码的耦合性
抽象类 : 毕竟是个类, 类与类之间单继承关系, 一个子类只能有一个直接父类, 类与类之间有很大的耦合度
接口 : 不是类, 类与接口之间的关系, 可以多个对应关系, 一个类可以同时实现多个接口, 接口中全是抽象方法, 因此方法的规则, 都必须要实现类重写, 因此接口与实现类之间的耦合度, 降低
修饰符 interface 接口名 {接口的内容}
接口的源文件也是.java文件,照样参与编译,编译后的文件依然是字节码文件【.class】
内容:
属性:接口中的成员变量, 实际是成员常量,默认被 public static final修饰
注意:使用接口名访问即可
方法:jdk1.8之前:只有抽象方法, 默认被public abstract 修饰
没有构造方法 不能直接创建对象的
功能必须需要类来实现之后被类的对象调用使用
概述: 接口书写好之后里面的规则要想被使用,需要类来重写,一个类又需要这个接口的功能,要类和接口发生关系,就使类拥有接口中的规则功能。
类去重写接口规则的过程就叫做实现接口
类实现接口:
使用关键字implements连接类和接口
接口的实现类前途:
是一个抽象类,该类没有实现接口中的所有抽象方法
是一个普通类,该类实现了接口中的所有抽象方法
单实现:
一个类实现了一个接口的实现方式
多实现:
一个类同时实现多个不同接口的实现方式就是多实现
1、类与类
继承的关系,使用extends关键字
可以单继承、不可以多继承、可以多层继承
2、类与接口:
实现关系,使用implements关键字
java中有单实现和多实现
多实现没有安全隐患:即使两个接口中有一样的方法声明,但是在类中也只有一个实现
注意 : 父优先
3、接口与接口:
继承关系,使用extends
可以单继承、也可以多继承、可以多层继承
多继承的格式:
4、类和接口的区别(设计区别):
抽象类:定义物体本身具有的固有属性和行为
接口:定义物体通过学习、训练而扩展出来的行为
定义在一个类中的另一个类就叫做内部类
举例:在一个类a的内部定义一个类b,类b就被称为内部类
分类: 根据定义的位置不一样以及是否有名分为了不同的内部类,具体分类如下:
成员内部类
局部内部类
匿名内部类
访问特点:
内部类可以直接访问外部类的成员,包括私有成员
外部类要访问内部类的成员,必须创建对象
定义位置: 在类中方法外,跟成员变量是一个位置
外界创建成员内部类格式
成员内部类的推荐使用方案
案例: 定义一个身体body类, body类中定义一个heart心脏内部类, 测试内部类的使用
定义位置: 局部内部类是定义在方法中的类
访问方式:
-局部内部类,外界是无法直接使用,需要在方法内部创建对象并使用
-该类可以直接访问外部类的成员,也可以访问方法内的局部变量
概述: 想要使用一个类的子类或接口实现类对象的时候,匿名内部类就是其中的一种获取子类对象或实现类对象的方式,他是一个固定的语法格式。
匿名内部类的使用前提:
存在一个类或者接口,这里的类可以是具体类也可以是抽象类
匿名内部类的格式
举例:
匿名内部类的本质
本质:是一个类的子类对象或者一个接口的实现类对象
匿名内部类的使用:
匿名内部类可以通过多态的形式接受
匿名内部类作为对象直接使用(只能使用一次)
当发现某个方法需要接口或抽象类的子类对象,我们就可以传递一个匿名内部类过去,来简化传统的代码
1、final是一个关键字 含义:最终的,最后的,表示不能再改变的。
2、final关键字:可以修饰类、方法、变量
3、修饰类:
表示一个最终类,表示不能有子类,【不能被其他类继承】
一旦一个类型不能被继承,那么其中所有的方法都不能被重写
不影响当前类的方法被调用
4、修饰方法:
表示一个最终方法,【该方法不能被重写】
5、修饰变量:
表示一个最终变量,该【变量变成了常量】,就只能赋值一次
使用final修饰的变量, 不能进行二次赋值, 值不能改变, 因此成为常量, 命名规范 : 所有单词前大写, 多个单词之间使用_进行分隔了; 举例 : school_name pi
定义常量的好处:见名知意,容易理解;可维护性高
总结 :
final修饰的类不能有子类
final修饰的方法不能被重写
final修饰的变量,称为常量,其值不能修改
包的概述: 用来统一分类管理源代码资源的特殊的文件夹;这个文件夹会参与编译。
com.ujiuye.demo 下的 person类进行编译的时候类所在的包参与编译,编译后
字节码文件名:com.ujiuye.demo.person
字节码文件中类名:com.ujiuye.demo.person【全限定类名】
统一管理代码资源
保证代码编译后类名唯一
保证代码运行的过程直接进入包找到对应的类
命名规则:
使用公司域名的反写【保证每一个包路径唯一】
全部小写
包名和包名之间使用.隔开
包的声明:
使用关键字 package + 包路径【ide生成类的时候自动声明】
导包:
同包下:不需要导包
不同包:需要导包【jdk的lang包除外】
使用 import + 包路径
概述: 用来限定资源的使用范围的修饰词汇,就叫做权限(使用)修饰符,不同的符号有不同的限定范围
分类: 从小到大权限罗列
private :私有的 限定范围是:本类中使用, 通常修饰成员变量
默认的 :啥也不写 限定范围: 本类和本包(package)中使用
说明 : 定义类, 定义方法, 定义一个变量, 如果没有使用任何权限修饰符, 那么就使用默认权限, 切记, 什么都不写, 写出来反而报错
protected :受保护的 限定范围: 本类和本包中使用, 可以外包的子类内部使(protected 受保护权限被外包子类继承了, 那么在外包子类中, 相当于private)
说明 : protected 只能修饰方法和变量, 不能修饰类, protected 关键字也是封装的一种体现形式
public :公共的 限定范围:没有范围, 通常修饰类和方法