为了考SCJP自己研究了一下,觉得有点收获,给大家分享。
    
重载解析 (overloading resolution)是一个伴随重载过程获得正确方法签名的分析过程。深入理解这个过程,有助于理解继承、多态、重载、动态绑定的概念,让知识系统
化。在泛型方法中,桥方法的生成的理解依赖于重载解析概念。在学习重载解析之前,先明确几个概念。1:方法签名    
要完整地描述一个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。返回类型不是方法签名的一部分。也就是说,不能有两个名字相同、参数类型也相同却返回不同类型值的方法。
    
下面的两个方法具有不同的方法签名:           void getX(){...}
void getX(String){...}
它们的方法签名分别标识为getX()和getX(String)。下面这两个方法是不可能同时存在的,因为方法签名相同是不允许的,它们的方法签名都是X(),编译器认为它们是重复的方法:        //不能有方法名和参数名相同而返回类型不同的方法
String X(){...}
Date X(){...}
下面这两个方法同样也不能同时存在,编译器认为它们是重复的方法,理由相同:          //也不能有方法名和参数名相同,返回类型也相同,但访问修饰符不同的方法
 public String X(){...}
 private String X(){...}
方法签名的实质的具体描述是:一个类中只能有一个类似于X(){...}这样的方法,但可以有X(){...},X(String){...},X(Date){...}这样的方法同时存在。一旦有一个类似X()的方法被定义,就不能再定义这样的方法,尽管再定义的方法的返回类型或访问修饰符不一样也不行。方法名以及参数类型都相同的方法不允许出现两次。2:可协变的返回类型假如有如下两个类:class Person{
private Person father;
public Person getFather(){

return father;
}
}
class European extends Person{
private European daddy;
public European getFather(){
return daddy;
}
}
Person是European的父类,这两个类中都有一个getFather方法。如果严格按照继承法则,European类中应该存在一个继承自父类的方法Person getFather()方法,但又存在一个European getFather()方法,这违背了方法签名唯一的原则。在Java SE 5.0之后,如果子类的某个方法和父类的方法具有相同签名,而且返回类型是父类返回了类型的子类,虚拟机认为这是重写父类的方法,它们具有可协变的返回类型,这样就不存在方法签名冲突问题的问题了。从返回类型的继承层次看,我们可以认为European是一个Person(is-a关系),符合多态的概念,这样便于理解。                   Person p=new European();

//虽然p.getFather()返回一个European,但可以赋值给Person,
//因为European和Person之间的关系是is-a关系,
//所以可以认为European中的European getFather(){...}方法看成
//Person getFather(){...},所以可以认为European中的getFather方法
//重写了Person中的getFather方法,这种情况下,
//我们把Person和European中的getFather方法的返回类型叫做可协变的返回类型。

Person father=p.getFather();
    
    既然有可协变的返回类型,那么有没有可协变的方法参数呢?比如:Person类中的setFather方法:void setFather(Person father){this.father=father;}假设我们想在European类中这样重写父类的setFather方法:void setFather(European daddy){this.daddy=daddy;}    结果是失败的,European中存在两个方法名相同的不同签名的方法 setFather(European)和setFather(Person),证明可协变方法参数的想法纯属臆想。3:多态与动态绑定    Java程序设计语言中,对象变量是多态的。一个Person变量既可以引用一个Person类对象,也可以引用一个Person类的任何一个子类的对象(例如,European 、Asian等等)。例如Person p= new European()就是让父类变量引用子类对象,是一个对象变量具有多态特性的例子。    多态特性带来了引用的方便,但由此带来了执行方法上的复杂问题。比如上例中p.getFather到底执行哪个类中的方法的问题。我们根据学到的一知半解的知识可能知道getFather会执行European方法中的getFather方法,但具体到编译器的操作程,就需要了解动态绑定的过程。4:动态绑定与重载解析    如果方法是private、static、final方法或者构造器,那么编译器将可以准确地知道应该调用哪一个方法,我们将这种调用方式称为静态绑定(static binding)。与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定。在我们列举的实例中,编译器采用动态绑定的方式生成一条调用getFather()指令。    编译器首先在对象p的实际类型European方法中查找具有相同方法签名的方法,如果找到,就调用本类的方法。如果在本类中没有找到这个方法,就会寻找父类中的方法签名,找到了就调用父类的这个方法。如果在父类中没有找到方法,继续寻找父类的父类,知道找到为止(当然,如果找到Object类还没找到,编译器就会报错了)。    上面就是动态绑定的过程。实际上,到这一步,重载解析的概念已经很明显了。重载解析就是在动态绑定过程中,如何找到正确方法的解析过程,实际上,这个解析过程是用方法签名作为关键名词解析的。5:方法表    每次调用方法都要进行搜索,开销相当大。因此,虚拟机预先为每个类创建了一个方法表(method table),其中列出了所有方法的签名和实际调用的方法。这样一来,在真正调用方法的时候,虚拟机仅查找这个表就行了。在前面的例子中,虚拟机搜索European类的方法表,以便寻找与调用getFather()相匹配的方法。这个既有可能是European.getFather(),也有可能是Person.getFather()。这里需要提醒一点,如果调用super.getFather(),编译器将对隐式参数超类的方法表进行搜索。    某个类实例变量可以调用哪些方法,在Eclipse中,我们如果设置了content Assistant,可以在输入变量名以后看到一竖列包含方法和公有域(基本上,只有public的才能看到)的列表,这可以看做是Eclipse通过某种方式获得了这个类变量所属类的方法表(当然还有“域表”,为什么打引号?因为我不知道是不是真的存在“域表”这个东东)。6:理解泛型方法中编译器生成的桥方法    理解了基本概念,在学习新知识的时候就不会有概念上了模糊认识,就可以顺利的掌握新的知识点。    桥方法(bridge method)是泛型方法被编译器翻译为原型方法后,原型方法和重载冲突,为解决这个问题而生成的方法。   我们忘掉之前European和Person的例子,这里重写这两个类为泛型类。  
class Person<T> {
private T father;
public T getFather(){

return  father;
}
public void setFather(T father) {
System.out.println("set Person's father");
this.father = father;
}

}
class European extends Person<String>{
private String daddy;

public String getFather(){
return daddy;
} public void setFather(String daddy) {
System.out.println("set European's father");
this.daddy = daddy;
}

}    
   新定义的类Person为泛型类,European类为实例化Person类型参数T为String的类的子类(有点拗口)。在子类European中,我们重写了父类的方法getFather和setFather(T),因为T在European中被实例化(不知道这里叫做实例化是不是准确)为String,所以European类中重写的方法的返回类型和参数如果对应父类中的T都被改写为String。    这样的写法符合Java语法吗?先看看父类Person中的方法getFather,它在擦除参数(不知道擦除参数神马意思?那先去研究下泛型的基础吧。)以后变为:public Object getFather(){...}    按照可协变返回类型的定义,子类的重写方法String getFather()符合这一定义,属于重写父类方法。    再看看另外一个Person类的方法setFather,在擦除参数以后变成了:public void setFather(String daddy){...}    方法签名是 setFather(String),和父类中的方法签名setFather(Object)是不一样的。之前说过,没有可协变的参数类型,于是,European类中存在两个参数不一样的setFather方法。    我们在编写European类的时候,是按照把Person类的类型参数T实例化为String的思路写的。我们希望在运用多态时调用的方法可以准确的重载到正确的方法,我们希望调用European对象的setFather方法时能执行自己重写的这个setFather方法。实际写一段测试代码看看European对象执行setfather方法后的执行结果。
         Person<String> p=new European();
p.setFather(" father of European Object ");
    编译器执行了上述代码,打印出"set European's father",说明执行了European中的setFather方法。    既然代码没有错,那么就是我们的设想错了,说明European中不存在两个setFather方法。这个和我们学习到的知识是冲突的。不要怀疑自己把握错了知识要点,这里,编译器用了一个叫“桥方法”的方法解决了泛型原型代码和重载冲突的问题。我们在European中编写的setFather是这样的:
             public void setFather(String daddy) {
System.out.println("set European's father");
this.daddy = daddy;
}
    而编译器翻译这段代码的时候,悄悄地把这段代码改为了如下方法:         public void setFather(Object daddy){
System.out.println("set European's father");
this.daddy = (String)daddy;
}
    这个编译器悄悄改写的方法就叫桥方法。我们书写方法的时候,传入的参数是String类型的,编译器为了让这个方法符合重写父类方法的语法规则,把参数转换为了Object,这就保证了European中的setFather方法是重写父类的setFather方法(方法名和参数都相同)。在这个方法中,我们自己编写的代码是把daddy当成一个String用的,而编译器的桥方法却传入的是个Object,所以当我们要使用参数daddy时,编译器又悄悄地把daddy强制转换为String。