javaSE
idea快捷键
main/psvm,sout,快捷键入相关代码
CTRL+d,复制当前代码到下一行
ctrl+y,删除所在行建议用ctrl+x
ctrl+alt+L,格式化代码
ctrl+shift+enter 自动补全代码
alt+shift+↑/↓上下移动代码
ctrl+H展示类的依赖架构
ctrl+shift+f在文件中查找输入内容
ctrl+alt+M代码抽取
ctrl+/,ctrl+shift+/,/**+enter对代码进行注释
//单行注释
/* 注释内容*/多行注释
/**文档注释*/文档注释一般用在类上,方法上
数组名.fori
快速写好for循环定义
idea中debug使用方法
在代码左侧点一下,从当前行开始运行,但是当前行还未循行,然后点↓单行单行运行,点跳转符号直接运行完
如果点了两个点而且已经不需要继续看第一个了,可以直接点| |>键
数据类型
作用:用于定义变量的,然后约束变量只能存储什么类型的数据
引用数据类型
不是基本类型的数据都是引用类型string
基本数据类型(四大类八大种)
byte short int(默认)long整型
- byte 字节型占1个字节 -128 -127
- short 短整型占2个字节
- int 整型 默认类型 占4个字节
- long 长整型 占8个字节 如果希望当成长整型需要在后面加L/l; long lg=124673616571743182L
float double(默认)浮点型
- float 单精度占4个字节如果希望当成长整型需要在后面加F/f; float score =98.5f
char 字符型
boolean 布尔型
规则范围
byte short int long float double
char
字面量
直接看到的数据
整数
小数
字符
必须单引号围起来
有且仅有一个字符
特殊字符
- /t空格
- /n换行
字符串
必须双引号围起来,内容可随意
布尔型
true
false
空:null
变量
内存中的一块数据区域,可以理解成盒子,装一个数据
怎么定义?
数据类型 变量名称 = 初始值
- int age=21;
- double money=6.0
变量的核心点
装数据的
里面的数据可以改变
- = 进行赋值,从右往左执行
变量定义注意点
什么类型变量存储什么类型字面值
同一个范围变量名不能重复
变量定义时可以不用赋初始值,在使用时要有初始值
变量存在访问范围,从定义开始到 } 截止
ascll编码表
作用:美国为西方文字:英文,数字进行的一套编号规则
a 97
A 65
0 48
为什么要给字符编号
计算机要存字符但是不能直接存储字符,只能存储字符编号的二进制形式
结论:字符在计算机底层其实可以当整数使用的a就是97
关键字,标志符
关键字:Java自己保留的特殊单词,有特殊含义;不能用关键字,变量名作为类名
标志符
字母,数字,下滑线,$符号组成的名称
硬性要求
- 不能数字开头
- 不能关键字开头
- 不能是特殊符号
推荐要求
- 变量名称:有意义,全英文,首字母小写,满足驼峰模式
- 类名称:有意义,全英文,首字母大写,满足驼峰模式
类型转换
为什么要进行类型转换
存在不同类型的变量赋值给其他类型的变量
自动类型转换是什么样的
范围小的变量可以直接给范围大的变量赋值
什么是强制类型转换
可以强行将类型范围大的变量,数据赋值给范围小的变量进行运算
- 可能出现数据丢失
- 小数强制转换成整数是直接截断小数保留整数
数据类型 变量 =(数据类型)变量,数据
表达式的自动转换类型
小范围的类型会自动转换成大范围的类型运算
表达式的最终结果类型是由谁决定的
由最高类型决定
注意事项
byte short char 是直接转换成int 类型进行运算的
常用运算符
+的其他功能
与字符串做+运算时会被当成连接符,结果是字符串
能算就算,不能算放一起做字符串
自增自减注意事项
++,--如果在变量前后使用,并且包含其他操作,赋值或者在表达式中,放在前后有明显区别
- 变量前(++a)先进行+1,-1再拿变量值进行运算
- 变量后(a++)先拿变量值进行运算,再进行+1,-1
++,--单独使用无区别
= 赋值运算就是“=”
扩展
- +=
• 加后赋值
• a+=b等价于 a=(a的数据类型)(a+b);
- -=
• 减后赋值
• a-=b等价于 a=(a的数据类型)(a-b);
- *=
• 乘后赋值
• a*=b等价于 a=(a的数据类型)(a*b);
- /=
• 除后赋值
• a/=b等价于 a=(a的数据类型)(a/b);
- %=
• 取余后赋值
• a%=b等价于 a=(a的数据类型)(a%b);
注意
- 扩展的赋值运算符隐含了强制类型转换
逻辑运算符
逻辑与"&"
- 有一个为false,结果就是false
短路与"&&"
- 一个为false,结果是false。前一个为false,后一个条件就不执行了
逻辑或"|"
- 有一个为true,结果就是true
短路与"| |"
- 一个为true,结果是true。前一个为true,后一个条件就不执行了
逻辑非"!"
- !false=true,!true=false
逻辑异或"^"
- 相同是false,不同是true
注意
- 实际开发中常用逻辑运算符是:&&,| |,!
三元运算符
作用
- 根据条件作出分支选择,返回对应值
格式
- 条件表达式? 值1:值2
使用场景
- 一般只有两种情况的时候使用三元运算符会简化代码(如只有一个if eles语句)
运算符优先级
最高优先级是()
api
Application Programming Interface,应用程序编程接口
Java写好的程序,可以直接调用
键盘录入开发步骤
- 导包:import java.util.Scanner;
- 抄写代码得到扫描器对象:Scanner sc=new Scanner(System.in)
- 抄写代码等待接收用户输入的数据:sc.nextInt(),sc,next()
随机数开发步骤
- 导包:import java.util.Random;
- Random r = new Random();
- int number = r.nextInt(10)
- 注意
• 括号中的范围是【0-10)包左不包右,Java中大部分的范围规则都是包左不包右
• 可用加减法进行范围扩展得到所需范围
• 例:生成65-91之间的随机数
• 65 - 91=>(0-26)+65;减加法先减算出插值,在加上减数,注意包左不包右,所以括号要加1
• int number = r.nextInt(27) + 65;
object类
- 作用
• 一个类要么默认继承了Object类,要么间接继承了Object类,Object类是java中的祖宗类
• Object类的方法是一切子类都可以直接使用的
- 常用方法
• public String toString()
• 默认是返回当前对象在堆内存中的地址信息:类的全限名@内存地址(一般不重写的话可以省略不写)例:System.out.println(s)等同于System.out.println(s.toString());
• 父类的toString方法存在的意义就是被子类重写,以便返回对象的内容信息,而不是地址信息
• public Boolean equals(Object o)
• 默认是比较当前对象与另一个对象的地址是否相同,相同返回true,不同返回false(可以用“==”替代)
• 父类equals方法存在的意义也是被子类重写,以便子类自己来定义比较规则
• 官方在进行字符串比较时没有用对象自己的equals方法,而是选择了Objects(与Object类还是继承关系,jdk1.7以后才有)的equals方法比较结果一样,更安全
• Objects常见方法
• public static boolean equals(Object a,Object b)
• 比较两个对象的,底层会先进性非空判断,从而可以避免空指针异常。再进行equals比较
• 源码
• public static boolean equals(Object a,Object b){return (a==b)| |(a!=null&&a.equals(b));}
• public static boolean isNull(Object obj)
• 判断变量是否为null,为null返回true,反之
StringBuilder类
- 是一个可变的字符串类,我们可以把它看成是一个对象容器
- 作用
• 提高字符串的操作效率,如拼接,修改
• String s1="a";String s2=s1+"b";
• 一个加号,堆内存中两个对象,而StringBuilder将字符串存在常量池中,只在创建对象的时候有一个对象
- 构造器
• public StringBuilder()
• 创建一个空白的可变字符串对象,不包含任何内容
• public StringBuilder(String str)
• 创建一个指定字符串内容的可变字符串对象
- 常用方法
• public StringBuilder append(任意类型)
• 添加数据返回StringBuilder对象本身
• public StringBuilder reverse()
• 将对象内容反转
• public int length()
• 返回对象内容长度
• public String toString()
• 通过toString()就可以实现把StringBuilder转换为String
• 支持链式编程,例:sb1.append("a").append("b")append("c").reverse();
- 与String的区别
• String
• 内容是不可变的,拼接字符串性能差
• 定义字符串使用String
• StringBuilder
• 内容可变,拼接字符串性能好,代码优雅
• 拼接,修改字符串等操作使用StringBuilder
Math类
- 包含执行基本数字运算的方法,Math类没有提供公开的构造器
- 如何使用类中的成员
• 看类的成员是否都是静态的,如果是,通过类名就可以直接调用
- 常用方法
• public static int abs(int a)
• 获取参数绝对值
• public static double ceil(double a)
• 向上取整
• public static double floor(double a)
• 向下取整
• public static int round(float a)
• 四舍五入
• public static int max(int a,int b)
• 获取两个int值中较大的值
• public static double pow(double a,double b)
• 返回a的b次幂
• public static double random()
• 返回值为double的随机值,范围[0.0,1.0)
System类
- System的功能是通用的,都是直接用类名调用即可,所以System不能实例化
- 常用方法
• public static void exit(int status)
• 终止当前运行的Java虚拟机,非零表示异常终止
• public static long currentTimeMillis()
• 返回当前系统的时间毫秒值形式
• 计算机认为时间有起点的起始时间:1970年1月1日 00:00:00
• 时间毫秒值指从1970年1月1日走到此刻的总毫秒值。1s=1000ms
• 进行性能分析
• public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数)
• 数组拷贝
BigDecimal类
- 使用步骤
• 创建对象BigDecimal封装浮点型数据(最好的方式是调用方法)
• public static BigDecimal valueof(double val):包装浮点数成为BigDecimal对象
- 常用api
• public BigDecimal add(BigDecimal b)
• 加法
• public BigDecimal subtract(BigDecimal b)
• 减法
• public BigDecimal multiply(BigDecimal b)
• 乘法
• public BigDecimal divide(BigDecimal b)
• 除法
• public BigDecimal divide(另一个BigDecimal对象,精确几位,舍入模式)
• 除法
• BigDecimal c11=a11.divide(b11,2,RoundingMode.HALF_UP);
- 注意
• 禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象
• BigDecimal(double)存在精度损失风险
• BigDecimal g=new BigDecimal(0.1F);实际存储值为0.10000000149
• 优先推荐入参为String的构造方法,或使用BigDecimal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double的实际能表达的精度对尾数进行了截断
• BigDecimal recommend1=new BigDecimal("0.1");
• BigDecimal recommend2=BigDecimal.valueOf(0.1);
- 作用
• 解决浮点型运算的精度失真问题
Date类
- Date类的对象在Java中代表的是当前所在系统的此刻日期时间
- 构造器
• public Date()
• 创建一个Date对象,代表的是系统当前此刻日期时间
• public Date(long time)
• 把时间毫秒值转换成Date日期对象
- 常用方法
• public long getTime()
• 获取时间对象的毫秒值
• public void setTime(long time)
• 设置日期对象的时间为当前时间毫秒值对应的时间
- 记录时间的两种形式
• 日期对象
• 创建一个日期对象代表了:当前系统的此刻日期时间对象
• Date d=new Date();
• System.out.println(d);
• 时间毫秒值
• 获取当前的时间毫秒值
• long time=d.getTime();
• System.out.println(time);
SimpleDateFormat类
- 作用
• 可以对Date对象或时间毫秒值格式化成我们喜欢的时间形式
• 也可以把字符串的时间形式解析成日期对象
- 构造器
• public SimpleDateFormat()
• 构造一个SimpleDateFormat,使用默认格式
• public SimpleDateFormat(String pattern)
• 构造一个SimpleDateFormat,使用指定的格式
- 格式化方法
• public final String format(Date date)
• 将日期格式化成日期/时间字符串
• public final String format(Object time)
• 将时间毫秒值格式化成日期/时间字符串
- 对应关系
• y-年
• M-月
• d-日
• H-时
• m-分
• s-秒
• 例
• 2020-11-11 13:27:06-yyyy-MM-dd HH:mm:ss
• 2020年11月11日 13:27:06-yyyy年MM月dd日 HH:mm:ss
- 解析字符串成为日期对象
• public Date parse(String source)
• 从给定的字符串开始解析文本以生成日期
• String dateStr="2020年11月11日 13:27:06";
• SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
• Date d=sdf.parse(dateStr);
Calendar类
流程控制
分支结构
if
- 作用:根据条件有选择的执行代码
- 格式
• if(条件)(执行代码)
• 注意
• 如果{}中只有一行代码,可以省略{}不写,不建议省略
• 只能执行一个分支
• if(条件1){执行代码}else{其他代码}
• if(条件1){执行代码1}else if(条件2){执行代码2}...else{其他代码}
switch
- switch(表达式){ case 值1: 执行代码; break;} case 值n-1: 执行代码; break;} default: 执行代码; }
- 表达式类型只能是byte,short,int,char,jdk5开始支持枚举,jdk7开始支持String,不支持double,float,long
- case给出的值不允许重复,且只能是字面值,不能是变量
- 穿透性
• 如果case中没有写break,执行完这个case会直接往下一个case执行,不会判断了,直到遇到break截止
• 存在多个case分支的功能代码是一样时,可以用穿透性把流程集中到同一处处理,这样可以简化代码
- 注意别忘了分析所有情况都没有的情况放在default里
使用场景
- switch分支结构
• 判断值匹配时
- if分支结构
• 判断区间范围时
循环结构
while
- 初始化语句
• while(循环条件){循环体语句(被重复执行的代码);迭代语句:}
do-while循环
- 先执行再判断
• 初始化语句:do{循环体语句;迭代语句;}while(循环条件)
- 注意:一定会先执行一次循环体
- 业务举例
• 抢票系统会先抢一次票再循环
for循环
- 用for循环求奇数和
• 方式一:for(int i =1;i <= 10; i++){if (int i % 2 == 1){}}
• 方式二:for (int i = 1; i <= 10; i +=2 ){}
- for循环的格式
• for(初始化语句:循环条件:迭代语句){循环体语句}
• 变为while循环
• for(:循环条件:){循环体语句;}
- 在用for循环时,控制内层循环何时需要返回值时,可以在内层循环外加信号位标记,一般信号位默认为true,当循环结束还为true时则记录该值
三种循环的差别
- for和while是判断后执行;do -while是直接执行一次,再判断
- for和while功能上没有任何区别,while能做的for一定能做
- for的变量只能循环内部有效,while的变量从定义开始到循环体结束后还能被使用(一般在循环外定义变量)
- 使用关系
• 不知道次数的用while
• 知道次数的用for
死循环
- for(;;){循环体代码;}
- while(true){循环体语句;}
- do{循环体语句;}while(true);
循环嵌套
- 形式:循环中又包循环
- for(int i = 0 ; i < 3 ; i++){for(int j = 0 ; j < 5 ; j++){循环体语句}}
- 外部循环每执行一次,内部循环全部执行完一次
跳转控制语句
continue关键字
- 跳出当前循环的当次执行,进入循环下一次
- 只能在循环中使用
break关键字
- 跳出并结束当前所在循环的执行
- 只能用于结束所在的循环,或者结束switch分支的执行
return关键字
- 无返回值时跳出并结束当前所在方法,有返回值时将返回值返回并结束当前方法
数组
数组定义
静态初始化写法
- 完整格式:数据类型[] 数组名 =new 数据类型[]{元素1,元素2,元素3...};
- 简化格式:数据类型[] 数组名 = {元素1,元素2,元素3...};
动态初始化写法
- 数据类型[] 数组名 =new 数据类型[长度];
使用场景
- 动态初始化
• 只指定数组长度,后期赋值,适合开始就知道数据的数量,但是不确定具体元素值的业务场景
- 静态初始化
• 开始就存入元素值,适合一开始就能确定元素值的业务场景
- 两种格式写法是独立的,不可以混用
元素默认值规则
基本类型
- byte,short,char,int,long
• 0
- float,double
• 0.0
- boolean
• false
引用类型
- 类,接口,数组(数组嵌套),String
• null
属于引用数据类型,变量名存储的数组在内存中的地址信息
[I@4c873330; [:代表数组 I代表数组数据类型 @代表地址在哪
数组的访问
数组名称[索引]
数组的长度属性:length
- 最大索引表示方法:数组名.length -1;前提是个数大于0
注意事项
数据类型[] 数组名 也可以写成 数据类型 数组名[]
什么数据类型就存储什么类型的数据,否则报错
数组一旦定义出来程序执行的过程长度和类型就固定了
如果访问元素位置超过最大索引,执行时会出现ArrayIndexOutOfBoundsException(数组索引越界异常)数组索引从0开始
如果数组变量中没有存储数组的地址,而是null,在访问数组信息时会出现NullPointerException(空指针异常)
数组应用
数组求和
- 使用数组存储批量元素
- 遍历数组中每个元素然后求和
数组元素求最大值
- 使用数组存储数据
- 定义变量记录最大值,建议存储数组第一个元素为最大值,防止自定义的最大值比数组中元素最大值还大
- 遍历数组元素,如果该元素大于变量存储的元素值则替换
- 循环结束输出最大值即可
猜数字游戏
- 动态初始化数组存入5个随机的1-20之间的数据
- 定义一个死循环,不断才数据,遍历数组,判断是否在数组中,如果在结束死循环,否则继续
- 注意break只能跳出当前循环,要想跳出整个循环,可以给死循环定义名称,然后直接break 该名称;即可例:out: while(true){ for(;;){ break out;}}
随机排名
- 定义一个动态初始化数组用于录入数据
- 遍历数组每个元素,每次随机一个索引值,让当前元素和该索引位置的元素进行交换
- 比那里输出数组元素内容即可
- 注意
• 交换需要定义一个临时变量来辅助
• 用Random方法随机索引值时括号里的范围最好填数组长度,方便以后数组长度改变时不用再逐一修改,可用性强
冒泡排序
- 思想
• 从头开始两两比较,把最大的元素与最小的元素进行交换
• 每轮把当前最大的一个元素存入到数组当前的末尾
- 步骤
• 定义外部循环,确认总共需要几轮比较:数组长度-1
• 定义内部循环,控制每轮依次往后比较几次:数组长度-i
• 如果当前位置的元素>后一个元素的元素值,两者交换
- 注意
• 如果外层循环从1开始则内层循环的循环条件是数组长度-i
• 如果外层循环从0开始则内层循环的循环条件是数组长度-i-1
注意事项
- 尽量用数组给的属性来代表变量,length
java内存分配
栈
方法运行时所进入的内存,变量也是在这里
堆
new出来的东西会在这里开辟空间并产生地址
方法区
字节码(class)文件加载时进入的内存
本地方法栈
寄存器
方法
方法修饰符 返回值类型 方法名称 (形参列表){方法体代码(需要执行的功能代码) return 返回值;}
(public static)(int)(add)(int a,int b){int c = a + b ; return c ;}
方法参数
形参
- 在方法定义时的变量
实参
- 在方法内部定义的变量
java传输机制
值传递,传输的是实参存储的值(方法中改变不了相当于拷贝)(如果传输的是地址则有可能会改变地址中的值,但是地址还是不变)
- 基本数据类型
• 传输的是存储的数据值
- 引用数据类型
• 传输的是地址值
方法重载
同一个类中多个方法名称相同,形参列表不同
对于相似性业务场景:可读性好,方法名称相同提示是同一类型的功能,通过形参列表不同实现功能差异化的选择,这是一种专业的代码设计
识别技巧
- 只要同是一个类中,方法名称相同(区分大小写),形参列表不同,那么他们就是重载方法,其他都不管(修饰符,返回值类型都无所谓)
- 形参列表不同是指:参数的个数,类型,顺序不同,不关心参数的名称
重载方法中可以调用别的重载方法(例:传一个参数的可以调用传两个参数的方法,只需要给另一个参数赋值即可),减少代码量
注意
如果方法声明了返回值类型,内部必须使用return返回对应类型的数据
方法不需要返回结果,返回值必须声明成void(无返回值类型),此时方法内部不可以使用(return返回数据)
形参列表可以有多个,甚至可以没有,如果有多个形参,多个形参必须用","隔开,且不能给初始值
方法要执行必须进行调用:方法名称(...)
方法编写顺序无所谓
方法和方法是平级关系,不能嵌套定义
return语句下面不能写代码,永远无法执行无效代码
不调用就不执行调用必须严格匹配方法参数情况
有返回值的方法调用时可以定义变量接收结果,或者直接调用输出语句,甚至直接调用;无返回值的调用只能直接调用一下
一般功能性的代码都放在方法中方便后续调用
面向对象
类和对象
类是共同特征的描述
对象是真实存在的具体实例
- 如何得到对象
• public class 类名{1.成员变量(代表属性的,一般是名词)2.成员方法(代表行为的,一般是动词)}
• 类名 对象名 =new 类名();
- 拿到后能做什么
• 对象.成员变量
• 对象.成员方法
- 放在堆内存中
- 是引用类型,变量存储的是堆内存的地址
- 对象中,成员变量的数据放在堆内存中
注意事项
- 格式
• 修饰符 数据类型 变量名称 =初始化值;一般不用指定初始化值,存在默认值
- 类名首字母建议大写,具有意义,满足“驼峰模式”
- 一个Java文件中可以定义多个class类,且只能一个类是public修饰,而且public修饰的类名必须成为代码文件名。实际开发中建议还是一个文件一个class类
构造器
作用
- 用于初始化一个类的对象,并返回对象的地址
定义格式
- 修饰符 类名(形参列表){}
初始化对象格式
- 类型 变量名称 = new 构造器;
- Car c =new Car();
分类
- 无参构造器(默认存在的):初始化对象时,成员变量的数据均采用默认值
- 有参构造器:在初始化对象时,同时可以为对象进行赋值
注意
- 任何类定义出来,默认就自带了无参数构造器,写不写都有
- 一旦定义了有参数构造器,无参数构造器就没有了,此时就需要自己写无参构造器了
权限修饰符
用来控制一个成员能够访问的范围
可以修饰成员变量,方法,构造器,内部类,不同权限修饰符修饰的成员能被访问的范围将受到限制
范围大小:private->缺省->protected->public
- private
• 同一个类中
- 缺省
• 同一个类中
• 同一个包中其他类
- protected
• 同一个类中
• 同一个包中其他类
• 不同包下的子类
- public
• 同一个类中
• 同一个包中其他类
• 不同包下的子类
• 不同包下的无关类
要求
- 成员变量一般私有化
- 方法一般公开
- 如果该成员只希望本类访问,使用private修饰
- 如果该成员只希望本类,同一个包下的其他类和子类访问,使用protected修饰
final关键字
- 是最终的意思,可修饰方法,变量,类
- 修饰方法:表明该方法是最终方法,不能被重写
- 修饰变量:表示该变量第一次赋值后不能再被赋值(有且只有一次赋值)
• 基本不会修饰实例成员变量,无意义
• 修饰基本数据不能发生改变
• 修饰引用类型变量地址值不能发生改变,地址指向的内容可以改变
- 修饰类:表示该类是最终类,不能被继承
常量
常量是使用public static final修饰的成员变量,必须有初始化值,而且在执行的过程中其值不可改变
好处
- 可以用于系统的配置信息,方便程序的维护,同时也能提高可读性
- 常量命名规范
• 英文单词全部大写
• 多个单词下划线连接起来
执行原理
- 在编译阶段会进行“宏替换”,使用常量把地方全部替换成真是字面量
- 好处是让使用常量的程序执行性能与直接使用字面量是一样的
枚举
是Java的一种特殊类型
作用
- 为了做信息标志和分类
格式
- 修饰符 enum 枚举名称{ 第一行都是罗列枚举类实例的名称 }
- enum Season{SPRING,SUMMER,AUTUMN,WINTER; }
特征
- 枚举类都是继承了枚举类型:java.lang.Enum
- 枚举都是最终类,不可被继承
- 枚举类的构造器都是私有的,枚举对外不能创建对象
- 枚举类的第一行默认都是罗列枚举对象的名称的
- 枚举类相当于是多例模式
使用场景
- 变量
• 具体值
- 枚举
• 做分类的时候
• 枚举是对象没有值
编译器会将枚举转换成常量定义,一般枚举的代码约束性好,入参值受控制,不像变量入参不受限制(例:调用方法时,传参可以写枚举中定义的名称,有效的防止代码漏洞)
抽象类
某个父类知道其所有子类所要完成的某种功能,但是每个子类完成情况不一样,父类就只定义该功能的基本要求,具体由子类完成,这个类可以是一个抽象类,抽象类就是一种不完全的设计图,只给框架
必须使用abstract修饰
- 修饰符 abstract class 类名{}
抽象方法
- 就是抽象类中定义的子类必须完成的功能基本要求
- 修饰符 abstract 返回值类型 方法名称(形参列表);
- 没有方法体,只有方法签名,必须用abstract修饰
注意
- 一个类如果继承了抽象类,那么这个类必须重写完抽象类的全部抽象方法
- 或者这个类也定义成抽象类(再被其他子类继承重写抽象方法)
特征
- 有得有失
• 得到抽象方法,失去了创建对象的能力
- 为什么不能创建对象
• 类有的成员(成员变量,方法,构造器)抽象类都具有
• 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
• 一个类继承了抽象类必须重写完抽象类的所有抽象方法,否则这个类也要成为抽象类
• 不能用abstract修饰变量,代码块,构造器
- final和abstract关系
• 互斥关系
• abstract定义抽象类作为模板让子类继承,final定义的类不能被继承
• 抽象方法定义通用功能让子类重写,final定义的方法子类不能重写
• 模板方法建议用final
• 模板方法是给子类直接使用的,不让子类重写的,一旦子类重写了模板方法就失效了
接口
格式
- 使用interface关键字来定义
- public interface 接口名{ //常量 //抽象方法}
特点
- jdk8之前接口中只能是抽象方法和常量,没有其他成分了
- 接口不能实例化(创建对象)
- 接口中的成员都是public修饰的,写不写都是,因为规范的目的是为了公开化
用法
- 接口是用来被类实现的,实现接口的类称为实现类,实现类可以理解成所谓的子类
- 修饰符 class 实现类 implements 接口1,接口2,接口3...{}
- 实现关键字:implements
- 从上面看出,接口可以被类单实现,也可以被类多实现
- 接口是干爹,实现类可有多个干爹,父类是亲爹,实现类只有一个亲爹
方法
- 默认方法
• 必须用default修饰
• 默认会用public修饰。需要用接口的实现类的对象来调用
- 静态方法
• 默认会public修饰,必须static修饰
• 注意
• 接口的静态方法必须用本身的接口来调用
- 私有方法
• 默认会public修饰,必须用private修饰,从jdk1.9才开始有的
• 只能在本类中被其他的默认方法或私有方法访问
注意
- 一个类实现接口,必须重写完全部接口的全部抽象方法,否则这个类需要定义成抽象类
- 接口不能创建对象
- 一个类实现多个接口,多个接口中同样的静态方法不冲突
- 一个类实现了多个接口,多个接口存在同名的默认方法,不冲突,这个类重写该方法即可
- 一个接口继承多个接口是没问题的,如果多个接口存在规范冲突则不能多继承
关键字
this关键字
- 代表当前对象的地址(谁调用他就代表谁)(本类对象的引用)
- 可以用于访问当前对象的成员变量
super关键字
- 代表父类存储空间的标识
区别
- this
• this.成员变量,访问本类成员变量
• this.成员方法(...)访问本类成员方法
• this(...)访问本类构造器
- super
• super.成员变量访问父类成员变量
• super.成员方法(...)访问父类成员方法
• super(...)访问父类构造器
注意
- 子类通过this(...)去调本类的其他构造器,本类的其他构造器会通过super去手动调用父类的构造器,最终还是会调用父类的构造器
- 子类只会调用父类无参构造器,想要调用有参构造器用super
- this(...)和super(...)必须都只能放在构造器第一行,所以二者不能共存在同一个构造器中
三大特征
封装
- 面向对象的三大特征之一(可以使用时尽量使用),合理隐藏,合理暴露
- 一般会把成员变量使用private隐藏起来
- 通过getter和setter方法暴露其访问
- 好处
• 加强了程序代码的安全性
• 适当的封装可以提升开发效率,同时可以让程序更容易理解和维护
继承
- 好处
• 继承是子类到父类的一种关系
• 提高代码复用性,减少代码冗余,增添类的功能扩展性
- 格式
• 子类 extends 父类
- 特点
• 子类继承父类,子类可以得到父类的属性和行为,子类可以用(可以继承父类的私有成员,但是不能直接访问)
• 子类能否继承父类的静态成员
• 个人认为不能因为静态成员是共享的子类可以直接访问,共享并非继承
• 子类不能继承父类的构造器,子类有自己的构造器,父类构造器用来初始化父类对象
• 子类所有构造器都会默认先访问父类中无参构造器,再执行自己
• 原因
• 子类在初始化的时候有可能会使用到父类中的数据,如果父类没有完成初始化,子类无法访问父类的数据
• 子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化(继承父类数据)
• 怎么调用的
• 子类构造器的第一行语句默认是super(),不写也存在
• 如果父类没有无参构造器会报错,需要手动书写super(...)手动调用父类的有参构造器
• 一个类只能继承一个直接父类
• 子类访问成员原则
• 就近原则
• 子类局部范围
• 子类成员范围
• 父类成员范围
• 出现重名的成员优先使用子类的,如果一定要用父类的可以用super关键字,指定访问父类成员
• super.父类成员变量/父类成员方法
• Java中不支持多继承,但是支持多层继承
• Java中所有类都是Object类的子类
• Java中子类功能更强大
- 设计规范
• 子类们相同的特征(共同属性,共性方法)放在父类中定义
• 子类独有的属性和行为应该定义在子类自己里面
- 方法重写
• 在继承体系中,子类出现了和父类一摸一样的方法声明,我们就称子类的方法是重写方法
• 应用场景
• 当子类需要父类功能但父类该功能不能完全满足自己的需求
• 子类可以重写父类方法
• 案例
• 旧手机功能只是打电话,发短信
• 新手机功能要打电话下支持视频通话,发短信下支持发语音和图片
• @Override重写注释
• 放在重写后的方法上,校验是否正确重写方法
• 加该注释如果重写错误,编译阶段会有错误提示
• 建议都加上注解,安全优雅
• 注意
• 重写方法的名称,形参列表必须与重写方法的名称和参数列表一致
• 私有方法不能被重写
• 子类重写方法时,访问权限必须大于等于父类(缺省<protected<public)
• 子类不能重写父类静态方法,如果重写会报错
多态
- 定义
• 同类型的对象,执行同一个行为,会表现出不同的行为特征
- 常见形式
• 父类类型 对象名称=new 子类构造器;
• 接口 对象名称=new 实现类构造器;
- 访问特点
• 方法调用
• 编译看左,运行看右
• 变量调用
• 编译看左,运行也看左(多态侧重行为多态)
- 前提
• 有继承/实现关系;父类引用指向子类对象;有方法重写
- 类型转换
• 自动转换类型
• 从子到父
• 子类对象赋值给父类类型的变量指向
• 强制类型转换
• 从父到子
• 此时必须进行强制类型转换
• 子类 对象变量=(子类)父类类型的变量
• 作用
• 可以解决多态下的劣势,可以实现调用子类独有功能
• 注意
• 如果转型后的类型和对象真实类型不是同一种类型,那么在转换时就会出现类型转换异常ClassCastException
• Animal t =new Tortoise();
• Dog d=(Dog)t;//出现异常ClassCastException
• Java建议强制类型转换前用instanceof判断当前对象的真实类型,再进行强转
• 变量名 instanceof 真实类型
• 判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,是则返回true,反之
• if(a instanceof Tortoise{Tortoise t =(Tortoise)a;t.layEggs();}else if(a instanceof Dog){DOg d1=(Dog) a; d1.lookDoor();})
- 优势
• 在多态形势下,右边对象可以解耦合,便于扩展和维护
• Animal a=new Dog();
• a.run()//后续业务行为随对象而变,后续代码无需修改
• 定义方法时使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利
- 劣势
• 多态下不能使用子类的独有方法
内部类
内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)
- public class People{public class Heart{}}
使用场景,作用
- 当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构可以选择使用内部类来设计
- 内部类通常可以方便访问外部类成员,包括私有成员
- 内部类提供了更好的封装性,内部类本身就可以用private protected等修饰,封装性可以做更多控制
静态内部类
- 有static修饰,属于外部类本身
- 他的特点和使用与普通类完全一样的,类有的成分它都有,只是位置在别人里面而已
• public class Outer{//静态成员内部类public static class Inner{}}
- 静态内部类创建对象格式
• 外部类名.内部类名 对象名=new 外部类名.内部类构造器;
• Outer.inner in=new Outer.Inner();
- 访问扩展
• 静态内部类可以直接访问外部类的静态成员,外部类的静态成员只有一份可以被共享访问
• 静态内部类中不可以直接访问外部类的实例成员,外部类的实例成员必须用外部类对象访问
- 使用场景
• 如果一个类包含了一个完整的成分,如汽车类中的发动机类
• 特点,使用场景与普通类一样的,类的成分他都有,只是位置在别人里面而已
• 可以直接访问外部类的静态成员,不能直接访问外部类的实例成员
• 开发实际中用的比较少
成员内部类
- 无static修饰,属于外部类的对象
- jdk16之前,成员内部类中不能定义静态成员,jdk16开始也可以定义静态成员了
• public class Outer{//成员内部类public class Inner{}}
- 成员内部类创建对象格式
• 外部类.内部类 对象名=new 外部类构造器().new 内部类构造器();
• Outer.Inner in=new Outer().new Inner();
- 访问扩展
• 成员内部类中可以直接访问外部类的静态成员,外部类的静态成员只有一份可以被共享访问
• 成员内部类的实例方法中可以直接访问外部类的实例成员,因为必须现有外部类对象才能有内部类对象,所以可以直接访问外部类对象的实例成员
匿名内部类
- 本质上是一个没有名字的局部内部类,定义在方法中,代码块中等
- 作用
• 方便创建子类对象,最终的目的为了简化代码编写
- 格式
• new 类|抽象类名|或者接口名(){重写方法;};
• Employee a =new Employee(){public void work(){}};a.work();
- 特点
• 匿名内部类是一个没有名字的内部类
• 匿名内部类写出来就会产生一个匿名内部类的对象
• 匿名内部类的对象类型相当于是当前new的那个的类型的子类类型
• 匿名内部类可以作为方法的实际参数进行传输
• 开发中并不是我们主动去定义匿名内部类的,而是别人需要我们写或者我们可以写的时候才会使用,匿名内部类的代码可以实现进一步的简化
JavaBean
也可以理解成实体类,其对象可以用于在程序中封装数据
要求
- 成员变量使用private修饰
- 提供每一个成员变量对应的setXxx()/getXxx()
- 必须提供一个无参构造器
成员变量和局部变量
区别
- 类中的位置不同
• 成员变量:类中,方法外
• 局部变量:常见于方法中
- 初始化值不同
• 成员变量:有默认初始化值
• 局部变量:没有,使用之前需要完成赋值
- 内存位置不同
• 成员变量:堆内存
• 局部变量:栈内存
- 生命周期不同
• 成员变量:随着对象的创建而存在,随着对象的消失而消失
• 局部变量:随着方法的调用而存在,随着方法的运行结束而消失
- 作用域
• 局部变量:在所归属的大括号中
成员变量分类和访问
- 静态成员变量(有static修饰,属于类,加载一次可以被共享访问)
• 类名.静态成员变量(推荐)
• 对象.静态成员变量(不推荐)
- 实例成员变量(无static修饰,属于对象,没对象就不加载)
• 对象.实例成员变量
- 什么情况定义
• 静态成员变量
• 表示在线人数等需要被共享访问的信息
• 实例成员变量
• 属于每个对象,且每个对象信息不同时(name,age等)
成员方法
静态成员方法(有static修饰,属于类和对象共享)
- 类名.静态成员方法
- 对象.静态成员方法(不推荐)
- 注意
• 同一个类中访问静态成员,类名可以不写
• 静态方法只能访问静态的成员,不可以直接访问实例成员
• 静态方法中是不能出现this关键字的
实例成员方法(无static修饰,属于对象)
- 对象.实例成员方法
- 注意
• 实例方法可以访问静态的成员,也可以访问实例成员
使用场景
- 表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法
- 如果该方法是执行一个通用功能为目的,或者需要方便访问,则可以申明成静态方法
工具类
对于一些应用程序中多次使用的功能,可以将这些功能封装成静态方法,放在一个类中,这个类就是工具类
作用
- 方便调用
- 提高了代码复用
注意
- 建议将工具类的构造器私有化,不让工具类对外产生对象(防止有人不知道,调用构造器)
为什么不用实例方法做工具类
- 实例方法需要创建对象调用,此时用对象只是为了调用方法,这样会浪费内存
代码块
是类的5大成分之一(成员变量,构造器,方法,代码块,内部类),定义在类中方法外
在Java类下,使用{}括起来的代码被称为代码块
分类
- 静态代码块
• 格式:static{}
• 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次
• 使用场景:在类加载的时候做一些静态数据初始化以便后续使用,使用静态代码块完成数据初始化操作,代码优雅(例如先把54张牌先初始化)
- 构造代码块
• 格式:{}
• 特点:每次创建对象调用构造器执行时都会执行该代码块中的代码,并且在构造器执行前执行
• 使用场景:初始化实例资源
设计模式
单例模式
- 可以保证系统中,应用该模式的类永远只有一个实例,即一个类永远只能创建一个对象
- 场景和作用
• 例如任务管理器对象只用一个就行了,可以节省空间
- 饿汉单例模式
• 在类获取对象的时候,对象已经提前创建好了,直接调用就行了不用再new
• 设计步骤
• 定义一个类,把构造器私有
• 定义一个静态变量存储本类对象,初始化对象(可以将静态成员变量私有,防止别人调方法时调错误以为是方法)
• 提供一个返回单例对象的方法,让其他位置可以调用获取一个对象
- 懒汉单例设计模式
• 在真正需要该对象的时候,采取创建一个对象(延迟加载对象)
• 设计步骤
• 定义一个类,把构造器私有
• 定义一个静态变量存储一个对象,此时不能初始化对象
• 提供一个返回单例对象的方法,让其他位置可以调用获取一个对象
- 区别
• 有没有初始化对象
String
String
String字符串类型,可以定义字符串变量指向字符串对象
String变量每次的修改其实都是产生并指向新的字符串对象
原来的字符串对象都是们没有改变的,所以称不可变字符串
创建字符串对象的两种方式
直接定义:String name =”java";推荐使用
通过String类的构造器创建对象
- public String();创建空白字符串对象,不含任何内容
- public String(String original)根据传入的字符串内容,创建字符串对象
- public String(char[] chs)根据字符数组的内容创建字符串对象
- public String (byte[] chs)根据字节数组的内容创建字符串对象
面试题
- 两种方式有什么区别
• 以" "方式给出的字符串对象,在字符串常量池中存储(不管出现在哪里见面试题),而且相同内容只会存储一份
• 通过构造器new对象,每次new一次就会创建一个新对象放在堆内存中分开存储
• 证明代码:String s1="abc";String s2="abc";System.out.println(s1==s2)//true
• char[] chs={'a','b','c'};String s3=new String(chs);String s4=new String(chs);System.out.println(s3==s4)//false
- String s2 =new String("abc");//此时不仅在字符串常量池中创建字符,也在堆内存中创建字符串对象,但是s2是引用类型存的是数据地址,String s1="abc";//这里不在字符串常量池创建字符System.out.println(s1==s2)//false
- java存在编译优化机制,程序在编译时:"a"+"b"+"c"会直接转成"abc"
字符串内容比较:推荐使用String类提供的"equals"比较,==在比较基本数据类型时使用
public boolean equals (Object anObject)将此字符串与指定对象进行比较,只关心字符内容是否一样
public boolean equalsIgnoreCase(String anotherString)将此字符串与指定对象进行比较忽略大小写比较字符串,只关心字符内容是否一样
常用api
public int length();返回字符串长度
public char chaAt(int index);获得某个索引位置的字符
public char[] toCharArray():将当前字符串转换成字符数组返回
public String substring(int beginIndex,int endIndex)根据开始和结束索引进行截取,截取到末尾,得到新的字符串(包前不包后)
public String substring(int beginIndex)从传入的索引截取,截取到末尾,得到新的字符串
public String replace(CharSequence target,CharSequence replacement)使用新值,将字符串中的就只替换,得到新的字符串
public String[] split(String regex)根据传入的规则切割字符串,得到字符串数组返回
用String的业务
验证码
- 定义可能出现的全部字符
- 循环n次每次随机生成一个索引,提取对应位置的字符连接在一起(charAt方法)
- 好处:代码简单
手机号屏蔽
- 键盘录入一个字符串
- 截取字符串前三位,后四位(substring方法)
- 将截取后的两个字符串加上“****”进行拼接,输出结果
敏感词替换
- replace方法
集合
ArrayList集合
集合的一种支持索引
对象获取
- public ArrayList()创建一个空的集合对象
集合添加元素
- public boolean add(E e)将指定元素添加到集合的末尾
- public void add(int index,E element)再次集合中的指定位置插入指定的元素
如何创建对象添加元素
- ArrayList list =new ArrayList();
- public boolean add(E e)
- public void add(int index,E element)
泛型概念
- ArrayList<E>就是泛型类,可在编译阶段约束集合对象只能操作某种数据类型
- ArrayList<String> list=new ArrayList<>();从jdk1.7开始泛型后面的类型声明可以不写
- 集合中只能存储引用类型,不支持基本数据类型
• ArrayList<String>只操作字符串类型
• ArrayList<Integer>只操作整数类型
要求:使用泛型,即使集合要接所有数据类型也要写Object
常用方法
- public E get(int index)返回指定索引处的元素
- public int size()返回集合中的元素个数
- public E remove(int index)删除指定索引处的元素,返回被删除的元素
- public boolean remove(Object o)删除指定的元素,返回删除是否成功
- public E set(int index,E element)修改指定索引处的元素,返回被修改的元素
注意
- 从集合筛选元素并删除,需要从集合后面遍历,可以避免漏掉元素(元素会自动移位置)