在其他学习网站看到的,自己又整理了一下。(陆续更新)
6.说出ArrayList,Vector, LinkedList的存储性能和特性
先说ArrayList和Vector
两者都继承了抽象类AbstractList,但是Vector是线程安全的,而ArrayList是非线程安全的
再说ArrayList和LinkedList的区别
ArrayList 是数组结构,所以定位很快,但是插入和删除很慢
LinkedList 是双向链表结构,所以插入和删除很快,但是定位很慢
7.Collection 和 Collections的区别
Collection 和 Collections的区别。顶折纠问
首先不要说成了一个是单数,一个是复数。。。
Collection是接口,是List和Set的父接口
Collections是工具类,提供了排序,混淆等等很多实用方法
9.HashMap和Hashtable的区别
HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
区别1:
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是线程安全的类
Hashtable是线程安全的类
13.abstract class和interface有什么区别?
abstract class 抽象类和interface接口的区别
使用方式:
抽象类只能够通过继承被使用
接口必须通过实现被使用
实现方法:
抽象类不仅可以提供抽象方法,也可以提供实现方法
接口只能提供抽象方法,不能提供实现方法。 但是在JAVA8版本开始,接口可以提供实现方法了,前提是要在方法前加一个default修饰符
23.数组有没有length()这个方法? String有没有length()这个方法?
数组获取长度的手段是 .length 属性
String获取长度的手段是 length()方法
集合获取长度的手段是 size()方法
文件获取长度的手段是 length()方法
24.Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?
以HashSet为例,判断重复的逻辑是:
- 首先看hashcode是否相同,如果不同,就是不重复的
- 如果hashcode一样,再比较equals,如果不同,就是不重复的,否则就是重复的。
更多关于hashcode的原理,参考 Java HashCode原理详解
25.构造器Constructor是否可被override?是否可以继承String类?
子类不能继承父类的构造方法,所以就不存在重写父类的构造方法。
注: super() 表示子类调用父类的构造方法,这不能被叫做继承父类的构造方法
String是final修饰的,所以不能够被继承
27.try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
try(){…}运行至return语句处,将将要返回的结果暂存起来;
然后转到finally{…}语句中运行;
运行完该部分code之后再将之前return处暂存的结果返回。
public class Test {
public static void main(String[] args) {
int num = printNum();
System.out.println("最后返回的数值是: "+num);
}
public static int printNum() {
int i = 1;
try {
System.out.println("try语块中i= "+i);
return i;
} catch(Exception e) {
e.printStackTrace();
} finally {
i++;
System.out.println("finally语块中i= "+i);
}
return i;
}
}
输出结果为:
try语块中i= 1
finally语块中i= 2
最后返回的数值是: 1
但如果把try{}中的return语句注释掉的话:
public class Test {
public static void main(String[] args) {
int num = printNum();
System.out.println("最后返回的数值是: "+num);
}
public static int printNum() {
int i = 1;
try {
System.out.println("try语块中i= "+i);
//return i;
} catch(Exception e) {
e.printStackTrace();
} finally {
i++;
System.out.println("finally语块中i= "+i);
}
return i;
}
}
输出结果就是:
try语块中i= 1
finally语块中i= 2
最后返回的数值是: 2
28.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
因为hashCode()方法和equals()方法都可以通过自定义类重写,是可以做到equals相同,但是hashCode不同的
但是,在Object类的equals()方法中有这么一段话:
Note that it is generally necessary to override the hashCode method whenever this method is overridden,
so as to maintain the general contract for the hashCode method,
which states that equal objects must have equal hash codes.
翻译如下:
通常来讲,在重写这个方法的时候,也需要对hashCode方法进行重写,
以此来保证这两个方法的一致性——
当equals返回true的时候,这两个对象一定有相同的hashcode.
至于两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
答案应该是否定的,但是得搞清楚里面的原委。
46.sleep() 和 wait() 有什么区别?
首先sleep和wait之间没有任何关系
sleep 是Thread类的方法,指的是当前线程暂停。
wait 是Object类的方法, 指的占用当前对象的线程临时释放对当前对象的占用,以使得其他线程有机会占用当前对象。 所以调用wait方法一定是在synchronized 中进行。
49.Class.forName的作用?为什么要用?
Class.forName常见的场景是在数据库驱动初始化的时候调用。
Class.forName本身的意义是加载类到JVM中。 一旦一个类被加载到JVM中,它的静态属性就会被初始化,在初始化的过程中就会执行相关代码,从而达到"加载驱动的效果"。
50.final修饰变量时,不能修改的是变量的引用,还是变量引用的值?
final的作用
- 被final修饰的类不可以被继承 (注意 final类中的所有成员方法都会被隐式地指定为final方法。)
- 被final修饰的方法不可以被重写: 如果你想明确禁止 该方法在子类中被覆盖,可将方法设置为final。但是!同时注意 如果父类的 final修饰的方法设置为private,则子类可以写一个同名的方法,此时 ,该同名的方法不再产生final的报错,而是在子类重新定义了一个方法(注:类的private方法会隐式地被指定为final方法。)
- 被final修饰的变量不可变:被final修饰的变量其实就相当于定义了一个常量,无法被修改的变量,如果final修饰的是一个基本数据类型的变量,那么这个变量的值就定了,不能变了,而如果修饰的是一个引用变量,那么该变量存的是一个内存地址,该地址就不能变了,但是该内存地址所指向的那个对象还是可以变的。
被final修饰的变量,不可变的是变量的引用,而不是变量的内容
当然,final还有其他作用,比如:
被final修饰的常量,在编译阶段会存入调用类的常量池中
参考
51.final 和 static
final
1.final修饰类
用final修饰类,表示这个类不能被继承
2.final修饰方法
使用final方法的原因有两个,第一个原因是把方法锁定,以防任何继承类修改它的含义;
第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。
《Java编程思想》
即父类的final方法是不可以被子类继承重写的。
如果父类中的final方法是public修饰的,子类可以继承到此方法,子类会重写此方法,将会导致编译出错
如果父类中的final方法是private修饰的,子类继承不到此方法,这时子类可以定义一个和父类中的final方法相同的方法,因为这个方法是属于子类重新定义的,所以编译不会出错。
3.final修饰变量
final成员变量表示常量,一但被赋值,值不可以再被改变
当final修饰一个基本数据类型时,该基本数据类型的值在初始化之后便不能再改变。
当final修饰一个引用类型时,在初始化之后不能再让其指向其他对象,但是对象的内容是可以改变的。
static
static关键字作用:在没有创建对象的情况下来调用方法/变量
static修饰的方法或变量不需要依赖对象进行访问,只要类被加载了就可以
1.static修饰的方法,即类.方法。
2.static变量
即静态变量,静态变量可以被所有对象共享。
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
static成员变量的初始化顺序按照定义的顺序进行初始化。static不可以修饰局部变量;
所以一般在需要实现以下两个功能时使用静态变量:
• 在对象之间共享值时
• 方便访问变量时
3.static代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。下面看个例子:
class Person{
private Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
Date startDate = Date.valueOf("1946");
Date endDate = Date.valueOf("1964");
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf("1946");
endDate = Date.valueOf("1964");
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。