从两次面试说起,一年前,我五年java工作经验,被一个张总面试。我描述了之前所做的工作内容。张总直接点出:我们现在招的是高级工程师,应该具备一定的架构能力。你所描述的工作内容看不出有架构方面的东西。虽然张总不是做技术的,但是指出的问题还是很准。工作多年,却没有本质上的提升。
前几天,我六年工作经验,被一个架构师面试。(这两年并没有换工作)他是这样问我的:
你最擅长哪方面,因为java ee 范围很大,你最擅长哪些,我就问哪些。这样我来判断你的级数。
我说,java基础和数据库吧。
问题:
1final都用在哪些场景?有没有见过方法的参数用final修饰,解释原因
2有没有用过内部类?
3解释线程安全
4类加载器的了解
5static 的用处
6不可变类
我基本上被秒杀了,工作六年,但是这些内容了解的非常少。这才发现原来技术细节,基础也没有学好。我把以后学习的过程记录下来,一方面自己回顾,一方面希望对他人有所帮助。
未来学习方向上将是两个维度:1 架构方面的学习 2 基础知识重新学习。
接下来先回答上面的问题。
final
final修饰class表示class不可以被继承,没有子类。
final修饰变量,表示变量赋值后,指向的这个对象的指向不能变了。只能是这个对象了。但是这个对象是可以变的。比如下面的例子:
import java.util.ArrayList;
import java.util.List;
public class Test {
private List list = new ArrayList();
private final List s = list;
public static void main(String[] args){
Test t= new Test();
System.out.println(t.s.size());
t.s.add("hello");
System.out.println(t.s.size());
System.out.println(t.s.get(0));
}
}
final修饰方法的参数。简单的来说是方法的形参如果要被内部类访问,就需要被fianl修饰。重点是why?
首先要熟悉内部类,平时的工作中内部类本来就没有用过,就是学j2se基础的时候学过,有点印象而已。如果不知道内部类,这个问题是不可能回答出来的。
现在用一个例子来解释一个外部类包含了一个匿名内部类,还有一个接口:
public class Outer {
public static void main(String[] args){
Outer outer = new Outer();
System.out.print(outer.getInner("hello", "city").getName());
}
public Inner getInner(final String name,String city){
return new Inner(){
public String getName(){
return name;
}
};
}
}
interface Inner {
String getName();
}
编译后的class我反编译后代码如下
一共三个class
1
abstract interface Inner
{
public abstract String getName();
}
2
import java.io.PrintStream;
public class Outer
{
public static void main(String[] args)
{
Outer outer = new Outer();
System.out.print(outer.getInner("hello", "city").getName());
}
public Inner getInner(String name, String city)
{
return new Inner(this, name) {
public String getName() {
return this.val$name;
}
};
}
}
3
class 1
implements Inner
{
public String getName()
{
return this.val$name;
}
}
可以看出来内部类在返回name值的时候没有直接返回name,而是返回了一个this.val$name;这是怎么回事?
解释是内部类使用的是自己的一个属性,这个属性值是将传进来的参数通过构造器赋值的。所以这时候使用的这个参数看起来是name,其实是name的拷贝(这里用“拷贝”其实并不准确,因为这个拷贝和name其实指向了同一个对象,准确的说法应该是指向的传递。如果这里的拷贝是完全拷贝了一个新的对象,那么使用final也没有任何意义)。假如我们在内部类里修改了name的指向,让它指向另外一个对象。正常的情况应该是name被修改了。但是拷贝没有被修改,所以用起来会发现name还是以前的值。从程序员的角度看同一个name值不统一了。为了避免这种情况使用final修饰。这样参数指定的对象不能换了。值就统一了。前面说了指向不能改了,但是指向对象的这个对象本身是可以改的,就算这个对象本身改了,因为那个拷贝指向的还是这个对象本身。所以值还是统一的。下面的例子来证明这一点:
import java.util.ArrayList;
import java.util.List;
public class Outer {
public static void main(String[] args){
Outer outer = new Outer();
List list = new ArrayList();
System.out.print(outer.getInner(list, "city").getList().get(0));
}
public Inner getInner(final List list,String city){
return new Inner(){
public List getList(){
list.add("22");
return list;
}
};
}
}
interface Inner {
public List getList();
}
打印结果是字符串:22
面试的时候没有答上来,如果答上来,肯定又会进一步问内部类相关的东西,或者怎么编译的,就像抓住一个根绳子,扯出无数的问题。其实关于final还没有完,它跟不可变类有密切的关系,这话题就到不可变类了。
先到这里,每篇不宜过长