Java学习路上一些小知识点
加深认知和理解。
一个Java文件中最多只能有一个public类
- 一个Java源文件中最多只能有一个public类,当有一个public类时,源文件名必须与之一致,否则无法编译,如果源文件中没有一个public类,则文件名与类中没有一致性要求。
- 至于main()不是必须要放在public类中才能运行程序。
以下引自百度知道:
每个编译单元都有单一的公共接口,用public类来表现。该接口可以按要求包含众多的支持包访问权限的类。如果在某个编译单元内有一个以上的public类,编译器就会给出错误信息。
一个Java源文件中可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。一个文件中可以只有非public类, 如果只有一个非public类,此类可以跟文件名不同。
(后面两句有待考证,我尝试了一下,Java文件中有且只有一个非public类,类名与文件名不同,eclipse不让执行,失败)
(再次测试,在dos命令行中可以实现,编译可以通过,编译用java文件名,运行用类名。)
子类每一个构造函数内的第一行都有一句隐式super()
子父类中的构造函数:
在对子类对象进行初始化时,父类的构造函数也会运行。
那是因为子类的构造函数默认第一行有一条隐式的语句super();
super():会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super();
为什么子类一定要访问父类中的构造函数?
因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化。
所以子类在对象初始化时,要先访问一下父类中的构造函数。
如果要访问父类中指定的构造函数,可以通过手动第一super语句的方式指定。
注意:super语句一定定义在子类构造函数的第一行。
结论:
子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中德构造函数。
子类中至少会有一个构造函数会访问父类中的构造函数。
case穿透
编译器:
编译器确保被调用方法的存在,并对调用参数和返回值执行类型检查(无法提供此类保证的语言被称为是弱类型的),但是并不知道将被执行的确切代码。
在Java中,所有的类最终都继承自单一的基类Object。(单根继承结构)
“==” 和 equals()的区别
== :
. 基本数据类型比较的是值;
. 引用类型比较的是地址值。
equals(Object o):
1)不能比较基本数据类型,基本数据类型不是类类型;
2)a.比较引用类型时(该方法继承自Object,在object中比较的是地址值)等同于“==”;
b.如果自己所写的类中已经重写了equals方法,那么就安装用户自定义的方式来比较俩个对象是否相等,
如果没有重写过equals方法,那么会调用父类(Object)中的equals方法进行比较,也就是比较地址值。
结论:在没有复写equals方法的情况下,equals等同于“==”,equals不能用于比较基本数据类型。
接口:
接口中的所有成员自动被设置为public。
接口中也可以包含域,但这些域隐式地是static和final的。
接口中的方法默认是public的,即使不用public修饰。
当一个类实现一个接口时,在接口中定义的方法在重写的时候必须被定义为public的。
覆盖与重载的区别
override和overload
①重载是指不同的函数使用相同的函数名,但是函数的参数个数或类型不同。调用的时候根据函数的参数来区别不同的函数。
②覆盖(也叫重写)是指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现。即函数名和参数都一样,只是函数的实现体不一样。
Mysql
主键、外键、索引的区别?
- 主键的关键字primary key ,是由表中的一个或者多个字段构成,主键不能重复,不能为空。主键本身也是一种索引,使用主键,数据库会自动创建主键索引。每个数据表中只有一个主键。
- 外键的关键字foreign key ,是用来与其他表建立联系的,使数据保持一致性和完整性。建立外键的列必须与主键字段类型相同,只有他表的主键才能作为本表的外键。一个表可以有多个外键,外键数据可以重复,也可以为空。使用外键,数据库会自动创建外键索引。
- 索引的关键字 index ,可以分为单一索引和复合索引,单一索引是建立在一列上的索引,复合索引是建立在两个或多个列上的索引,索引可以提高查询的效率,但会降低dml操作的效率。所以建立索引时需要权衡。对于dml操作比较频繁的表,索引的个数不宜太多。
主键、外键一定是索引,索引不一定是主键、外键。
主键不允许为空值,外键允许为空值,唯一索引列允许空值;
主键索引和唯一索引的区别:
1)主键一定会创建一个唯一索引,但是有唯一索引的列不一定是主键;
2)主键不允许为空值,唯一索引列允许空值;
3)一个表只能有一个主键,但是可以有多个唯一索引;
4)主键可以被其他表引用为外键,唯一索引列不可以;
5)主键是一种约束,而唯一索引是一种索引,是表的冗余数据结构,两者有本质的差别
mysql的事务隔离等级
简介: 数据库事务的隔离级别有4种,由低到高分别为读未提交Read uncommitted 、读已提交Read committed 、可重复度Repeatable read 、序列化Serializable
。而且,在事务的并发操作中可能会出现脏读,不可重复读,幻读。
- Read uncommitted
读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。
脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读。
那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。 - Read committed
读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。
一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。事务 A 多次读取同一数据,但事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致
不可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。
那怎么解决可能的不可重复读问题?Repeatable read ! - Repeatable read
可重复读,就是在开始读取数据(事务开启)时,不再允许修改操作
重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。
什么时候会出现幻读?
1、事务A,查询是否存在 id=5 的记录,没有则插入,这是我们期望的正常业务逻辑。
2、这个时候 事务B 新增的一条 id=5 的记录,并提交事务。
3、事务A,再去查询 id=5 的时候,发现还是没有记录(因为这里是在RR级别下研究(可重复读),所以读到依然没有数据)
4、事务A,插入一条 id=5 的数据。
最终 事务A 提交事务,发现报错了。这就很奇怪,查的时候明明没有这条记录,但插入的时候 却告诉我 主键冲突,这就好像幻觉一样。这才是所有的幻读。
不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。
那怎么解决幻读问题?Serializable!
- Serializable 序列化
Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
Mysql的默认隔离级别是可重复读Repeatable read。
spring bean的作用范围
Spring支持五个作用域:singleton、prototype、request、session、global session
- 1.单例singleton:默认作用域Spring IOC容器仅存在一个Bean实例,Bean以单例方式存在,在创建容器时就同时自动创建了一个Bean对象。作用域范围是ApplicationContext中。
- 2.原型多例prototype:每次从容器中调用Bean时,都会返回一个新的实例,即每次调用getBean时。作用域返回是getBean方法调用直至方法结束。
相当于执行newXxxBean().Prototype是原型类型,再我们创建容器的时候并没有实例化,而是当我们获取Bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。 - 3.request:每次HTTP请求都会创建一个新的Bean,作用域范围是每次发起http请求直至拿到相应结果。该作用域仅适用于WebApplicationContext环境。
- 4.session:首次http请求创建一个实例,作用域是浏览器首次访问直至浏览器关闭。
同一个HTTP Session共享一个Bean,不同Session使用不通的Bean,仅适用于WebApplicationContext环境。
5.global-session:作用域范围是WebApplicationContext中。一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境。
作用域范围比较:
prototype < request < session < global-session < singleton
为什么要定义作用域:
可以通过Spring配置的方式限定Spring Bean的作用范围,可以起到对Bean使用安全的保护作用
request请求作用域考虑如下的bean定义:
<bean id="loginController" class="com.example.LoginController" scope="request"/>
@Scope("request")
@Controller
public class LoginController{
private int flag = 0;
@RequestMapping("/login")
public int login(){
return flag++;
}
}
@RestController
@RequestScope
public class LoginController {
private int flag = 0;
@RequestMapping("/login")
public int login(){
return flag++;
}
}
对于每个http请求,Spring容器会创建一个 LoginController Bean 的新实例。也就是说,LoginController Bean 的作用域限于 HTTP 请求范围。 你可以在请求内随意修改这个Bean实例的状态,因为其他 LoginController Bean实例看不到这些变化,Bean实例是与特定的请求相关的。 当请求处理完毕,对应的Bean实例也就销毁(被回收)了。
Mybatis
mybatis中的#和$的区别:
能使用#{}的地方应尽量使用#{},#和KaTeX parse error: Expected 'EOF', got '#' at position 14: 在预编译处理中是不一样的。#̲类似jdbc中的Prepare…{}则可能导致sql注入成功。
多线程
线程创建的方式:
- 方式一:继承Thread类
- 优点:编码简单 缺点:继承Thread类后不能再继承其他类,不利于扩展。
- 方式二:实现Runnable接口
- 优点:线程任务类只需实现接口,可以继续继承和和实现其他接口,扩展性强。
缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。
也可以直接用匿名内部类实现: - 方式三:实现Callable接口(JDK5.0新增)