2018 java面试题

java面试总结

java基本数据类型:

字节型 byte 8位; 短整型 short 16位; 整型 int 32位; 长整型long 64位;

单精度float 32位;双精度 double 64位; 字符型char 8位; 布尔型 boolean。

String 不是基本数据类型, String类是final不可以继承。

java修饰符:

  • 访问权限修饰符:

    HTML
    public: 同一个类、同一个包、父子类、不同包;
    prodect:同一个类、同一个包、父子类;
    defailt:同一个类和同一包, 默认访问修饰符
    private:同一个类

    • abstract:

    抽象类不能被实例化,子类没有实现父类定义的所有抽象方法,子类也必须定义为抽象方法, 抽象类没有构造方法;非抽象类继承抽象类时,必须把抽象类中的所有方法实现。

    • final

    final变量必须被显示的初始化,并且只能赋值一次,final修饰的类是最终的类,不能被继承;final修饰的方法为最终方法,不能被重写;final 修饰引用类型变量的时候, 该变量不能重新指向其他对象 。

    • interface

      interface需要实现,要用implements;一个类可以实现多个接口,解决单继承;接口的所有方法必须被所有实现类实现;接口的方法都是public,如果创建变量接口变量默认是public static final; 接口不能实例化;多个接口方法名不能一样。

    • static

      静态方法或者变量,值是放在方法区的,因为方法区是一个之共享区, 所以不管是否访问他,都是同一份;静态方法不能直接访问实例方法和实例变量;静态成员变量可以用类名或者对象直接去访问;当类加载时静态代码块只会被执行一次,类中不同的静态代码块按他们再类中出现的顺序依次执行。

@Override和@Overload :

  1. Override(重写, 运行时多态)

    子类对父类的方法进行的新的编写,其中方法名和参数是不能变得,就是外壳不变,内容变了。但是不可以抛出新的或者更广的异常。可以降低访问限制。

  2. Overload(重载, 编译时多态)

    指的是在一个类中,方法名字相同,但是形参不同,返回类型可以相同也可以不同。可以修改访问限制。

try、catch、finally :

try { 
    //执行的代码,其中可能有异常。一旦发现异常,则立即跳到catch执行。否则不会执行catch里面的内容 
} catch { 
    //除非try里面执行代码发生了异常,否则这里的代码不会执行 
} finally { 
    //不管什么情况都会执行,包括try catch 里面用了return ,可以理解为只要执行了try或者catch,就一定会执行 finally 
} 

String字符串操作:

int length(); // 获取长度
char charAt(int index); // 返回指定索引出的char值
int indexOf(String str); // 返回的是str在字符串中第一次出现的位置, 如果没有则返回-1,也可以包含
int indexOf(int ch, int fromIndex); // 从fromIndex指定位置开始,获取ch在字符串中出现的位置。
int lastIndexOf(int ch); // 返回索引一个字符出现的位置
boolean contains(str); // 字符串是否包含某一个子串
boolean isEmpty(); // 判断长度是否为0
boolean startsWith(str); // 是否以指定内容开头
boolean endsWith(str); // 是否以指定内容结尾
boolean equals(str); // 判断字符串是否相同
boolean equalsIgnoreCase(); // 忽略大小写,判断是否为空
String(char[]); // 将字符串数组转为字符串
String(char[], offset, count); // 将字符串的一部分转为字符串
char[] toCharArray(); // 将字符串转为字符串数组
String valueOf(int); // 将基本数据类型转为字符串
String valueOf(double);
String replace(oldchar, newchar); // 替换
String[] split(regex); // 切割
String substring(begin); // 子串
String substring(begin, end); 
String toUpperCase(); // 将字符串转为大写和小写
String toLowerCase();
String trim(); // 将字符串两端的多个空格去除
compareTo(str); // 顺序比较
// 数据类型转换
String s = "1";
byte b = Byte.parseByte( s );
short t = Short.parseShort( s );
int i = Integer.parseInt( s );
long l = Long.parseLong( s );
Float f = Float.parseFloat( s );
Double d = Double.parseDouble( s );

Java中的String,StringBuilder,StringBuffer三者的区别

  1. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

  2. 在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的 。

  3. String:适用于少量的字符串操作的情况

    StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

    StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

String的Scanner类

String s1,s2;  
Scanner sc=new Scanner(System.in);  
System.out.print("请输入第一个字符串:");  
s1=sc.nextLine();  
System.out.print("请输入第二个字符串:");  
s2=sc.next();  
System.out.println("输入的字符串是:"+s1+" "+s2);  

日期和时间

// 格式化时间
Date now = new Date( );
now.getYear(); now.getMonth(); now.getDay(); now.getHours(); now.getMinutes(); now.getSeconds();
SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Current Date: " + ft.format(now));

final, finally, finalize的区别 :

final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 finally是异常处理语句结构的一部分,表示总是执行。 finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。

Error与Exception:

exception:可以使可被控制和不可被控制,表示由程序员导致的错误,应该在应用程序级被处理

error: 总是不可被控制的; 经常用来表示系统错误或者底层资源错误;应该在系统级被捕捉。

什么是堆内存?什么是栈内存?有什么区别 :

Java的内存空间分为堆内存和栈内存。栈内存用于存储定义的基本类型变量、函数返回值、对象的引用等,而堆内存用于存放new出来的一切对象。

Java的垃圾回收机制是怎样的?回收的是什么样的对象?

Java垃圾回收器实现对堆内存数据的自动回收,无需程序员显式地调用delete放啊。Java的垃圾自动回收机制有效地避免了因为程序员忘记释放内存而造成的内存溢出错误。 Java使用被称为垃圾收集器的技术来监视Java程序的运行,当对象不再被使用时,即不再被引用时,就会自动释放对象所占用的内存。Java使用一系列软指针来跟踪对象的各个引用,这些软指针并不直接指向对象,而是指向对象的引用。通过软指针,Java的垃圾收集器能够以单独的线程在后台运行,并不时检查每个对象的引用。 调用System的静态方法gc()可以运行垃圾收集器,但是并不能保证立即回收指定对象。(这就是建议回收,不能强迫回收。) finalize()方法可以终止一个对象来释放资源,调用之后对象不再被引用,就会被回收。

栈和队列:

队列:先进先出,只能在表的一端进行插入,可以从头部和尾部进行遍历,但不能同时遍历,不需要开辟空间,遍历速度要快;栈:现进后出,只能在表的一端插入和删除,只能在顶部取数据。

java程序的编译过程:

源代码 => 词法分析器 => Token流 => 语法分析器 => 语法数/抽象语法数 => 语义分析器 => 注解抽象语法树 => 字节码生成器 => jvm字节码

Linux命令:

ls -a  -l  文件目录
cd ~(用户主目录)  - (进入之前所在目录) .. (上级目录) ../.. (返回上两级)
mkdir (创建目录) -p (建立多个目录)
rm -rf   (强制删除目录或者目录)
cp -f(强行复制文件目录) -R/r (将指定目录下的所有文件与子目录一并处理)
mv 对文件或者目录重命名或者将文件移动
pwd 以绝对路径的方式显示用户当前工作目录
tree 以树形列出目录的内容
touch 创建空文件, 更新文件的时间
chmod 更改文件或者目录的权限
file 探测文件类型
cat 查看文件内容
tail 输出文件中的尾部内容,默认10行
head 显示文件的开头的内容
ps 报告当前系统的进程状态
ping  ifconfig top
tail -n 5 filename  输出文件最后五行
ps -ef|grep java   输出java运行的进程

java 线程

线程和进程

​ 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。

java实现线程

​ 在语言层面有两种方式。java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,由于线程类本身就是调用的Runnable接口所以你可以继承java.lang.Thread 类或者直接调用Runnable接口来重写run()方法实现线程。

Java中ThreadLocal变量, volatile变量, synchronized的区别

​ volatile主要是用来在多线程中同步变量。
但需要注意volatile只能确保操作的是同一块内存,并不能保证操作的原子性。所以volatile一般用于声明简单类型变量,使得这些变量具有原子性,即一些简单的赋值与返回操作将被确保不中断。但是当该变量的值由自身的上一个决定时,volatile的作用就将失效,这是由volatile关键字的性质所决定的。

​ ThreadLocal是一个线程的局部变量(其实就是一个Map),ThreadLocal会为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这样做其实就是以空间换时间的方式(与synchronized相反),以耗费内存为代价,单大大减少了线程同步(如synchronized)所带来性能消耗以及减少了线程并发控制的复杂度。

​ synchronized关键字是Java利用锁的机制自动实现的,一般有同步方法和同步代码块两种使用方式。Java中所有的对象都自动含有单一的锁(也称为监视器),当在对象上调用其任意的synchronized方法时,此对象被加锁(一个任务可以多次获得对象的锁,计数会递增),同时在线程从该方法返回之前,该对象内其他所有要调用类中被标记为synchronized的方法的线程都会被阻塞。

Thread 类中的start() 和 run() 方法有什么区别

​ start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程 。

死锁

​ 死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。 死锁的发生必须满足以下四个条件:

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

Java中创建线程安全的 Singleton

// 懒汉模式
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 
// 饿汉模式
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

Java多线程中调用wait() 和 sleep()方法有什么不同?

​ Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。

同步块内的线程抛出异常会发生什么?

​ 无论你的同步块是正常还是异常退出的,里面的线程都会释放锁。

如何让T1,T2,T3顺序执行

class PublicThread extends Thread{
    @Override
    public void run() {
        System.out.println("线程 : "+Thread.currentThread().getName());
    }
}
public class Thread_1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new PublicThread();    t1.setName("T1");
        Thread t2 =  new PublicThread();   t2.setName("T2");
        Thread t3 = new PublicThread();    t3.setName("T3");
        t1.start();  t1.join();
        t2.start();  t2.join();
        t3.start();  t3.join();
    }
}

线程通信:wait()/notify()/notifyAll()

wait(): 导致当前线程等待并使其进入到等待阻塞状态。直到其他线程调用该同步锁对象的notify()或notifyAll()方法来唤醒此线程。

  • void wait(long timeout) – 导致当前线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
  • void wait(long timeout, int nanos) – 导致当前线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

notify():唤醒在此同步锁对象上等待的单个线程,如果有多个线程都在此同步锁对象上等待,则会任意选择其中某个线程进行唤醒操作,只有当前线程放弃对同步锁对象的锁定,才可能执行被唤醒的线程。

notifyAll():唤醒在此同步锁对象上等待的所有线程,只有当前线程放弃对同步锁对象的锁定,才可能执行被唤醒的线程。

  这三个方法主要都是用于多线程中,但实际上都是Object类中的本地方法。因此,理论上,任何Object对象都可以作为这三个方法的主调,在实际的多线程编程中,只有同步锁对象调这三个方法,才能完成对多线程间的线程通信。

注意点:

1.wait()方法执行后,当前线程立即进入到等待阻塞状态,其后面的代码不会执行;

2.notify()/notifyAll()方法执行后,将唤醒此同步锁对象上的(任意一个-notify()/所有-notifyAll())线程对象,但是,此时还并没有释放同步锁对象,也就是说,如果notify()/notifyAll()后面还有代码,还会继续进行,知道当前线程执行完毕才会释放同步锁对象;

3.notify()/notifyAll()执行后,如果右面有sleep()方法,则会使当前线程进入到阻塞状态,但是同步对象锁没有释放,依然自己保留,那么一定时候后还是会继续执行此线程,接下来同2;

4.wait()/notify()/nitifyAll()完成线程间的通信或协作都是基于不同对象锁的,因此,如果是不同的同步对象锁将失去意义,同时,同步对象锁最好是与共享资源对象保持一一对应关系;

5.当wait线程唤醒后并执行时,是接着上次执行到的wait()方法代码后面继续往下执行的。

JDBC操作

JDBC操作数据库的步骤:

​ 1、注册数据库驱动

​ 2、建立数据库连接

​ 3、创建一个Statement

​ 4、执行SQL语句

​ 5、处理结果集

​ 6、关闭数据库连接

JDBC中的Statement 、PreparedStatement和CallableStatement的区别

​ PreparedStatement是预编译的SQL语句,效率高于Statement。 PreparedStatement支持?操作符,相对于Statement更加灵活。 PreparedStatement可以防止SQL注入,安全性高于Statement;CallableStatement适用于执行存储过程。

JDBC中大数据量的分页解决方法

select * from students limit ” + pageSize*(pageNumber-1) + “,” + pageSize;

数据库连接池工作原理和实现方案

​ 工作原理:JAVA EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。

​ 实现方案:返回的Connection是原始Connection的代理,代理Connection的close方法,当调用close方法时,不是真正关连接,而是把它代理的Connection对象放回到连接池中,等待下一次重复利用。

JDBC连接本机MySQL数据库的代码

Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://localhost/test";
Stirng user='root';
String password='root';
Connection conn = DriverManager.getConnection(url,user,password);

execute,executeQuery,executeUpdate的区别

  • Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpdateCount()方法来获取更新的记录条数。
  • Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null。我们通常使用executeQuery**来执行查询语句**,这样的话如果传进来的是insert或者update语句的话,它会抛出错误信息为 “executeQuery method can not be used for update”的java.util.SQLException。
  • Statement的executeUpdate(String query)方法用来执行insert或者update/delete(DML)语句,或者 什么也不返回DDL语句。返回值是int类型,如果是DML语句的话,它就是更新的条数,如果是DDL的话,就返回0。
  • 只有当你不确定是什么语句的时候才应该使用execute()方法,否则应该使用executeQuery或者executeUpdate方法。

JDBC的 ResultSet

  • 在查询数据库后会返回一个ResultSet,它就像是查询结果集的一张数据表。
  • ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。
  • 默认的ResultSet是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet
  • 当生成ResultSet的Statement对象要关闭或者重新执行或是获取下一个ResultSet的时候,ResultSet对象也会自动关闭。
  • 可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据。

Mysql 操作

MyISAM、InnoDB区别

​ 1、MyIASM是非事务安全的,而InnoDB是事务安全的

​ 2、MyIASM锁的粒度是表级的,而InnoDB支持行级锁

​ 3、MyIASM支持全文类型索引,而InnoDB不支持全文索引

​ 4、MyIASM相对简单,效率上要优于InnoDB,小型应用可以考虑使用MyIASM

​ 5、MyIASM表保存成文件形式,跨平台使用更加方便

Delete、truncaate、drop区别

​ delete 属于DML语句,删除数据,保留表结构,需要commit,可以回滚,如果数据量大,很慢。 truncate 属于DDL语句,删除所有数据,保留表结构,自动commit,不可以回滚,一次全部删除所有数据,速度相对较快。drop属于 DDL语句,删除数据和表结构,不需要commit,删除速度最快。

数据库事务

​ 事务是最小的逻辑工作单元。

​ 事务特性(ACID)

​ 原子性:一个事务里面的操作要么不做,要么都做;

​ 一致性:事务启动之前和启动之后要保持平衡状态。例如完整性约束a+b=10,一个事务改变了a,那么b也应随之改变。

​ 隔离性:在一个会话里面读取不到另一个会话里未提交的数据.

​ 永久性:事务一经提交永不回退。

视图的作用,视图可以更改?

​ 视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。 视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by 则对视图再次order by将被覆盖。

​ 创建视图:create view XXX as XXXXXXXXXXXXXX;

​ 对于某些视图比如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。

索引的工作原理及其种类

​ 数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

​ 索引的缺点:一是增加了数据库的存储空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

​ mysql索引分类:

​ 1、PRIMARY KEY(主键索引) ALTER TABLE table_name ADD PRIMARY KEY ( column )

​ 2、UNIQUE(唯一索引) ALTER TABLE table_name ADD UNIQUE (column )

​ 3.INDEX(普通索引) ALTER TABLE table_name ADD INDEX index_name ( column )

​ 4.FULLTEXT(全文索引) ALTER TABLE table_name ADD FULLTEXT ( column )

​ 5.多列索引ALTER TABLE table_name ADD INDEX index_name ( column1, column2, column3)

SQL语句

show databases;  显示全部数据库
drop data_name; 删除数据库
use data_name; 使用数据库
show tables; 显示数据库的表
desc table_name; 显示表的详细字段信息
rename table name_old to name_new; 表重名
insert into table_name (id, name, score) values(null, "张三", 140),(null, "李四", 150); 插入多条
update table_name set user="张三" where id=2;  更新数据
delete from table_name where id=3;  删除数据
select * from table_name group by score having count(*) > 2;
= 、> 、< 、<>、in(1,2,3...)、between a and b、not/and/or
select * from table_name where name regexp '^[A-D]';  支持正则表达式
select concat(name, '=>', score) from table_name;  字符串连接
avg(平均)、sum(求和)、max(最大)、min(最小)、count(统计数量)
order by desc/asc  按数据的降序/升序排列
create view view_name as select * from table_name where ~~ order by ~~;  创建视图
## 无参数的存储过程
create procedure myFirst_proc()
begin 
select stu_id from score where grade>80 and c_name='计算机';
select name from student where id in 
(select stu_id from(select * from score where grade>80 and c_name='计算机')a 
where a.stu_id in(select stu_id from score where grade>80 and c_name='英语'));
end;
show create procedure myFirst_proc();
call myFirst_proc();

集合和泛型 :

Java中的泛型是什么 ? 使用泛型的好处是什么?

​ Java1.4或更早版本的开发背景的人 都知道,在集合中存储对象并在使用前进行类型转换是多么的不方便。泛型防止了那种情况的发生。它提供了编译期的类型安全,确保你只能把正确类型的对象放入 集合中,避免了在运行时出现ClassCastException。

Java的泛型是如何工作的 ? 什么是类型擦除 ?

​ 泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。

你可以把List传递给一个接受List参数的方法吗?

​ 不能, 因为List可以存储任何类型的对象包括String, Integer等等,而List却只能用来存储Strings。

Array中可以用泛型吗?

​ Array事实上并不支持泛型,这也是为什么Joshua Bloch在Effective Java一书中建议使用List来代替Array,因为List可以提供编译期的类型安全保证,而Array却不能。

为什么Map接口不继承Collection 接口?

  • Set是无序集合,并且不允许重复的元素
  • List是有序的集合,并且允许重复的元素
  • 而Map是键值对
  • 它被视为是键的set和值的set的组合
  • Map被设计为键值对的集合,所以不需要继承Collection 接口

HashMap和Hashtable之间的区别?

  • 同步或线程安全
  • Null键和Null值
  • 迭代值
  • 默认容量大小

集合和数组的区别:

1:数组是固定长度的;集合可变长度的。

2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型

3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

ArrayList 和 LinkedList 有什么区别

​ ArrayList和LinkedList都实现了List接口,有以下的不同点:

​ 1、ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应,LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。

​ 2、相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。 3、LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。

Collection接口:

​ Collection接口是Set,Queue,List的父接口。Collection接口中定义了多种方法可供其子类进行实现,以实现数据操作。 set list 都属于collection的子接口(collection为顶层接口) Map 不属于collection接口

Set HashSet
TreeSet
List ArrayList Vector
LinkedList Stack
Map HashMap Hashtable
TreeMap Properties

Set接口:

​ 无序可变的数组,不允许添加重复元素,如果视图把两个相同的元素加入到同一个集合中,add方法返回false.

set判断对象是否相同使用equals方法, 就是说返回true就表示两个对象相同 set不会接受。

​ HashSet类直接实现了Set接口, 其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。

​ TreeSet实现了SortedSet接口,顾名思义这是一种排序的Set集合,查看jdk源码发现底层是用TreeMap实现的,本质上是一个红黑树原理。 正因为它是排序了的,所以相对HashSet来说,TreeSet提供了一些额外的按排序位置访问元素的方法,例如first(), last(), lower(), higher(), subSet(), headSet(), tailSet().

List接口:

​ 一个 List 是一个元素有序的、可以重复、可以为 null 的集合(有时候我们也叫它“序列”)

​ 实现类有ArrayList、LinkedList、Vector、Stack等

  • ArrayList是基于数组实现的,是一个数组队列。可以动态的增加容量!
  • LinkedList是基于链表实现的,是一个双向循环列表。可以被当做堆栈使用!
  • Vector是基于数组实现的,是一个矢量队列,是线程安全的!
  • Stack是基于数组实现的,是栈,它继承与Vector,特性是FILO(先进后出)!

使用场景

  1. 当集合中对插入元素数据的速度要求不高,但是要求快速访问元素数据,则使用ArrayList!
  2. 当集合中对访问元素数据速度不做要求不高,但是对插入和删除元素数据速度要求高的情况,则使用LinkedList!
  3. 当集合中有多线程对集合元素进行操作时候,则使用Vector!但是现在BVector现在一般不再使用,如需在多线程下使用,可以用CopyOnWriteArrayList,在java.util.concurrent包下。
  4. 当集合中有需求是希望后保存的数据先读取出来,则使用Stack!

Map接口:

​ Map是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。

Java的HashMap是如何工作的?

​ HashMap 基于 hashing 原理,我们通过 put ()和 get ()方法储存和获取对象。当我们将键值对传递给 put ()方法时,它调用键对象的 hashCode ()方法来计算 hashcode,让后找到 bucket 位置来储存值对象。当获取对象时,通过键对象的 equals ()方法找到正确的键值对,然后返回值对象。HashMap 使用 LinkedList 来解决碰撞问题,当发生碰撞了,对象将会储存在 LinkedList 的下一个节点中。 HashMap 在每个 LinkedList 节点中储存键值对对象。

注解:

基本的 Annotation

​ 1、@Overried 重写注解,告诉编辑器要检测该方法是实现父类的

​ 2、@Deprecated 过时注解, 为了兼容以前的程序, 是不能直接把他抛弃,于是就设置他为过时。

​ 3、@SupperssWarings 抑制编译器警告注解,让编辑器不给于我们警告

自定义注解

““java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)//注解的作用范围,就是注解是用在什么地方的
@Retention(RetentionPolicy.RUNTIME)//注解的级别,就是注解能留存到什么时候
@Documented //
@Inherited //
public @interface MyAnnaation {
public String value();//注解可以接收的参数
}
““

​ @Target:说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

​ @Retention定义了 注解的生命周期 SOURCE:在源文件中有效(即源文件保留) ; CLASS:在class文件中有效(即class保留) ; RUNTIME:在运行时有效(即运行时保留) 。

​ @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

​ @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

获取类注解

public class ParseAnn {
    public static void main(String[] args) {
        try {
            // 使用类加载器加载类
            Class c = Class.forName("com.test.Child");
            // 找到类上面的注解
            boolean isExist = c.isAnnotationPresent(Description.class);
            // 上面的这个方法是用这个类来判断这个类是否存在Description这样的一个注解
            if (isExist) {
                // 拿到注解实例,解析类上面的注解
                Description d = (Description) c.getAnnotation(Description.class);
                System.out.println(d.value());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

获取方法注解

Method[] ms = c.getMethods();
// 遍历所有的方法
for (Method m : ms) {
    boolean isExist1 = m.isAnnotationPresent(Description.class);
    if (isExist1) {
        Description d1=m.getAnnotation(Description.class);
        System.out.println(d1.value());
    }
}

反射:

​ 反射是一种间接操作目标对象的机制,在程序程序运行时获取或者设置对象自身的信息。 只要给定类的名字,就可以通过反射获取类的所有信息,接着便能调用它的任何一个方法和属性。

用处

​ jdbc中,获取数据库驱动对象实例的代码,很多框架都用到反射机制,如hibernate、struts、spring。

优缺点

​ 优点:可以动态的创建对象和编译,最大限度发挥了java的灵活性。

​ 缺点:对性能有影响。使用反射基本上一种解释操作,告诉JVM我们要做什么并且满足我们的要求,这类操作总是慢于直接执行java代码。

类反射

class Foot{ void disploy(){ System.out.println("Foot");}}
public class Main {
    public static void main(String[] args) {
        Foot foot = new Foot();
        /**
         * Class 类的实例对象如何表示:
         * 任何一个类都是Class 的实例对象
         */
        // 第一种方式: 任何一个类都有一个静态成员变量class
        Class c1 = Foot.class;
        // 第二种方式: 已经知道该类的对象通过 getClass() 方法获取
        Class c2 = foot.getClass();
        //
        System.out.println(c1 == c2);
        // 第三种方法:
        Class c3 = null;
        try {
            /**
             * Class.forName  不仅表示类的类类型, 还表示类的动态加载类
             * 编译时加载的类是静态加载类,
             * 运行时加载的类是动态加载类,
             */
            c3 = Class.forName("Foot");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(c2 == c3);
        try {
            Foot foot1 = (Foot) c1.newInstance();  // 需要无参数的构造方法
            foot1.disploy();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

方法的反射

class A{
    public void print(int a, int b){
        System.out.println(a + b);
    }
    public void print(String a, String b){
        System.out.println(a + b);
    }
    public void print(){
        System.out.println("hello world");
    }
}
public class MethodMain {
    public static void main(String[] args){
        A a = new A();
        Class c = a.getClass();
        Method m = null;
        {
            try {
                m = c.getMethod("print", int.class, int.class);
                try {
                    // 方法的反射操作
                    // 方法如果没有的返回值返回null, 又返回值返回具体的返回值
                    m.invoke(a, 1, 2);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            System.out.println("==================");
            try {
                m = c.getMethod("print", new Class[]{String.class, String.class});
                try {
                    m.invoke(a, new Object[]{"123", "5678"});
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            System.out.println("==================");
            try {
                m = c.getMethod("print");
                try {
                    m.invoke(a);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }
}

算法:

快速排序

public static void quik_sort(int arr[], int left, int right){
        if(left > right) return;
        int pivot = arr[left];
        int i = left;
        int j = right;
        while(i < j){
            // 查找从右侧开始第一个大于基准值的数的下标
            while (pivot <= arr[j] && i < j) j--;
            // 查找从左侧开始第一个小于基准值的数的下标
            while (pivot >= arr[i] && i < j) i++;
            // 找到后交换位置
            if(i < j){
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        System.out.print("交换值 :" + Arrays.toString(arr));
        // 交换中间位置arr[i]和基准值
        arr[left] = arr[i];
        arr[i] = pivot;
        System.out.println("   ==>  交换基准值 :" + Arrays.toString(arr));
        // 迭代[left, i-1]处的数组
        quik_sort(arr, left, i-1);
        // 迭代[i+1, right]处的数组
        quik_sort(arr, i+1, right);
    }

插入排序

public static void insert_sort(int arr[]){
        int temp, j;
        for(int i = 1; i < arr.length; i++){
            temp = arr[i];
            // 以i位置为分割线, [0, i-1]为一个有序数组, [i, arr.length]为无序数组
            // 用temp临时变量保存i位置的数据, 然后拿i位置的数据arr[i] 和 [0, i-1]之内的有序数组,
            // 进行比较放到有序数组中比这个数字最后一个大的数据的后面。
            for(j = i; j > 0 && arr[j-1] > temp; j--){
                arr[j] = arr[j-1];  // 向前移动一个位置
            }
            arr[j] = temp;  // 插入比这个数最后一个大的后面
            System.out.println("第" + i + "次: " + Arrays.toString(arr));
        }
    }

选择排序

public static void select_sort(int arr[]){
        int temp, index = 0;
        for(int i = 0; i < arr.length; i++){
            int min = arr[i];
            /**
             * 查找每一次[i+1, arr.length]之间的最小值和最小值下标并保存
             */
            for(int j = i + 1; j < arr.length; j++){
                if(arr[j] < min){
                    min = arr[j];
                    index = j;
                }
            }
            System.out.print("最小值是:" + min + " --> 下标 : " + index);
            /**
             * 比较arr[i] 和 arr[index] ; if arr[i] > arr[index]  交换;
             */
            if(arr[i] > min){
                temp = arr[i];
                arr[i] = min;
                arr[index] = temp;
            }
            System.out.println("   第" + i + "次: " + Arrays.toString(arr));
        }
    }

设计模式:

单例模式

/**
* 懒汉模式
*/
public class Singleton {
    private static Singleton singleton = null;
    private Singleton(){}
    synchronized public static Singleton getSingleton(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}
/**
* 饿汉模式
*/
public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton(){}
    public synchronized static Singleton getSingleton(){
        return singleton;
    }
}

工厂模式

// 接口
public interface Car {
    public void Start();
}
// 宝马车
public class BaoCar implements Car {
    @Override
    public void Start() {
        System.out.println("宝马车---->");
    }
}
// 奔驰车
public class BenCar implements Car {
    @Override
    public void Start() {
        System.out.println("奔驰车----->");
    }
}
// 汽车工厂
public class Factory {
    // 通过反射动态加载类
    public static void main(String[] args) {
        try {
            Class c = Class.forName("BaoCar");
            try {
                Car car = (Car)c.newInstance();
                car.Start();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

抽象工厂

// 抽象工厂模式
/**
 * 工厂的接口
 */
interface HumanFactory{
    MakeMoney getMakeMoney();
}
/**
 * 赚钱的接口
 */
interface MakeMoney{
    void doMakeMoney();
}
/**
 * 分别实现男人和女人的接口实现
 */
class ManFactory implements HumanFactory{
    @Override
    public MakeMoney getMakeMoney() {
        return new ManMakeMoney();
    }
}
class WomanFactory implements HumanFactory{
    @Override
    public MakeMoney getMakeMoney() {
        return new WomanMakeMoney();
    }
}
/**
 * 分别实现男人和女人的接口实现
 */
class ManMakeMoney implements MakeMoney{
    @Override
    public void doMakeMoney() {
        System.out.println("男人赚钱!");
    }
}
class WomanMakeMoney implements MakeMoney{
    @Override
    public void doMakeMoney() {
        System.out.println("女人赚钱!");
    }
}
public class Factory {
    public static void main(String[] args) {
        HumanFactory manMake = new ManFactory();
        manMake.getMakeMoney().doMakeMoney();
        HumanFactory womanMake = new WomanFactory();
        womanMake.getMakeMoney().doMakeMoney();
    }
}

门脸模式

/**
 * 门脸模式
 */
interface RepairFactory{
    String fix_A();
}
class Factory implements RepairFactory{
    @Override
    public String fix_A() {
        System.out.println("修理:");
        return "修理A";
    }
}
class PublicAgent{
    private RepairFactory factory = new Factory();
    public void repairForA(){
        String a = factory.fix_A();
        System.out.println(a);
    }
}
public class Facade {
    public static void main(String[] args) {
        PublicAgent publicAgent = new PublicAgent();
        publicAgent.repairForA();
    }
}

建造者模式

//1、Builder:为创建一个产品对象的各个部件指定抽象接口。
interface PersonBuilder{
    void buildHead();
    void buildBody();
    void buildFoot();
    Person buildPerson();
}
//2、ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。
class ManBuilder implements PersonBuilder{
    Person person;
    public ManBuilder(){
        person = new Man();
    }
    public void buildBody(){
        person.setBody("建造男人的身体");
        System.out.println("建造男人的身体");
    }
    public void buildFoot(){
        person.setFoot("建造男人的脚");
        System.out.println("建造男人的脚");
    }
    public void buildHead(){
        person.setHead("建造男人的头");
        System.out.println("建造男人的头");
    }
    public Person buildPerson(){
        return person;
    }
}
class WomanBuilder implements PersonBuilder{
    Person person;
    public WomanBuilder(){
        person = new Woman();
    }
    public void buildBody(){
        person.setBody("建造女人的身体");
        System.out.println("建造女人的身体");
    }
    public void buildFoot(){
        person.setFoot("建造女人的脚");
        System.out.println("建造女人的身体");
    }
    public void buildHead(){
        person.setHead("建造女人的头");
        System.out.println("建造女人的身体");
    }
    public Person buildPerson(){
        return person;
    }
}
//3、Director:构造一个使用Builder接口的对象,指导构建过程。
class PersonDirector{
    public Person contructPerson(PersonBuilder pb){
        pb.buildHead();
        pb.buildBody();
        pb.buildFoot();
        return pb.buildPerson();
    }
}
//4、Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
class Person{
    private String head;
    private String body;
    private String foot;
    public String getHead(){
        return head;
    }
    public void setHead(String head){
        this.head = head;
    }
    public String getBody(){
        return body;
    }
    public void setBody(String body){
        this.body = body;
    }
    public String getFoot(){
        return foot;
    }
    public void setFoot(String foot){
        this.foot = foot;
    }
}
class Man extends Person{
    public Man(){
        System.out.println("开始建造男人!");
    }
}
class Woman extends Person{
    public Woman(){
        System.out.println("开始建造女人!");
    }
}
public class Builder {
    public static void main(String args[]){
        PersonDirector pd = new PersonDirector();
        Person womanPerson = pd.contructPerson(new ManBuilder());
        Person manPerson = pd.contructPerson(new WomanBuilder());
    }
}

策略模式

//策略模式
// 抽象策略类
interface CarFunction{
    void run();
}
// 具体策略类父类
class Car implements CarFunction{
    protected String name;
    protected String color;
    private CarFunction carFunction;
    public Car(String name, String color){
        this.name = name;
        this.color = color;
    }
    @Override
    public void run() {
        System.out.println(color + " " + name + "在行驶...");
    }
}
// 具体策略类
class SmallCar extends Car{
    public SmallCar(String name, String color){
        super(name, color);
    }
    @Override
    public void run() {
        System.out.println(color + " " + name + "在行驶...");
    }
}
class BussCar extends Car{
    public BussCar(String name, String color){
        super(name, color);
    }
    @Override
    public void run() {
        System.out.println(color + " " + name + "在行驶...");
    }
}
// 应用场景类
class Person{
    private String name;
    private Integer age;
    private Car car;
    public void driver(Car car){
        System.out.print(name + " " + age + "开着  ");
        car.run();
    }
    public Person(String name, Integer age){
        this.name = name;
        this.age = age;
    }
}
// 运行环境类
public class Strategy {
    public static void main(String[] args) {
        Car smallCar = new SmallCar("路虎", "黑色");
        Car bussCar = new BussCar("公交车", "白色");
        Person person = new Person("小明", 20);
        person.driver(smallCar);
        person.driver(bussCar);
    }
}

Spring:

Spring IOC实现原理 :

​ Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度。而spring的核心是IOC控制反转和AOP面向切面编程。IOC控制反转主要强调的是程序之间的关系是由容器控制的,容器控制对象,控制了对外部资源的获取。而反转即为,在传统的编程中都是由我们创建对象获取依赖对象,而在IOC中是容器帮我们创建对象并注入依赖对象,正是容器帮我们查找和注入对象,对象是被获取,所以叫反转。

Spring AOP实现原理 :

​ AOP:面向切面编程,主要是管理系统层的业务,比如日志,权限,事物等。AOP是将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为切面(aspect),切面将那些与业务逻辑无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

Spring事务 :

配置事务管理器:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
</bean>
<!--&lt;!&ndash;开启基于注解的事务,使用xml配置形式的事务(必要主要的都是使用配置式)  &ndash;&gt;-->
<aop:config>
    <!--&lt;!&ndash; 切入点表达式 &ndash;&gt;-->
    <aop:pointcut expression="execution(* com.app.service..*(..))" id="txPoint"/>
    <!--&lt;!&ndash; 配置事务增强 &ndash;&gt;-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<!--&lt;!&ndash;配置事务增强,事务如何切入  &ndash;&gt;-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!--&lt;!&ndash; 所有方法都是事务方法 &ndash;&gt;-->
        <tx:method name="*"/>
        <!--&lt;!&ndash;以get开始的所有方法  &ndash;&gt;-->
        <tx:method name="get*" read-only="true"/>
    </tx:attributes>
</tx:advice>

Spring MVC:

SpringMVC的流程

​ 1.用户发送请求至前端控制器DispatcherServlet

​ 2.DispatcherServlet收到请求调用HandlerMapping处理器映射器。

​ 3.处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

​ 4.DispatcherServlet通过HandlerAdapter处理器适配器调用处理器

​ 5.执行处理器(Controller,也叫后端控制器)。

​ 6.Controller执行完成返回ModelAndView

​ 7.HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

​ 8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器

​ 9.ViewReslover解析后返回具体View

​ 10.DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。

​ 11.DispatcherServlet响应用户

SpringMVC与Struts2的主要区别

​ ①springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。

​ ②springmvc是基于方法开发,传递参数是通过方法形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
③Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成ModelAndView对象,最后又将模型数据通过request对象传输到页面。 Jsp视图解析器默认使用jstl。

如何解决POST请求中文乱码问题,GET的又如何处理呢

<!-- 在web.xml中加入 -->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

对于get请求中文参数出现乱码:

// 修改tomcat配置文件
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

SpringMvc的控制器是不是单例模式,如果是,有什么问题,怎么解决

是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段 。

SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代

一般用@Conntroller注解,表示是表现层,不能用用别的注解代替。

@RequestMapping注解用在类上面有什么作用

用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

怎么样把某个请求映射到特定的方法上面

直接在方法上面加上注解@RequestMapping,并且在这个注解里面写上要拦截的路径 。

如果在拦截请求中,我想拦截get方式提交的方法,怎么配置

可以在@RequestMapping注解里面加上method=RequestMethod.GET 。

我想在拦截的方法里面得到从前台传入的参数,怎么得到

直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样 。

SpringMvc中函数的返回值是什么

返回值可以有很多类型,有String, ModelAndView,当一般用String比较好 。

SpringMVC怎么样设定重定向和转发的

在返回值前面加”forward:”就可以让结果转发,譬如”forward:user.do?name=method4” 在返回值前面加”redirect:”就可以让返回值重定向,譬如”redirect:http://www.baidu.com” 。

SpringMvc中有个类把视图和数据都合并的一起的,叫什么

ModelAndView 。

怎么样把ModelMap里面的数据放入Session里面

可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key 。

SpringMvc怎么和AJAX相互调用的

通过Jackson框架就可以把Java里面的对象直接转化成Js可以识别的Json对象

具体步骤如下

​ 1.加入Jackson.jar

​ 2.在配置文件中配置json的映射

​ 3.在接受Ajax方法里面可以直接返回Object,List等, 但方法前面要加上@ResponseBody注解 。

当一个方法向AJAX返回特殊对象,譬如Object,List等,需要做什么处理

要加上@ResponseBody注解。

SpringMvc里面拦截器是怎么写的

<!-- 只针对部分请求拦截 -->
<mvc:interceptor>
   <mvc:mapping path="/modelMap.do" />
   <bean class="com.et.action.MyHandlerInterceptorAdapter" />
</mvc:interceptor>

讲下SpringMvc的执行流程

​ 系统启动的时候根据配置文件创建spring的容器, 首先是发送http请求到核心控制器disPatherServlet,spring容器通过映射器去寻找业务控制器, 使用适配器找到相应的业务类,在进业务类时进行数据封装,在封装前可能会涉及到类型转换,执行完业务类后使用ModelAndView进行视图转发,数据放在model中,用map传递数据进行页面显示。

mybatis:

#{}和${}的区别

  • #{}是预编译处理,${}是字符串替换。
  • Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
  • Mybatis在处理 {}替换成变量的值。
  • 使用#{}可以有效的防止SQL注入,提高系统安全性。

Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?

  • Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能
  • Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。
  • 其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能

为什么说Mybatis是半自动ORM映射工具

​ 而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。

Mybatis是如何进行分页的?分页插件的原理是什么?

​ 分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

MyBatis的一级缓存和二级缓存

​ Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象

​ Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。二级缓存是可以跨SqlSession的。

​ Mybatis默认开启一级缓存,没有开启二级缓存,二级缓存需要在xml配置中手动配置开启。

Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签

​ 、、、、,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等 。

git/SVN:

svn

​ 集中式版本控制系统(文档管理很方便) ;.企业内部并行集中开发 ;windows系统上开发推荐使用。

git

​ 分布式系统(代码管理很方便);开源项目开发; mac,Linux系统上开发推荐使用。

maven:

​ Maven简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝连接。 Maven增加可重用性并负责建立相关的任务。

HTTP

  • 200 OK 请求正常处理完毕
  • 204 No Content 请求成功处理,没有实体的主体返回
  • 206 Partial Content GET范围请求已成功处理
  • 301 Moved Permanently 永久重定向,资源已永久分配新URI
  • 302 Found 临时重定向,资源已临时分配新URI
  • 303 See Other 临时重定向,期望使用GET定向获取
  • 304 Not Modified 发送的附带条件请求未满足
  • 307 Temporary Redirect 临时重定向,POST不会变成GET
  • 400 Bad Request 请求报文语法错误或参数错误
  • 401 Unauthorized 需要通过HTTP认证,或认证失败
  • 403 Forbidden 请求资源被拒绝
  • 404 Not Found 无法找到请求资源(服务器无理由拒绝)
  • 500 Internal Server Error 服务器故障或Web应用故障
  • 503 Service Unavailable 服务器超负载或停机维护

Tomcat:

tomcat 有那几种Connector 运行模式 ?

1)、bio 默认的模式,性能非常低下,没有经过任何优化处理和支持。

2)、nio 利用java的异步io护理技术,no blocking IO技术。

3)、apr 安装起来最困难,但是从操作系统级别来解决异步的IO问题,大幅度的提高性能。

​ protocol为org.apache.coyote.http11.Http11AprProtocol

tomcat优化

需要修改conf/server.xml文件,主要是优化连接配置,关闭客户端dns查询。

<Connector port="8080"   
    protocol="org.apache.coyote.http11.Http11NioProtocol"  
    connectionTimeout="20000"  
    redirectPort="8443"   
     maxThreads="500"   
     minSpareThreads="20"  
    acceptCount="100" 
    disableUploadTimeout="true" 
    enableLookups="false"   
    URIEncoding="UTF-8" />

TCP/IP

TCP/IP是一个四层协议系统.

(1)链路层,有时也称作数据链路层或网络接口曾,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。

(2)网络层,有时也称作互联网层,处理分组在网络中的活动。网络层协议包括IP协议(网际协议),ICMP协议(internet互联网控制报文协议),以及IGMP协议(Internet组管理协议)

(3)运输层,包含协议TCP(传输控制协议)和UDP(用户数据报协议)。TCP把数据分成小块,交给网络层。UDP则为应用层提供服务,把数据报的分组从一台主机发送到另一台主机,但并不保证发送到另一台主机。

(4)应用层负责处理特定的应用程序细节。Telnet远程登录,FTP文件传输协议,SMTP简单邮件传送协议,SNMP简单网络管理协议。

建立TCP的三次握手:

(1)、客户(请求端)发送一个SYN段指明客户打算连接的服务器端口,以及初始序号(ISN)这个SYN称为报文段I

(2)、服务器发回包含服务器的初始序号的SYN报文段作为应答。同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。

(3)、客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认。

连接终止协议四次握手:

(1)、终止命令收到后,导致TCP客户端发送一个FIN,用来关闭从客户到服务器的数据传送。

(2)、服务器收到FIN,发回ACK,确认序号为收到的序号加1

(3)、同时服务器向应用程序传送一个文件结束符。接着这个服务器程序就关闭它的链接,发送一个FIN

(4)、客户必须发回一个 你,并将确认序号设置为收到序号+1

ajax:

url:  发送请求的地址。
type: 请求方式(post或get)默认为get。
async: 同步异步请求,默认true所有请求均为异步请求。
timeout : 超时时间设置,单位毫秒
data:要求为Object或String类型的参数,发送到服务器的数据
cache:默认为true(当dataType为script时,默认为false), 设置为false将不会从浏览器缓存中加载请求信息。
dataType: 预期服务器返回的数据类型。
html:返回纯文本HTML信息;包含的script标签会在插入DOM时执行。
script:返回纯文本JavaScript代码。不会自动缓存结果。
json:返回JSON数据。
jsonp:JSONP格式。使用JSONP形式调用函数时,例如myurl?callback=?,JQuery将自动替换后一个“?”为正确的函数名,以执行回调函数。
text:返回纯文本字符串。
success:请求成功后调用的回调函数,有两个参数。
    (1) 由服务器返回,并根据dataType参数进行处理后的数据。
    (2) 描述状态的字符串。
error:要求为Function类型的参数,请求失败时被调用的函数。该函数有3个参数
    (1) XMLHttpRequest对象
    (2) 错误信息
    (3) 捕获的错误对象(可选)
complete :function(XMLHttpRequest,status){ //请求完成后最终执行参数

ps:明天要去面试了,祝自己加油!也祝大家也可以找一个适合自己的工作,成为大佬!

猜你喜欢

转载自blog.csdn.net/yhflyl/article/details/80876171