第一天
1.
/*结果是什么?*/
int i = 0b110;
int j = 0b110;
System.out.println(i|j);
答案
i | j 或运算
110
110
i | j = 110 = 6
所以答案是6
2.
数据库操作的时候,什么情况下需要用到事务?
答案
当数据库需要处理操作量大、复杂度高的数据的时候需要用到事务。用事务是为了保证数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:
1、为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2、当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
当事务被提交给了数据库管理系统,则数据库管理系统需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。
3.
了解泛型么?简述泛型的上界和下界?
答案
有时候希望传入的类型有一个指定的范围,从而可以进行一些特定的操作,这时候就需要通配符,在Java中常见的通配符主要有以下几种:
符号 | 描述 |
---|---|
<?> | 无限制通配符 |
<? extends E> | extends 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类 |
<? super E> | super关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类它们的目的都是为了使方法接口更为灵活,可以接受更为广泛的类型 |
< ? extends E> | 用于灵活读取,使得方法可以读取 E 或 E 的任意子类型的容器对象。 |
< ? super E> | 用于灵活写入或比较,使得对象可以写入父类型的容器,使得父类型的比较方法可以应用于子类对象。 |
4.
三个小问:请分析这个类是否能够正常使用?是否有不妥的地方?如果有的话,为什么不妥?(可以从类的实际使用,以及定义规范角度思考)
class person {
public person parent ;// 人类的父亲仍旧是人类
public person(person parent) {
this.parent = parent;
}
public person getParent() {return parent;}
public void setParent(person parent) {this.parent = parent;}
}
答案
关于不妥的地方,有三点:
(1)类名大写,原因不多说。
(2)成员字段需要封装,原因如下:
1.我们需要把字段(成员变量)和实现细节隐藏起来,不允许外部直接访问。
在封装情况下,我们只能通过getter获取对象调用对象方法,setter修改对象的内存地址(实例化新对象),如果不封装,我们就可以直接获取到对象本身,可以肆意调用对象方法以及实例化一个新的对象,出现问题时不容易排查。
(3)构造方法要有无参构造,原因如下:
1.子类继承父类的时候会自动继承父类的默认构造函数(也就是继承那个无参数的构造函数)。
2.无参构造函数是所有构成函数的父类,如果没有写那个默认的不带参数的构造函数的话,继承的时候子类就会报错,因为系统不知道要不继承哪个构造函数,必须明确的使用super()关键字来描述。所以一般为了避免这种错误的发生,在有带有多个构造函数的类里面都会写一个不带参数的构造函数。
这个类本身编译没有错,但遗憾的是,我们无法实例化该类。因为构造方法的参数同样是这个类的对象。要修改的话可以再定义一个空构造器。
第二天
1. js中“==”与“===”,“!=”与“!==”的区别?
1.实例:假设 a=2,
==:等于。注意双等号在JS中才表示等于,一个等号为赋值。比较:a == 2,返回 ture。 a == 1,返回false。
===:绝对等于,值和类型均相等。比较:a === ‘2’,返回 false。a === 2,返回 true。
!=:不等于。和等于相反。比较:a != 2,返回 false,a != 1,返回 ture。
!==:绝对不等于,和绝对等于相反,值和类型均不相等。比较:a !== ‘2’,返回 true, a !== 2,返回 false。
2. 如何实现对象克隆?
答:java有两种方式:
1) 实现Cloneable接口并重写Object类中的clone()方法;
2) 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正 的深度克隆。
注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定, 可以检查
出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常, 这种是方案
明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是好过 把问题留到运行时。
3)js中也有clone,加参数true是深克隆(浅克隆只赋值父亲)
3. List、Set、Map是否继承自Collection接口?
答:List、Set 是,Map 不是,它本身就是最大的。Map是键值对映射容器,与List和 Set有明显的区别,
而Set存储的零散的元素且不允许有重复元素(数学中的集合也是如此),
List是线性结构的容器,适用于按数值索引访问元素的情形。
4. Java 中的final关键字有哪些用法?
答:
(1)修饰类:表示该类不能被继承;
(2)修饰方法:表示方法不能被重写;
(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
第三天
1. Test.main()函数执行后的输出是( )
class Test {
public static void main(String[] args) {
System.out.println(new B().getValue());
}
static class A {
protected int value;
public A (int v) {
setValue(v);
}
public void setValue(int value) {
this.value= value;
}
public int getValue() {
try {
value ++;
return value;
} finally {
this.setValue(value);
System.out.println(value);
}
}
}
static class B extends A {
public B () {
super(5);
setValue(getValue()- 3);
}
public void setValue(int value) {
super.setValue(2 * value);
}
}
}
A: 11 17 34
B: 22 74 74
C: 6 7 7
D: 22 34 17
D
首先,super()函数指的是调用父类的构造方法
①
new B()
执行B的构造函数,第一行是super(5);
此时执行的是A的构造函数,A的构造函数调用的是setValue()方法,由于B重写了A的这个方法,
所以!!!执行的是B的 setValue()方法。
即传入的参数是2*5=10
此时,因为super,所以调用的是父类的 setValue()方法,即value=10
第一行执行完毕。
第二行是 setValue(getValue()-3);
B没有getValue()方法,故执行父类的此方法,
try返回的是value=10+1=11,保存在临时栈中
finally中调用this的方法,这个this指的是B的对象,又重写,故就是B的 setValue()方法
value=2*11=22,第一个打印到屏幕上的数字
接下来参数 getValue()-3=11-3=8
传入B的 setValue()方法
此时value=2*8=16
至此,new B()执行结束
②
new B(). getValue()
B没有 getValue(),故执行A的 getValue()
try返回16+1=17,保存到临时栈中
finally调用B的 setValue()方法
value=17*2=34,第二个打印到屏幕上面的数字
最后主函数打印返回值,也就是try保存到临时栈的17
2. 使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。
栈内存:基本类型的变量和引用变量都在函数的栈内存中分配,
栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
堆内存用来存放由new创建的对象和数组。
在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
栈中引用变量的取值等于数组或对象在堆内存中的首地址。引用变量就相当于是为数组或者对象起的一个名称。在程序中使用栈中的引用变量来访问堆中的数组或对象。
3. 当一个线程进入一个对象的一个 synchronized 方法后,其它线程是否可进入此对象的其它方法 ?
分几种情况:
- 其他方法前是否加了 synchronized 关键字,如果没加,则能。
- 如果这个方法内部调用了 wait ,则可以进入其他 synchronized 方法。
- 如果其他方法都加了 synchronized 关键字,并且内部没有调用 wait ,则不能。
- 如果其他方法是 static ,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是 this 。
4. js中null和undefined的区别?
null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
当声明的变量还未被初始化时,变量的默认值为undefined。 null用来表示尚未存在的对象。
undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2)调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
null表示"没有对象",即该处不应该有值。典型用法是:
(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
第四天:
1. true、false、null、sizeof、goto、synchronized 哪些是Java关键字?
goto synchronized
2. 执行语句 int a= “2” 后,a的值是( ) A.2 B.50 C.49 D.0
2的ASCII码为50.常用ASCII码值:空格为32,数字0为48,字母A为65,字母a为97
3.以下代码可以使用的修饰符是(多选):()
public interface Status {
/INSERT CODE HERE/ int MY_VALUE=10;
}
A.final B.static C.abstract D.public
答案:C
abstract只能修饰类和方法,不能修饰字段。接口中字段的修饰符public static final默认不写,方法的修饰符public abstract默认不写
4.下面代码输出的是什么?
public class Base
{
private String baseName = "base";
public Base()
{
callName();
}
public void callName()
{
System. out. println(baseName);
}
static class Sub extends Base
{
private String baseName = "sub";
public void callName()
{
System. out. println (baseName) ;
}
}
public static void main(String[] args)
{
Base b = new Sub();
}
}
A. base B.sup C.null
答案:C
new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。
创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null
第五天
1.题目:利用条件运算符的嵌套来完成此题:
/*学习成绩> =90 分的同学用A 表示,60-89 分之
*间的用B 表示,60 分以下的用C 表示。
*/
import java.util.Scanner;
public class Demo5{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
System.out.println("请输入成绩:");
double score = s.nextDouble();
//此处输入答案
System.out.println("您的等级是:"+c);
}
}
答案:char c = score >= 90 ? ‘A’: (score >=60 && score <=89 ? ‘B’ : (score < 60 ? ‘C’:‘S’));
2.Enumeration和Iterator接口的区别?
Enumeration的速度是Iterator的两倍,也使用更少的内存。Enumeration是非常基础的,也满足了基础的需要。
但是,与Enumeration相比,Iterator更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。
迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者从集合中移除元素,
而Enumeration不能做到。为了使它的功能更加清晰,迭代器方法名已经经过改善。
3.编程题: 用最有效率的方法算出2乘以8等於几??
? 2 << 3
4.加载类的方式列举几种?
1)从本地系统直接加载
2)通过网络下载.class文件
3)从zip,jar等归档文件中加载.class文件
4)从专有数据库中提取.class文件
5)将Java源文件动态编译为.class文件(服务器)
5.java中会存在内存泄漏吗,请简单描述。
因为Java是自动进行垃圾回收管理的,所以不存在 C语言中同等概念的内存泄漏,但是存在Java特色的内存泄漏
当某些对象不被使用,但是又有非直接引用指向的时候,那么就不满足垃圾回收的条件,而形成内存泄漏。
比如代码中的例子,每个Object创建的时候,有一个引用o指向,接着就被放进了集合al中。 下一个Object创建的时候,上一个Object就没有引用指向了。
这些Object都没有引用指向,但是却放在ArrayList中,而这个Arraylist忘记了回收,那么里面的所有对象,都会一直存活下去,虽然不再被使用了。
package j2se;
import java.util.ArrayList;
public class MemoryLeak {
static ArrayList<Object> al = new ArrayList<Object>();
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Object o = new Object();
al.add(o);
}
}
}
6.Number()和parseInt()的区别
Number()和parseInt()一样,都可以用来进行数字的转换
区别在于,当转换的内容包含非数字的时候,Number() 会返回NaN(Not a Number)
parseInt() 要看情况,如果以数字开头,就会返回开头的合法数字部分,如果以非数字开头,则返回NaN
通过Number() 函数转换字符串’123’ 后得到的数字:123
通过Number() 函数转换字符串’123abc’ 后得到的数字:NaN
通过Number() 函数转换字符串’abc123’ 后得到的数字:NaN
通过parseInt() 函数转换字符串’123’ 后得到的数字:123
通过parseInt() 函数转换字符串’123abc’ 后得到的数字:123
通过parseInt() 函数转换字符串’abc123’ 后得到的数字:NaN
第六天
1、short s1 = 1; s1 = s1 + 1;有什么错?short s1 = 1; s1 += 1;有什么错?
①对于short s1 = 1; s1 = s1 + 1;由于s1+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型s1时,编译器将报告需要强制转换类型的错误。
②对于short s1 = 1; s1 += 1;由于+= 是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
2、解释servlet如何完成生命周期?
在Tomcat上运行的典型servlet生命周期如下:
·Tomcat通过它的其中一个连接器接收来自客户端的请求
·进程请求Tomcat将此请求映射为适当的
·一旦请求被定向到适当的servlet,Tomcat就会验证servlet类是否已经加载。如果不是Tomcat将servlet包装成Java字节码,这是由JVM执行的,并形成servlet的实例
·Tomcat通过调用它的init来启动servlet,它包含能够筛选Tomcat配置文件并相应地采取行动的代码,并声明它可能需要的任何资源
·一旦servlet启动,Tomcat就可以调用servlet的服务方法来进行请求
·在servlet的生命周期中,Tomcat和servlet可以通过使用侦听器类来进行协调或通信,从而跟踪各种状态变化的servlet
·删除servlet,Tomcat调用servlet销毁方法
3、下面的程序创建了一个文件输出流对象,用来向文件test.txt中输出数据,假设程序当前目录下不存在文件test.txt,编译下面的程序Test.java后,将该程序运行3次,则文件test.txt 的内容是( )。
A. ABCABC B. ABCDE C. Test D.ABCDE ABCDE ABCDE
答案:D
答案:B
第七天
1.前端中src和href的区别
(1)href是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的连接,用于超链接
(2)src是执行外部资源的位置,指向的内容会嵌入到文档中当前标签所在位置,在请求src资源时会将其指向的资源下载并应用到
文档中。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕
2. StringBuffer的实现方法,容量如何扩充。
StringBuffer是通过char[]来实现的,默认长度是16,在进行串的append时,StringBuffer会检测剩余的容量,适时会重新扩充,而扩容的同时,会创建一个新的数组,并将原来的数组内容复制到新的数组里面。
3. Statement与PreparedStatement的区别,什么是SQL注入,如何防止SQL注入(阿里巴巴面试题)
1、PreparedStatement支持动态设置参数,Statement不支持。
2、PreparedStatement可避免如类似 单引号 的编码麻烦,Statement不可以。
3、PreparedStatement支持预编译,Statement不支持。
4、在sql语句出错时PreparedStatement不易检查,而Statement则更便于查错。
5、PreparedStatement可防止Sql助于,更加安全,而Statement不行。
4. 指出下列程序运行的结果 ()
public class Example {
String str = new String("good");
char[] ch = { 'a', 'b', 'c' };
public static void main(String args[]) {
Example ex = new Example();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + " and ");
System.out.print(ex.ch);
} public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'g';
}
}
A、 good and abc
B、 good and gbc
C、 test ok and abc
D、 test ok and gbc
答案:B
解析:大家可能以为Java中String和数组都是对象所以肯定是对象引用,然后就会选D,其实这是个很大的误区:因为在java里没有引用传递,只有值传递这个值指的是实参的地址的拷贝,得到这个拷贝地址后,你可以通过它修改这个地址的内容(引用不变),因为此时这个内容的地址和原地址是同一地址,但是你不能改变这个地址本身使其重新引用其它的对象,也就是值传递。
第八天
1. Http中,get和post方法的区别
1,Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求
2,Get是获取信息,而不是修改信息,类似数据库查询功能一样,数据不会被修改
3,Get请求的参数会跟在url后进行传递,请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,%XX中的XX为该符号以16进制表示的ASCII,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
4,Get传输的数据有大小限制,因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了,不同的浏览器对URL的长度的限制是不同的。
5,GET请求的数据会被浏览器缓存起来,用户名和密码将明文出现在URL上,其他人可以查到历史浏览记录,数据不太安全。
在服务器端,用Request.QueryString来获取Get方式提交来的数据
Post请求则作为http消息的实际内容发送给web服务器,数据放置在HTML Header内提交,Post没有限制提交的数据。Post比Get安全,当数据是中文或者不敏感的数据,则用get,因为使用get,参数会显示在地址,对于敏感数据和不是中文字符的数据,则用post。
6,POST表示可能修改服务器上的资源的请求,在服务器端,用Post方式提交的数据只能用Request.Form来获取。
2. 什么是cookie?Session和cookie有什么区别?
Cookie是会话技术,将用户的信息保存到浏览器的对象.
区别:
(1)cookie数据存放在客户的浏览器上,session数据放在服务器上
(2)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session
(3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE
(4)单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。
结论:
将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中。
3. 执行如下程序,输出结果是
class Test {
private int data;
int result = 0;
public void m() {
result += 2;
data += 2;
System.out.print(result + " " + data);
}
}
class ThreadExample extends Thread {
private Test mv;
public ThreadExample(Test mv) {
this.mv = mv;
}
public void run() {
synchronized(mv){
mv.m();
}
}
}
class ThreadTest {
public static void main(String args[]) {
Test mv = new Test(); // 声明并初始化对data赋默认值
Thread t1 = new ThreadExample(mv);
Thread t2 = new ThreadExample(mv);
Thread t3 = new ThreadExample(mv);
t1.start();
t2.start();
t3.start();
}
}
A、0 22 44 6
B 、2 42 42 4
C、2 24 46 6
D、4 44 46 6
解析:C
① 使用synchronized关键字加同步锁,使三个线程依次顺序操作m() 方法
② t1.start(); 使得result=2,data=2,输出即为2 2
t2.start(); 使得result=4,data=4,输出即为4 4
t3.start(); 使得result=6,data=6,输出即为6 6
③ System.out.print(result +" "+ data);
是print()方法,不会自动换行,所以输出结果为2 24 46 6
4. 执行如下程序,输出结果是
class Base
{
void test() {
System.out.println(“Base.test()”);
}
}
public class Child extends Base {
void test() {
System.out.println(“Child.test()”);
}
static public void main(String[] a) {
Child anObj = new Child();
Base baseObj = (Base)anObj;
baseObj.test();
}
}
A Child.test()
Base.test()
B Base.test()
Child.test()
C Base.test()
D Child.test()
解答:D
测试代码相当于:Base baseObj = new Child();父类的引用指向子类的实例,子类又重写了父类的test方法,因此调用子类的test方法。