常见面试题:
https://blog.csdn.net/huangshulang1234/article/details/79513867 【面试题】
https://mp.weixin.qq.com/s/kJpRgfI3zT77XqMeRfmmQQ 【微信java技术栈】
代码块的优先顺序?
1.FatherClass fc = new FatherClass();
public class FatherClass {
static {
System.out.println("父类的静态代码块");
}
{
System.out.println("父类的局部代码块");
}
public FatherClass() {
a();
System.out.println("父类的构造代码块");
}
public void a() {
System.out.println("父类的方法a");
}
}
class ChildClass extends FatherClass {
static {
System.out.println("子类的静态代码块");
}
{
System.out.println("子类的局部代码块");
}
public ChildClass() {
a();
System.out.println("子类的构造代码块");
}
public void a() {
System.out.println("子类的方法a");
}
public static void main(String[] args) {
FatherClass fc = new FatherClass();
//ChildClass cc = new ChildClass();
}
}
结果:
父类的静态代码块
子类的静态代码块
父类的局部代码块
父类的方法a
父类的构造代码块
2.ChildClass cc = new ChildClass();
结果:
父类的静态代码块
子类的静态代码块
父类的局部代码块
子类的方法a
父类的构造代码块
子类的局部代码块
子类的方法a
子类的构造代码块
try…catch…finally都是return怎么执行?
public class return的问题 {
public static void main(String[] args) {
System.out.println(method());
}
private static int method() {
int a = 0;
try {
return ++a;
} catch (Exception e) {
return ++a;
} finally {
return ++a;
}
}
}
结果:2
解析:try中的return不是真正意义上的return动作
String,数组,基本类型类型的局部变量传输?
public class Helloword {
public static void main(String[] args) {
//String类型局部变量和成员变量
String word = new String("Hello");
System.out.println(method(word));
System.out.println(word);
//int 类型的局部变量和成员变量
int a = 10;
method(a);
System.out.println(a);
//数组 类型的局部变量和成员变量
int[] arr = { 0 };
method(arr);
System.out.println(arr[0]);
}
public static String method(String word) {
return word = word + "word";
}
public static void method(int a) {
a = a + a;
}
public static void method(int[] arr) {
arr[0] = 10;
}
}
结果:
10
10
Helloword
Hello
String在栈,和堆中的位置?
1. String str1 = "abc";
System.out.println(str1 == "abc");
步骤:
1) 栈中开辟一块空间存放引用str1,
2) String池中开辟一块空间,存放String常量"abc",
3) 引用str1指向池中String常量"abc",
4) str1所指代的地址即常量"abc"所在地址,输出为true
2. String str2 = new String("abc");
System.out.println(str2 == "abc");
步骤:
1) 栈中开辟一块空间存放引用str2,
2) 堆中开辟一块空间存放一个新建的String对象"abc",
3) 引用str2指向堆中的新建的String对象"abc",
4) str2所指代的对象地址为堆中地址,而常量"abc"地址在池中,输出为false
3. String str3 = new String("abc");
System.out.println(str3 == str2);
步骤:
1) 栈中开辟一块空间存放引用str3,
2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象,
3) 引用str3指向另外新建的那个String对象
4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false
4. String str4 = "a" + "b";
System.out.println(str4 == "ab");
步骤:
1) 栈中开辟一块空间存放引用str4,
2) 根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量"ab",
3) 引用str4指向池中常量"ab",
4) str4所指即池中常量"ab",输出为true
5. final String s = "a";
String str5 = s + "b";
System.out.println(str5 == "ab");
步骤:
同4
6. String s1 = "a";
String s2 = "b";
String str6 = s1 + s2;
System.out.println(str6 == "ab");
步骤:
1) 栈中开辟一块中间存放引用s1,s1指向池中String常量"a",
2) 栈中开辟一块中间存放引用s2,s2指向池中String常量"b",
3) 栈中开辟一块中间存放引用str5,
4) s1 + s2通过StringBuilder的最后一步toString()方法还原一个新的String对象"ab",因此堆中开辟一块空间存放此对象,
5) 引用str6指向堆中(s1 + s2)所还原的新String对象,
6) str6指向的对象在堆中,而常量"ab"在池中,输出为false
7. String str7 = "abc".substring(0, 2);
步骤:
1) 栈中开辟一块空间存放引用str7,
2) substring()方法还原一个新的String对象"ab"(不同于str6所指),堆中开辟一块空间存放此对象,
3) 引用str7指向堆中的新String对象,
8. String str8 = "abc".toUpperCase();
步骤:
1) 栈中开辟一块空间存放引用str6,
2) toUpperCase()方法还原一个新的String对象"ABC",池中并未开辟新的空间存放String常量"ABC",
3) 引用str8指向堆中的新String对象
Delete和truncate的区别?
(1)DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。
TRUNCATE TABLE 则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。
(2)表和索引所占空间。
当表被TRUNCATE 后,这个表和索引所占用的空间会恢复到初始大小,
DELETE操作不会减少表或索引所占用的空间。
drop语句将表所占用的空间全释放掉。
(3)一般而言,drop > truncate > delete
(4)应用范围。
TRUNCATE 只能对TABLE; DELETE可以是table和view
(5)TRUNCATE 和DELETE只删除数据, DROP则删除整个表(结构和数据)。
(6)truncate与不带where的delete :只删除数据,而不删除表的结构(定义)drop语句将删除表的结构被依赖的约束(constrain),触发器(trigger)索引(index);依赖于该表的存储过程/函数将被保留,但其状态会变为:invalid。
(7)delete语句为DML(data maintain Language),这个操作会被放到 rollback segment中,事务提交后才生效。如果有相应的 tigger,执行的时候将被触发。
(8)truncate、drop是DDL(data define language),操作立即生效,原数据不放到 rollback segment中,不能回滚
(9)在没有备份情况下,谨慎使用 drop 与 truncate。要删除部分数据行采用delete且注意结合where来约束影响范围。回滚段要足够大。要删除表用drop;若想保留表而将表中数据删除,如果于事务无关,用truncate即可实现。如果和事务有关,或老师想触发trigger,还是用delete。
(10) Truncate table 表名 速度快,而且效率高,因为:
truncate table 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。
(11) TRUNCATE TABLE 删除表中的所有行,但表结构及其列、约束、索引等保持不变。新行标识所用的计数值重置为该列的种子。如果想保留标识计数值,请改用 DELETE。如果要删除表定义及其数据,请使用 DROP TABLE 语句。
(12) 对于由 FOREIGN KEY 约束引用的表,不能使用 TRUNCATE TABLE,而应使用不带 WHERE 子句的 DELETE 语句。由于 TRUNCATE TABLE 不记录在日志中,所以它不能激活触发器。
一、delete
1、delete是DML,执行delete操作时,每次从表中删除一行,并且同时将该行的的删除操作记录在redo和undo表空间中以便进行回滚(rollback)和重做操作,但要注意表空间要足够大,需要手动提交(commit)操作才能生效,可以通过rollback撤消操作。
2、delete可根据条件删除表中满足条件的数据,如果不指定where子句,那么删除表中所有记录。
3、delete语句不影响表所占用的extent,高水线(high watermark)保持原位置不变。
二、truncate
1、truncate是DDL,会隐式提交,所以,不能回滚,不会触发触发器。
2、truncate会删除表中所有记录,并且将重新设置高水线和所有的索引,缺省情况下将空间释放到minextents个extent,除非使用reuse storage,。不会记录日志,所以执行速度很快,但不能通过rollback撤消操作(如果一不小心把一个表truncate掉,也是可以恢复的,只是不能通过rollback来恢复)。
3、对于外键(foreignkey )约束引用的表,不能使用 truncate table,而应使用不带 where 子句的 delete 语句。
4、truncatetable不能用于参与了索引视图的表。
三、drop
1、drop是DDL,会隐式提交,所以,不能回滚,不会触发触发器。
2、drop语句删除表结构及所有数据,并将表所占用的空间全部释放。
3、drop语句将删除表的结构所依赖的约束,触发器,索引,依赖于该表的存储过程/函数将保留,但是变为invalid状态。
总结:
1、在速度上,一般来说,drop> truncate > delete。
2、在使用drop和truncate时一定要注意,虽然可以恢复,但为了减少麻烦,还是要慎重。
3、如果想删除部分数据用delete,注意带上where子句,回滚段要足够大;
如果想删除表,当然用drop;
如果想保留表而将所有数据删除,如果和事务无关,用truncate即可;
如果和事务有关,或者想触发trigger,还是用delete;
如果是整理表内部的碎片,可以用truncate跟上reuse stroage,再重新导入/插入数据。
泛型的作用?
泛型的应用:可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法
1.泛型类的定义和使用:
一个泛型类(generic class)就是具有一个或多个类型变量的类。定义一个泛型类十分简单,只需要在类名后面加上<>,再在里面加上类型参数:
class Pair<T> {
private T value;
public Pair(T value) {
this.value=value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
Pair pair=new Pair(“Hello”);
注意:类型变量使用大写形式,且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。(需要时还可以用临近的字母U和S)表示“任意类型”。
2.泛型接口的定义和应用
interface Show<T,U>{
void show(T t,U u);
}
class ShowTest implements Show<String,Date>{
@Override
public void show(String str,Date date) {
System.out.println(str);
System.out.println(date);
}
}
3.泛型方法的定义和应用
泛型类在多个方法签名间实施类型约束。在 List 中,类型参数 V 出现在 get()、add()、contains() 等方法的签名中。当创建一个 Map<K, V> 类型的变量时,您就在方法之间宣称一个类型约束。您传递给 add() 的值将与 get() 返回的值的类型相同。
类似地,之所以声明泛型方法,一般是因为您想要在该方法的多个参数之间宣称一个类型约束。
public static void main(String[] args) throws ClassNotFoundException {
String str=get("Hello", "World");
System.out.println(str);
}
public static <T, U> T get(T t, U u) {
if (u != null)
return t;
else
return null;
}
泛型在使用中还有一些规则和限制:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如。习惯上成为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(Java.lang.String);
mybatis实现主从数据分离的方式?
https://blog.csdn.net/wuyongde_0922/article/details/70655185
1.通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactoryBean对象的mapperLocations属性制定两个读写数据源的配置文件。将所有读的操作配置在读文件中,所有写的操作配置在写文件中。
2.通过Spring AOP在业务层实现读写分离,在DAO层调用前定义切面,利用Spring的AbstractRoutingDataSource解决多数据源的问题,实现动态选择数据源
3.通过Mybatis的Plugin在业务层实现数据库读写分离,在MyBatis创建Statement对象前通过拦截器选择真正的数据源,在拦截器中根据方法名称不同(select、update、insert、delete)选择数据源。
4.如果你的后台结构是spring+mybatis,可以通过spring的AbstractRoutingDataSource和mybatis Plugin拦截器实现非常友好的读写分离,原有代码不需要任何改变。推荐第四种方案
mysql的引擎?
https://www.cnblogs.com/sunsky303/p/8274586.html
https://www.cnblogs.com/xiaohaillong/p/6079551.html
1.Innodb引擎:InnoDB是一个事务型的存储引擎,有行级锁定和外键约束。
适用场景:
1)经常更新的表,适合处理多重并发的更新请求。
2)支持事务。
3)可以从灾难中恢复(通过bin-log日志等)。
4)外键约束。只有他支持外键。
5)支持自动增加列属性auto_increment。
2.myiasm引擎:MyIASM是MySQL默认的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。
适用场景:
1)不支持事务的设计,但是并不代表着有事务操作的项目不能用MyIsam存储引擎,可以在service层进行根据自己的业务需求进行相应的控制。
2)不支持外键的表设计。
3)查询速度很快,如果数据库insert和update的操作比较多的话比较适用。
4)整天 对表进行加锁的场景。
5)MyISAM极度强调快速读取操作。
6)MyIASM中存储了表的行数,于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持,那么MyIASM也是很好的选择。
缺点:
就是不能在表损坏后恢复数据。(是不能主动恢复)
3.Memory(也叫HEAP)堆内存嘛
4.Mrg_Myisam:(分表的一种方式–水平分表)
5.Blackhole(黑洞引擎)
Java的位运算符解析:
http://www.cnblogs.com/xiaozigbd/p/9202373.html
$与运算符:
与运算符就相当于&&,不同的是,这是按位对比,比如8&9,用十进制的眼光去看简直就瞎了,8&9其实做的运算就是00001000&00001001,然后看到当且仅当两个对应的位置都是1,结果才是1,否则结果为0,那么结果就是00001000,也就是8.
|或运算符:
或运算符就相当于||, 当然也是按位去或的,当且仅当两个对应的位置都是0,结果才是0,否则结果是1,那么8|9就是00001000|00001001,结果就是00001001=9。
~运算符:
就是按位取反,比如8对吧,那就是00001000按位取反结果是11110111.前面说了,这是有符号数,也就是最高位代表符号位,也就是8的结果是一个负数,那么人类第一反应是-8,但结果却不是,那这里简单解析一下,负数的二进制表示方式跟正数不一样,负数有一个反码和补码的概念,这么理解呢?就说-8吧,用二进制表示-8是:11111000,-10的二进制是:11110110.
首先-8的绝对值8的二进制是00001000, 求其反码就是11110111,补码(+1)是11111000。那么上面8的结果11110111是多少呢?我们算一下,先-1得到11110110,然后取反:00001001,得到9,那么8==9?不是的,是结果的绝对值,因为是负数,所以是-9.
^异或运算符:
异或运算是:当运算符两边不同的时候结果为1,两边相同的时候结果为0 这就是传说中的同性相杀,异性相吻。举个例子就是:8 ^ 6=1000 ^ 0110=1110=14
>>位移运算符(<<同理)
位移运算符我们可以简单的理解为乘除法,像左移是除法,向右移是乘法。这个符号位是不移动的,注意下。8>>2大家不要理解为8/2,位移两位就是除以2的2次方也就是8/4.这里注意9>>1的结果是4,即最低位的1会移没了··当然了<<如果结果超过了最大整数能表示的范文,那就·····你懂的。
>>> 是无符号的位移运算符
这个运算符跟>>差不多,不同点是,它移动后高位补0,。好像>>位移后高位也是补0啊,是的,但符号位不移动,而>>>tm符号位都移动了,就是负数一移就正了·····
mysql数据库的索引:
https://www.cnblogs.com/bypp/p/7755307.html
mysql索引分类:
1.普通索引index:加速查询
2.唯一索引:
主键索引:primary key :加速查找+约束(不为空且唯一)
唯一索引:unique:加速查找+约束(唯一)
3.联合索引:
-primary key(id,name):联合主键索引
-unique(id,name):联合唯一索引
-index(id,name):联合普通索引
4.全文索引fulltext:用于搜索很长一篇文章的时候,效果最好。
5.空间索引spatial:了解
索引的两大类型:hash和btree
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)
不同的存储引擎支持的索引类型:
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;
sql语句优化:
https://www.cnblogs.com/knowledgesea/p/3686105.html
1.’对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
3.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
5.下面的查询也将导致全表扫描:
select id from t where name like '%abc%'
若要提高效率,可以考虑全文检索。
6.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
select id from t where num=@num
可以改为强制查询使用索引:
select id from t with(index(索引名)) where num=@num
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=100*2
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)='abc'--name以abc开头的id
select id from t where datediff(day,createdate,'2005-11-30')=0--'2005-11-30'生成的id
应改为:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
12.不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(...)
13.很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
14.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
15.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
16.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。
17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
19.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
20.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
21.避免频繁创建和删除临时表,以减少系统表资源的消耗。
22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
29.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
30.尽量避免大事务操作,提高系统并发能力。
Linux命令:
https://www.cnblogs.com/yjd_hycf_space/p/7730690.html
https://blog.csdn.net/qq_29954971/article/details/79141276
https://blog.csdn.net/tao934798774/article/details/79491951
前端反转字符串:
1.使用字符串函数
//str=hello
function reverseString(str) {
var array = str.split('');//['h','e','l','l','o'];
array = array.reverse();// ['o','l','l','e','h'];
str = array.join('');//"olleh"
return str;
}
代码的简写:
//str=hello
function reverseString(str) {
return str.split('').reverse().join('');;
}
2.使用for循环:
function reverseString(str) {
var newStr="";
for(var i=str.length-1;i>=0;i--){
newStr+=str[i];
}
return newStr;
}
3.使用递归:
function reverseString(str) {
if (str === "") {
return "";
} else {
return reverseString(str.substr(1)) + str.charAt(0);
}
}
reverseString("hello"); // => olleh
链表的分类:
1.单项链表
单链表指的是链表中的元素的指向只能指向链表中的下一个元素或者为空,元素之间不能相互指向。也就是一种线性链表。
2.双向链表:
双向链表即是这样一个有序的结点序列,每个链表元素既有指向下一个元素的指针,又有指向前一个元素的指针,其中每个结点都有两种指针,即left和right。left指针指向左边结点,right指针指向右边结点。
3.循环链表:
循环链表指的是在单向链表和双向链表的基础上,将两种链表的最后一个结点指向第一个结点从而实现循环。
树结构:
http://blog.51cto.com/9291927/2068745
https://blog.csdn.net/caozl218/article/details/72861072
序列化:
序列化:将java对象转化为字节序列的过程
反序列化:将字节序列转化为java对象的过程
作用:
1.用于io流的输入输出,把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2.在网络上传送对象的字节序列。
JSP内置对象及其作用?
https://blog.csdn.net/mao834099514/article/details/78697079
request:HttpServletRequest
response:HttpServletRequest
session:HttpSession
application:ServletContext
out:JSPWriter
pagecontext:pageContext
config:ServletConfig
page:Object
exception:Throwable
dubbo的协议:
https://blog.csdn.net/xiaojin21cen/article/details/79834222
1.dubbo 协议 (默认)
2、rmi 协议
3、hessian 协议
4、http 协议
5、webservice 协议
7、memcached 协议
8、redis 协议
反射的创建,以及方法?
创建方法:
1.创建Class对象的方式一:(对象.getClass()),获取person类中的字节码文件
Person p1 = new Person(“小明” ,20,‘男’ );
Class class1 = p1.getClass();
2.创建Class对象的方式二:(类.class:需要输入一个明确的类,任意一个类型都有一个静态的class属性)
Class class3 = Person.class;
3.创建Class对象的方式三:(forName():传入时只需要以字符串的方式传入即可)
通过Class类的一个forName(String className)静态方法返回一个Class对象,className必须是全路径名称;
Class.forName()有异常:ClassNotFoundException
Class class4 = Class.forName(“cn.itcast.Person”);
反射的方法:
Field[] getFields() :获取公共的成员变量
Field[] getDeclaredFields() :获取所有的成员变量
Field getField(String name) :根据字段名称获取公共的字段对象
Field getDeclaredField(String name):获取私有的字段对象
Constructor<?>[] getConstructors() :获取所有public修饰的构造方法
Spring的模块?
spring core:核心容器
核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。
Spring context:应用上下文
Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:Spring面向切面编程
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC和DAO模块
JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。
Spring ORM:对象实体映射
Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。
Spring Web:Web模块
Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring Web MVC:MVC模块
MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。
Hibernate的主键生成策略:
https://www.cnblogs.com/hoobey/p/5508992.html
1.assigned
特点:可以跨数据库,人为控制主键生成,应尽量避免。
2.increment
特点:跨数据库,不适合多进程并发更新数据库,适合单一进程访问数据库,不能用于群集环境。
3.hilo
特点:跨数据库,hilo算法生成的标志只能在一个数据库中保证唯一。
4.seqhilo
特点:与hilo类似,只能在支持序列的数据库中使用。
5.sequence
特点:只能在支持序列的数据库中使用,如Oracle。
6.identity
特点:只能用在支持自动增长的字段数据库中使用,如MySQL。
7.native
特点:根据数据库自动选择,项目中如果用到多个数据库时,可以使用这种方式,使用时需要设置表的自增字段或建立序列,建立表等。
8.uuid
特点:uuid长度大,占用空间大,跨数据库,不用访问数据库就生成主键值,所以效率高且能保证唯一性,移植非常方便,推荐使用。
9.guid
注意:长度因数据库不同而不同
特点:需要数据库支持查询uuid,生成时需要查询数据库,效率没有uuid高,推荐使用uuid。
10.foreign
特点:很少使用,大多用在一对一关系中。
11.select
使用触发器生成主键,主要用于早期的数据库主键生成机制,能用到的地方非常少。
链表的冒泡排序:
https://www.cnblogs.com/darkchii/p/7302412.html
树的顺序遍历:
http://www.cnblogs.com/ABCDXYZnoip/p/7622090.html
1.先序遍历—理解:中–>左–>右
2.中序遍历—理解:左–>中–>右
3.后序遍历—理解:左–>右–>中
笔试题-压缩与解压缩字符串
题目:
- 请编写一个字符串压缩程序,将字符串中连续出席的重复字母进行压缩,并输出压缩后的字符串。
- 根据压缩规则编写函数对压缩后的字符串进行解压缩
压缩规则:
1、仅压缩连续重复出现的字符。比如字符串"abcbc"由于无连续重复字符,压缩后的字符串还是"abcbc"。
2、压缩字段的格式为"字符重复的次数+字符"。例如:字符串"xxxyyyyyyz"压缩后就成为"3x6yz"。
代码:
public class ZipChar {
private static final String TAG = "ZipChar";
public static void main(String[] args) {
String str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaavcsdssssdfvvvvv";
System.out.println(compressChar(str));
System.out.println(decompressChar(compressChar(str)));
}
private static String compressChar(String str) {
StringBuilder sb = new StringBuilder();
char[] chars = str.toCharArray();
int count = 1;
int n = chars.length;
for (int i = 1; i < n; i++) {
if(chars[i] == chars[i-1]) {
count++;
} else {
if(count > 1) {
sb.append(count);
}
sb.append(chars[i-1]);
count = 1;
}
}
if(count > 1) {
sb.append(count);
sb.append(chars[n-1]);
}
return sb.toString();
}
private static String decompressChar(String str) {
StringBuilder sb = new StringBuilder();
char[] chars = str.toCharArray();
int count = 0;
for(int i = 0, n = chars.length; i < n; i++) {
if((chars[i] + "").matches("[0-9]")) {
count = count * 10 + Integer.parseInt(chars[i] + "");
} else if((chars[i] + "").matches("[a-z]")) {
if(count == 0) {
sb.append(chars[i]);
}
for(int j = 0; j < count; j++) {
sb.append(chars[i]);
}
count = 0;
}
}
return sb.toString();
}
十年中一共多少天?
10年有多少天,有三种情况:
3651天(一个闰年),如从1897到1906,因为1900不能被400整除,所以不是闰年,这十年只有一个闰年1904年。
3652天(两个闰年),如1902到1911,其中1904、1908是闰年,故天数3652天。
3653天(三个闰年),如1904到1913,其中1904、1908、1912都有366天。