1、同步异步区别
同步:发送一个请求,等待返回,然后再发送下一个请求 。
异步:发送一个请求,不等待返回,随时可以再发送下一个请求 。
并发:同时发送多个请求
同步可以避免出现死锁,一般共享某一资源的时候用,如果每个人都有修改权限,同时修改一个文件,有可能使一个人读取另一个人已经删除的内容,就会出错,同步就会按顺序来修改。异步则是可以提高效率了,现在cpu都是双核,四核,异步处理的话可以同时做多项工作,当然必须保证是可以并发处理的。
2、线程和进程区别
进程是程序的一次执行,而线程可以理解为进程中执行的一段程序片段。进程间是独立的,而线程运行在进程空间中。
3、线程的5种状态
新建、就绪、运行、阻塞、死亡
4、servlet的九大内置对象
1)request 封装了用户的提交信息,该对象调用相应的方法获取用户提交参数信息。
2)response 对客户端的请求做出响应,然后向客户端发送数据。
3)session 从浏览器的开启到关闭称为一个会话。session可以保存用户的登录信息。
4)application 服务器启动的时候创建此对象,所有客户共享这个application对象,直到服务器关闭。
5)out 输出对象 用来向客户端输出数据。
6)page 当前jsp页面本身。
7)config 该实例代表jsp的配置信息。
8)exception 处理界面中出现的异常信息。
9)pagecontext 代表当前页面的常用属性,通过他获取其他的8大内置对象。
5、Ajax请求
$.ajax({ type : "POST", //提交方式 url : "${pageContext.request.contextPath}/org/doDelete.action",//路径 data : { "org.id" : "${org.id}" },//数据,这里使用的是Json格式进行传输 success : function(result) {//返回数据根据结果进行相应的处理 if ( result.success ) { $("#tipMsg").text("删除数据成功"); tree.deleteItem("${org.id}", true); } else { $("#tipMsg").text("删除数据失败"); } } });
6、跨域
7、数据结构
List:有序的可重复的。
实现方式ArrayList和LinkedList 区别
不同点:ArrayList数据结构是基于数组实现的,数据的查询速度比较快,不适合数据的插入和删除操作,因为需要移动元素。
LinkedList的数据结构是基于双向链表实现的,适合数据的插入和删除操作,不适合数据的查询操作。
相同点:两者都是线程不安全的,对于ArrayList集合如果两个线程同时往集合中添加数据 可能出现数组越界异常和null的情况。
对于LinkedList集合如果多个线程同时往某个节点添加数据的时候、再去查询可能查到的数据不是当前线程插入的数据元素。
解决方法就是使用线程安全的集合(vector)或者使用同步代码块。
Set:无序的不可重复的。
实现方式HashSet和LinkHashSet 都是线性不安全的。
Map:键是唯一的。
实现方式 HashMap和HashTable
区别:HashTable是线性安全的,HashMap是线性不安全的。对于HashMap可以使用currentHashMap替换HashMap
8、String、StringBuilder和StringBuffer三者的区别
String是被final修饰的,不能被继承。其成员属性也是final修饰。
String的常用方法 substring、split、replace、format、contract、equals、indexof
“对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。(String是不可变的对象)
1)String str="hello world"和String str=new String("hello world")的区别
public class Main {
public static void main(String[] args) {
String str1 = "hello world";
String str2 = new String("hello world");
String str3 = "hello world";
String str4 = new String("hello world");
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str2==str4);
}
}
这段代码的输出结果为
false
true
false
String str1 = "hello world";和String str3 = "hello world"; 都在编译期间生成了字面常量和符号引用,运行期间字面常量"hello world"被存储在运行时常量池(当然只保存了一份)。JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。
通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。
2)StringBuffer是线性安全的可变对象,可以使用append方法进行字符串的追加。
3)Stringbuilder是线性不安全的可变对象,同样可以使用append的方法进行字符串的追加。如果不是多线程操作的情况下可以使用Stringbuilder.
效率上Stringbuilder>StringBuffer>String
三者使用的场景:
当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。
1. 下面这段代码的输出结果是什么?
String a = "hello2"; String b = "hello" + 2; System.out.println((a == b));
输出结果为:true。原因很简单,"hello"+2在编译期间就已经被优化成"hello2",因此在运行期间,变量a和变量b指向的是同一个对象。
2.下面这段代码的输出结果是什么?
String a = "hello2"; String b = "hello"; String c = b + 2; System.out.println((a == c));
输出结果为:false。由于有符号引用的存在,所以 String c = b + 2;不会在编译期间被优化,不会把b+2当做字面常量来处理的,因此这种方式生成的对象事实上是保存在堆上的。因此a和c指向的并不是同一个对象
3.下面这段代码的输出结果是什么?
String a = "hello2"; final String b = "hello"; String c = b + 2; System.out.println((a == c));
输出结果为:true。对于被final修饰的变量,会在class文件常量池中保存一个副本,也就是说不会通过连接而进行访问,对final变量的访问在编译期间都会直接被替代为真实的值。那么String c = b + 2;在编译期间就会被优化成:String c = "hello" + 2;
4.下面这段代码输出结果为:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Main {
public static void main(String[] args) {
String a = "hello2";
final String b = getHello();
String c = b + 2;
System.out.println((a == c));
}
public static String getHello() {
return "hello";
}
}
|
输出结果为false。这里面虽然将b用final修饰了,但是由于其赋值是通过方法调用返回的,那么它的值只能在运行期间确定,因此a和c指向的不是同一个对象。
5.String str = new String("abc")创建了多少个对象?
该段代码执行过程和类的加载过程是有区别的。在类加载的过程中,确实在运行时常量池中创建了一个"abc"对象,而在代码执行过程中确实只创建了一个String对象。
6.下面这段代码1)和2)的区别是什么?
|
1
2
3
4
5
6
7
8
|
public class Main {
public static void main(String[] args) {
String str1 = "I";
//str1 += "love"+"java"; 1)
str1 = str1+"love"+"java"; //2)
}
}
|
1)的效率比2)的效率要高,1)中的"love"+"java"在编译期间会被优化成"lovejava",而2)中的不会被优化
值传递和引用传递
1、按值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。简单来说就是直接复制了一份数据过去,因为是直接复制,所以这种方式在传递时如果数据量非常大的话,运行效率自然就变低了,所以java在传递数据量很小的数据是值传递,比如java中的各种基本类型:int,float,double,boolean等类型的,具体可以自己测试。
结果:
2、按引用传递:引用传递其实就弥补了上面说的不足,如果每次传参数的时候都复制一份的话,如果这个参数占用的内存空间太大的话,运行效率会很底下,所以引用传递就是直接把内存地址传过去,也就是说引用传递时,操作的其实都是源数据,这样的话修改有时候会冲突,记得用逻辑弥补下就好了,具体的数据类型就比较多了,比如Object,二维数组,List,Map等除了基本类型的参数都是引用传递。代码:
有些文章中写的是java中所有的传参方式都是按值传递,这也说得通,无非就是文字游戏,因为无论是按值传递还是按引用传递都是把值传递过去了,所以就叫按值传递。
接口和抽象类区别
1)接口中的方法都是抽象的方法,属性都是常量,接口可以多实现,实现接口后必须实现其抽象方法。
2)抽象类中的方法可以是抽象的也可以是非抽象的,抽象类不能实例化,子类继承抽象父类后可以实现其抽象方法,这样的话子类就可以进行实例化,否则子类仍然是抽象类。子类可以重写父类的非抽象方法。3)抽象类可以包含构造函数,其目的不是为了构造对象,而是为了子类进行初始化。
4) 抽象类中不能出现final、private、static等关键字。
5)接口是多实现的,而类是单继承的。
多线程操作
常用的设计模式
单例模式
/**
* 方法四
* 单例模式最优方案
* 线程安全 并且效率高
*
*/
public class SingletonTest {
// 定义一个私有构造方法
private SingletonTest() {
}
//定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用)
private static volatile SingletonTest instance;
//定义一个共有的静态方法,返回该类型实例
public static SingletonTest getIstance() {
// 对象实例化时与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率)
if (instance == null) {
//同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建)
synchronized (SingletonTest.class) {
//未初始化,则初始instance变量
if (instance == null) {
instance = new SingletonTest();
}
}
}
return instance;
}
}
工厂设计模式
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
一个栗子:
我喜欢吃面条,抽象一个面条基类,(接口也可以),这是产品的抽象类。
public abstract class INoodles {
/**
* 描述每种面条啥样的
*/
public abstract void desc();
}
工厂如下:
public class MulWayNoodlesFactory {
/**
* 模仿Executors 类
* 生产泡面
*
* @return
*/
public static INoodles createPm() {
return new PaoNoodles();
}
/**
* 模仿Executors 类
* 生产兰州拉面
*
* @return
*/
public static INoodles createLz() {
return new LzNoodles();
}
/**
* 模仿Executors 类
* 生产干扣面
*
* @return
*/
public static INoodles createGk() {
return new GankouNoodles();
}
}
使用时:
/**
* 多方法静态工厂(模仿Executor类)
*/
System.out.println("==============================模仿Executor类==============================" +
"\n 这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑");
INoodles lz2 = MulWayNoodlesFactory.createLz();
lz2.desc();
INoodles gk2 = MulWayNoodlesFactory.createGk();
gk2.desc();
面向切面编程
将业务逻辑代码和繁琐事务代码(日志的处理、事务的开始、事务的提交)分开,将精力主要放在业务逻辑的处理上。最后将繁琐的代码动态的植入到程序中。
依赖注入(控制反转)
依赖注入和控制反转是同一个概念,当我们在一个类中需要另一个类的实例的时候,通常我们会new 这个类的实例,在Spring中创建被调用者的实例由Spring容器来完成,然后注入到调用者,这就是依赖注入。
drop truncate delete区别
drop table stu; 删除表,释放空间
truncate table stu; 保留表的结构,删除数据,释放空间,不能恢复,速度快
delete from stu 删除数据,可以恢复,速度慢



2453

被折叠的 条评论
为什么被折叠?



