java面试复习巩固
韩顺平Java__哔哩哔哩_bilibili
1、Java中源文件中可以有多个类,最多只能有一个public类?
程序分为编译和执行两个阶段。
编译阶段
如果存在public类,那么一个源文件中只能够存在一个而且要与源文件的名字相同。----------否则编译会报错
如果不存在public类,那么程序也可以成功编译。
执行阶段
只有存在main()方法程序就可以执行,和public类无关。
也就是必须要有main方法,可以没有public类,main也可以不在public类中,只要程序能找到启动的main就行,不管有多少个main方法。
而找到的话默认从public类中找,所以public类必须与文件同名,否则编译报错。
没有public类只要指定一个类并且该类有main就行。
参考:为什么Java源文件只能有一个public类?
2、变量
定义变量=声明+赋值
三要素:变量名、值、类型
基本数据类型:char\int\double\float\byte\long\short\boolean
3、浮点数细节
float4字节、double8字节
浮点型常量默认为double
float a=1.1;错误
float b=2.2f;正确
double c=3.3;正确
double d=4.4f;正确
科学计数法形式:3.14e12、66.6e-3
精度问题:2.7!=8.1/3
判断在一定范围内就行:Math.abs(a-b)<1e-6;
4、算术运算符
+-*/ ++ -- %
除法注意数据类型转换
取模:a%b=a-a/b*b
10%3=1;
-10%3=-1;
10%-3=1;
-10%-3=-1;
练习:
int i=1;
i=i++;
//i=1
/*
因为会使用temp临时变量。temp=i,i=i+1,i=temp;
所以i=1;
*/
int i=1;
i=++i;
//i=2
/*
还是用temp,i=i+1,temp=i,i=temp;
i=2
*/
5、运算符优先级
括号、单目、算术、位移、比较、逻辑、三元、赋值
6、标识符
规则:
规范:
7、switch细节
8、循环细节
for循环
循环条件表达式返回一个布尔值的表达式
循环初始值和迭代可多条语句,但必须类型一样
for(int i=0,j=1;i<10;i++,j+=1){}
while循环
循环条件仍是返回布尔值的表达式
先判断再执行
9、数组
数组名.length
int a[]=new int[5];
int a[] int[] a //声明 为null
a=new int[10]; //分配空间
int a[1]={1}
10、类与对象
类是一种数据类型。对象是它的实例
对象在内存中存在形式:
创建对象:
Cat a; /*null*/a=new Cat();
Cat b=new Cat();
内存分配机制:
内存结构:
栈:一般存基本数据类型、变量
堆:存放对象
方法区:常量池、类加载
举例:
输出:小明
200
空指针异常
基本数据类型值传递,引用数据类型传递地址
11、方法重载
方法名必须相同,形参类型、个数、顺序至少一个不一样,返回类型随意。
12、作用域
13、构造器
细节:
1、构造器可以重载
2、构造器与类名要一样
3、构造器无返回值
4、构造器是完成对象初始化、不是创建对象
5、创建对象时,系统自动调用该类的构造方法
6、系统默认有无参构造器
7、一旦定义了自已的构造器,则无默认构造器
对象创建流程:
- 加载Person类信息
- 堆中分配空间
- 完成对象初始化,先默认初始化,再显式初始化、最后构造器初始化
- 将对象的地址返回给引用的变量
14、this
this代表当前对象。
15、包
不同的包下可重名类,不同级目录用.隔开
用不同包名区分
a.cat cat1=new a.cat();
b.cat cat2=new b.cat();
16、访问修饰符
17、封装
把抽象出的属性和方法封装在一起。程序的其它部分只有通过被授权的方法才能进行操作。
好处:隐藏实现细节,可以对数据进行验证,保证安全合理。
一般步骤:属性private。设置set\get方法
封装与构造器:构造时也用set方法验证
this.name=name;//×
setName(name);//√
18、继承
提高代码复用性。
class 子类 extends 父类{}
细节:
- 子类继承了所有的属性和方法。但是私有属性/方法不能在子类直接访问,要通过公共的方法访问。
- 子类必须调用父类的构造器完成父类的初始化
- 当创建子类对象时,不管使用子类的哪个构造器,默认调用父类的无参构造器。若父类没有无参构造器,子类构造器中必须用super指定用父类的哪个构造器,否则编译不通过。
- super()与this()不能共存在一个构造器
- 子类最多只能继承一个父类
查找某一属性,从子类一直到父类递归访问,直到Object都没有那就是没有可访问的该属性,会报错。(无权限访问则直接报错不再递归)
练习:(黄色的为后添加的答案)
19、多态
方法和对象体现多态
方法的重载与重写体现多态。
对象的多态:
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时确定,不能改变
- 运行类型是可以变化的
- 编译类型看定义时=号的左边,运行类型看等号的右边
- 编译从Object到父类结束(限制能找到的方法),运行则是从子类开始找(最终效果看子类的实现)
- 属性没有重写之说,具体调用哪个看编译类型
20、Object类关键方法
public boolean equals(Object obj) //举例,重写equals
{
if(this ==obj)
{
return true;
}
if(obj instanceof Person)
{
Person p=new (Person) obj;
return this.name.equals(p.name) && this.age==p.age;
}
return false;
}
练习
object的equals默认判断对象的地址是否相等
==判断引用的值是否一样(是否指向同一对象),基本数据类型比值
String重写了equals,比较值是否相等
答案:FTFTF
答案:TTTFT编译错误,无法进行类型比较
toString方法
21、String
方法:
substring(0,5)
substring(7)//到最后
trim()//去开头结尾的空格
split(“\\s”)//正则分割,返回String数组
indexOf("wor")
indexOf("a",0)//0处开始查找
length()
isEmpty()
charAt()
valueOf()//其它数据类型转为字符串
toCharArray()
concat()
字符串常量池:
创建字符串对象时先在常量池里创建(池里没有),再在堆里创建。String s=new String("aaas")创建了两个对象。若常量池有则只创建一个对象。
用String s="aaa"创建字符串引用,则会在常量池中创建对象,引用赋值也为常量池中的地址
new 的方式始终会创建一个对象,不管字符串的内容是否已经存在,而双引号的方式会重复利用字符串常量池中已经存在的对象
String.intern():如果常量池中已经存在该字符串,则返回池中该字符串的引用。
如果常量池中没有该字符串,则将其添加到常量池中,并返回这个新添加字符串的引用。
String s1 = new String("6666");//引用堆中对象
String s2 = s1.intern();//引用常量池中对象
System.out.println(s1 == s2);//false
String s1 = new String("555") + new String("666");//堆中创建555666对象但常量池没有
//因为此处+调用了StringBuilder创建的是可变长的字符串变量 可变长就意味着不可能是常量,所以自然不会在常量池创建
String s2 = s1.intern();//常量池保存堆中对象的引用
System.out.println(s1 == s2); //true
StringBuffer/StringBuilder:
new StringBuilder().append("5555").append("6666").toString();
value数组默认大小是16
Object 类的
.equals()
方法默认采用的是==
操作符进行比较。假如子类没有重写该方法的话,那么==
操作符和.equals()
方法的功效就完全一样——比较两个对象的内存地址是否相等。练习:
new String("小萝莉").equals("小萝莉")//true
new String("小萝莉") == "小萝莉"//false
new String("小萝莉") == new String("小萝莉")//false
"小萝莉" == "小萝莉"//true
"小萝莉" == "小" + "萝莉" //true
new String("小萝莉").intern() == "小萝莉"//true
编译的时候把“+”号操作符替换成了 StringBuilder 的
append()
方法方法:
append()
concat()和
+
号操作符相比,concat()
方法在遇到字符串为 null 的时候,会抛出 NullPointerException,而“+”号操作符会把 null 当做是“null”字符串来处理。
22、final
使用final:
- 不希望类被继承
- 不希望父类的某个方法被子类重写
- 不希望某个属性值被修改
- 不希望局部变量被修改
细节:
- final修饰的属性一般叫常量
- final修饰的属性赋值可在定义时、构造器中、代码块中
- final修饰的属性若为静态的,则在定义时、静态代码块中赋值
- final类可以实例化对象,但不能被继承
- 非final类的final方法可以被继承,只是不能重写,可以用
- final类不能修饰构造器
- final和static同时修饰属性不会加载类,更迅速使用变量
- 包装类和String类都是final
23、抽象类
当父类有一些方法不确定如何实现,可写成抽象方法和抽象类。使用abstract
细节:
- 抽象方法不能有方法体
- 抽象类不能被实例化
- 抽象类可以没有抽象方法
- abstract只能修饰方法和类
- 本质还是类,可以有类的任意成员(非抽象方法,构造器,静态属性。。。)
- 如果一个类继承了抽象类则必须实现抽象类的方法,否则它本身也必须是抽象类
- 抽象方法不能有private\final\static
24、接口
interface,其它类实现接口inplements
细节:
- 在接口中抽象方法可以省略abstract
- 如果类实现了接口,那么需要把该接口的方法全部实现,且必须加public(alt+enter)
- jdk8以后,接口可以有默认实现方法,用default修饰
- 接口不能被实例化
- 接口中所有方法都是public,默认的可以不写
- 抽象类实现接口可以不实现接口的方法
- 一个类可以实现多个接口
- 接口中的属性必须是public static final (默认的) ,且必须初始化
- 接口不能继承其它的类,但可以继承其它接口,但不能写implements
main中:TTTT,全都正确
实现接口是对单继承的一种补充
继承满足is-a的关系,接口满足like-a的关系
接口在一定程度上实现代码解耦
多态:向上转型、向下转型
多态继承:
interface IH{}
interface IG extends IH{}
class teacher implements IG{}
IG ig=new teacher(); //对
IH ih =new teacher(); //对,多态继承
编译器报错,x不知道是哪个,x不明确。
应用A.x或super.x
25、四种内部类
类的五大成员:属性、方法、构造器、代码块、内部类
内部类分类:局部内部类、匿名内部类、成员内部类、静态内部类
局部内部类:
26、枚举类enum
27、注解
28、异常
try-catch{
}catch(){
}finally{}
29、反射
在不修改源码的情况下来控制程序,通过外部配置文件。
Class c1=Class.forName("com.cat");
Constructor cons=c1.getConstructor();
Cat cat1=(Cat)cons.newInstance();
Field fie=c1.getField();
Method me=c1.getMethods();
String name = (String) getNameMethod.invoke(c1);
Field ageField = c1.getDeclaredField("age");
ageField.setAccessible(true);
二、JVM
1、概述
只要能生成jvm的规则的字节码文件则就能在jvm上运行
跨平台、指令集小、指令多;执行性能比寄存器差。
JVM的生命周期:
- 启动:由引导类加载器创建一个初始类来完成的
- 执行:启动java虚拟机进程来执行java程序
- 退出:正常退出、执行出现异常、操作系统错误、调用某些方法退出
2、类加载子系统
1、类加载器只负责class文件的加载,至于它是否可以运行则由执行引擎决定
2、一般分为加载、链接、初始化三个环节
1、加载
读取class文件,将其转换为静态数据结构存在方法区,并在堆中生成一个java.lang.Class的对象。
2、链接
- 验证:对加载的class类进行语法和语义上的分析使其不会产生危害虚拟机的行为
- 准备:为其中的静态变量赋值0
- 解析:将符号引用替换为解析引用,a中的class引用了b中的class,会触发bclass的类加载,并生成加载后的地址来让a能找到。如果这里涉及动态绑定(也就是java的多态特性)那么虚拟机不知道b的具体实现类是哪个所以并不会加载,等到运行时知道了再加载解析。(这里解析阶段在初始化之后了)
三、JUC
1、概述
进程与线程:
进程是系统在运行中的一个应用程序,程序一旦运行就是进程,进程是资源分配的最小单位。
线程是系统分配处理器时间资源的基本单元,也可以说是进程之内独立执行的一个单元。是程序执行的最小单元
线程状态:
NEW, RUNNABLE, BLOCKED, WAITING(不见不散), TIMED_WAITING(过时不候), TERMINATED;
wait与sleep:
- sleep是Thread的静态方法,wait是Object的方法,任何对象都能调用
- sleep不会释放锁也不占用锁,wait会释放锁,调用它需要当前线程占有锁
- 都会被interrupt方法中断
并发和并行:
并发:间这些任务可能不会同时执行,而是交替执行,给人一种“同时处理”的错觉。
并行是同一时刻多个任务同时进行,执行通常需要多个处理器或者处理器核心
管程:锁
是一种同步机制,保证同一个时间只有一个线程访问被保护的数据或者代码。
用户线程:自定义线程,jvm存活
守护线程:运行在后台,jvm结束
Synchronized:是一种同步锁,
多线程编程:创建资源类,在资源类中创建属性和操作方法。创建多个线程,调用资源类的方法。
创建线程的方式:
- 继承Thread类重写run方法
- 创建一个类实现Runnable接口,并重写run方法
- 实现Callable接口,重写call方法
Lock接口:
2、集合的线程安全问题
四、spring家族
1、spring使用
1、获取bean对象
ApplicationContext context =new ClassPathXmlApplicationContext("bean.xml");
User user1=(User)context.getBean("user");//id获取对象
User user2=(User)context.getBean(User.class);//根据类型获取对象
User user3=(User)context.getBean("user",User.class);//结合id和class
根据类型获取bean时,容器中同类型bean对象只能一个。
如果多个实现类实现同一个接口则找不到接口的bean对象
2、setter注入
<property name="set后面的字母小写“ value="设置的属性值"></property>
3、构造器注入
<constructor-arg name="" value=""></constructor-arg>
<:< >:>
4、特殊类型注入
2、SpringMVC
3、Spring Boot
1、相关注解
@RestController
@RequestMapping
@RequestParam
@RequestBody
@PathVariable
@ResponseBody
@Component
@Autowired
@Controller
@Service
@Repository
@ComponentScan
@Primary
@Qualifier
@Resource
HttpServletRequest:封装了请求的所有数据
2、请求参数
1、普通参数
保证方法形参名与请求参数名一致即可,若参数对应不上则不会报错继续接受
在形参前加注解@RequestParam(name="age")int userage,且这个参数必须传递
可修改required=false来取消必须传递
2、实体参数
保证实体变量名与请求参数名一致即可,若参数对应不上则不会报错继续接受
实体中有实体对象,有.连接封装
3、数组集合参数
数组形参名与请求参数名一致即可
也可以存到集合里,前面需要加上注解
@RequestParam List<String> hobby
4、日期时间参数
形参名与请求参数名一致,并格式也要一样
5、json参数
保证实体变量名与请求参数名一致即可,前面加上注解
@RequestBody User user
6、路径参数
请求参数属于路径的一部分,使用注解PathVariable
3、响应参数
ResponseBody注解:该类的所有方法都作为响应数据
对象返回Json格式,集合返回json格式的数组,字符串就是字符串
统一响应结果:
编写Result类:code\msg\data等
直接调用Result类的方法,保证响应的数据格式一致
三层架构:
分层解耦:
减少三层之间的耦合,实现高内聚低耦合。
解决:IOC、DI
使用注解@Component(IOC) @Autowired(DI).
service层、dao层类交给容器管理,controller层、service层使用依赖注入
4、IOC
会强制类的首字母小写生成bean对象
组件扫描:@ComponentScan,默认扫描启动类所在包及其子包
手动设置:
@ComponentScan("dao","begin"),写在启动类上面
//一般按照要求,包位置不要随意安排
5、DI
同时有多个同类型bean对象,则会报错
解决:
- 使用注解@Primary在想被注入的类上,设置它的优先级最高
- @Qualifier("bean的名字“),写在@Autowired上面
- @Resource(name="bean的名字“),注释掉Autowired,写在它的位置
五、MySql
1、常用命令:
show databases;
use thissql;
create database thatsql;
desc thissql;
select version();
select database();
2、分类
DQL:数据查询语言(select)
DML:数据操纵语言(增删改、insert\delete\update)
DDL:数据定义语言(create\drop\alter)
TCL:事务控制语言(commit\rollback)
DCL:数据控制语言(grant\revoke)
3、 查询
select a from tb;
select a,b from tb;
select * from tb;
select a as aa from tb;(as可省略)
select a as 'a a' from tb; //一般字符串都用单引号
select a*10 '总结果' from tb;
select a from tb where a=10;
select a from tb where a is null ; (=null 不行)
select a from tb where a in (88,99);
select a from tb where name like '%o%'; //找_用\转义
select a from tb order by a desc;//降序
select a from tb order by a asc, b asc,c desc;
数据处理常用函数:
lower \upper\substr(串,起始,长度)\length\trim\str_to_date\format\round\rand()\ifnull
concat(a,b)字符串拼接
4、分组
分组函数自动忽略null
count
sum
avg
max
min
分组、连接查询
select distinct a from tb;
select count(distinct a) from tb;
select a from tb join bt on tb.a=bt.a; //等值连接
select a from tb join bt on tb.a>bt.a; //非等值连接
select aa.name,ab.name from tb as aa join tb as ab on aa.sal=ab.s;//内连接
select tb.a ,bt.a from tb right join bt on tb.a=bt.a; //右连接,右边的表的数据
select tb.a ,bt.a from tb left join bt on tb.a=bt.a; //左连接
5、limit用法
limit startindex,length(默认下标从0开始)
分页:limit (pagenumber -1)*pagesize,pagesize
练习:表emp,dept,salgrade
1、查询每个部门最高薪水的人员名称.
select e.ename,t.*
from emp e
join (select deptno ,max(sal) from emp group by deptno) t
on t.deptno=e.deptno and t.maxsal=e.sal;
2、哪些人的薪水在部门平均薪水之上
select e.ename,e.sal,t.*
from emp e
join (select deptno ,avg(sal) avgsal from emp group by deptno) t
on e.deptno=t.deptno and e.sal>t.avgsal;
3、取得部门中所有人的平均的薪水等级
select e.deptno,avg(s.grade)
from emp e
join slagrade s
on e.salgrade between s.losal and s.hisal
group by e.deptno
6、Mybatis
1、入门
注解:
@Mapper
@Select
@Test
@Results
@Result
使用java程序操作数据库,是优秀的持久层框架,简化jdbc的开发。
Springboot配置文件
@Mapper写在接口上,会自动生成该接口的实现类对象,并且将该对象交给IOC容器管理
注意实体类的变量名与数据库一致
@Select(”select * from user"),编写sql语句
JDBC:
- 注册驱动,使用哪个数据库的驱动类
- 获取连接对象,提供url,用户名密码
- 获取Statement对象执行sql,得到结果集
- 解析结果集,封装结果数据
- 释放资源
数据库连接池:
lombok:
![]()
2、基础操作
删除:
#{},预编译SQL
?{},直接拼接,存在SQL注入问题
新增:
主键返回:
更新:
查询:
使用@Results\@Result注解手动进行封装(不推荐)
column是数据库字段名
正解:打开驼峰命名自动映射开关
将数据库中a_column与类中aColumn映射
条件查询:返回多条结果用列表封装
XML映射文件:
前面使用注解方式配置SQL语句,现在使用xml映射文件配置
3、动态SQL
动态SQL:使用mybatis的动态sql的标签
<where>:判断条件是否有成立的,去除前面多余的and或or
<if>:
<set>:生成set关键字并去除多余的逗号
<foreach>:
<sql>:提高复用性
<include>:引用
4、实战代码练习
7、redis
1、基础篇
是Nosql非关系型数据库,存储键值对信息,单线程,每个命令具有原子性。低延迟、速度快(基于内存、IO多路复用、良好的编码)、支持数据持久化、支持主从集群、分片集群。支持多语言客户端。
数据结构:
通用命令:
KEYS *age*
KEYS a??
DEL name name1 //返回删除的键的数量
EXITST age
EXPIPE age 20 //设置有效期
TTL age //查看剩余时间 -1表示永久有效 -2表示已过期
String: