一个final引发的的血案(java基础系列)

来源:互联网 发布:火影忍者手游网络异常 编辑:程序博客网 时间:2024/05/17 03:21

        从两次面试说起,一年前,我五年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还没有完,它跟不可变类有密切的关系,这话题就到不可变类了。

先到这里,每篇不宜过长




        

         

0 0
原创粉丝点击