• GLADIATOR
    2019-10-23
    变色壳应该是忘上撸不是往下撸吧,因为继承自phone

    作者回复:
    往根节点撸,这样说比较没有歧义。

    
     1
  • 梁大瓜
    2019-07-07
    老师我这样理解不知道对不对:声明引用实际上就是在堆中建立里一块引用类的内存地址指向,这个引用具体指向的对象可以是他的子类,但是只能在这个内存区域中放入子类覆盖了与父类相同方法的值。所以在调用的时候,返回的值是由实际的子类对象的值,只不过这个值的类型是子类的类型,在重载的时候,标签对应的是这个值的类型。

    作者回复: 声明引用实际上就是在“内存”(可以是堆,比如是一个成员变量,也可以是线程栈,比如说说一个局部变量或者参数)中建立里一块(32bit或者64bit大小)引用“对象”的内存地址指向,这个引用具体指向的对象可以是他的子类,但是只能在这个内存区域(32bit或者64bit大小,和对象类型以及大小没关系,只是一个地址)中放入“子类或者本类的对象的地址”。所以在调用(调用什么?方法吗?)的时候,(后面感觉有点模糊,你可以再说的清楚一点)返回的值是由实际的子类对象的值,只不过这个值的类型是子类的类型,在重载的时候,标签对应的是这个值的类型。


    其实覆盖不复杂,核心就是:寻找调用哪个方法。这里有两个角色:1)引用的类型,调用的方法签名必须是这个类型中定义了的;2)引用实际指向的对象,它决定的是通过这个签名调用的实际是哪个类的方法。

    结合super,this,重载,问题会变得复杂,但是万变不离其宗,也就是上面的亮点。

    -------- 以下内容涉及堆和栈,属于超纲 --------
    至于底层的逻辑,你的描述中有一个可能的错误,就是认为引用是在堆里建立一块内存。其实引用就是在内存里建立一个引用。也就是我们说的对象的“名”。

    这里说的内存,可能是栈上的,比如下面的代码:
    public void test(){
        Person person = new Person();
    }
    person是个局部变量,那就是在栈内存上。

    Person类的定义如果如下的话:

    public class Person{
        private Company company = null;
    }

    那么company这个引用就是在堆上。因为整个Person对象都在在堆上分配的内存,所有对象都是在堆上分配的内存。只有执行方法的时候,需要的局部变量和参数,才是在栈上分配内存。

    
     1
  • 就是故意丶
    2019-10-25
    老师,我看了你回复的评论里,有关堆和栈的知识,也就是说,“Java中所有引用都是在栈上”这句话是错的,“Java中所有非静态成员变量的引用都是在堆上”是对的,“Java中所有用new捣鼓出来的对象实例都是在堆上”这句话是对的,是这样吗。

    作者回复:
    new出来的对象(无论在哪里new的)都是在堆上的。对象里的成员变量也都是在堆上的。

    方法里的数据都是在栈上的

    
    
  • 就是故意丶
    2019-10-25
    老师~ 我看到这自己去试了一下,如果是单个有继承关系的多个重载方法,确实是按照继承链上从近到远的找,但是如果是有多个有继承关系的重载方法,找到具体执行的方法的规则貌似是按照总距离,而不是优先计算第一个参数的距离,不考虑后面的参数的~
        public static void main(String[] args) {
            C cc = new C();
            C c = null;
            D d = null;
            E e = null;
            F f = null;
            cc.overload(c,d);
        }
        public void overload(D d, D dd) {
            System.out.println("dd");
        }

        public void overload(C c, F f) {
            System.out.println("cf");
        }
    比如这个 c d e f四个类,c继承d,d继承e,e继承f,我传参c,d,那dd那个方法 就是第一个参数c 到 d距离是1,d到d距离0总距离1,cf那个方法,就是c到c是0,d到f是2,总距离2,所以直接找的是dd的方法执行的,我如果把cf的方法改成ce,就会报错,因为大家都是1所以不知道找哪个了,是这样吗?
    展开

    作者回复:
    继承链+方法重载的情况,参数匹配确实比较麻烦。当我们在设计程序的时候,如果发现需要涉及到这方面的问题,首先要想的是避免,而不是如何正确的使用。没错,要避免出这种麻烦的,饶脑子的(代码不易读)的情况。

    实际上大多数的设计的好的类库也会避免这种情况出现。这部分知识我在课程中也没有深入讲述,也正是出于这两点1)确实有点绕 2)确实不大用得到。也就是说,学习的投入产出比太低。尤其是对于初学者,还容易绕着绕着绕迷糊了。

    到底应该调用哪个方法,这个问题到底有多麻烦呢,Java Language Specification上有详尽的描述 (15.12.2.5. Choosing the Most Specific Method)
    https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.12.2.5

    当然这里还包括了覆盖和重载等内容。就你当前这个问题来说,我试下来和你的结果不大一样。如下代码(在包tta里)就已经报错了,错误内容是“Error:(16, 12) java: reference to overload is ambiguous
      both method overload(tta.D,tta.D) in tta.AppMain and method overload(tta.C,tta.F) in tta.AppMain match”

    错误内容和你理解的一样,就是ambiguous method call,Java无法帮我们选择一个唯一的“最应该”调用的方法。

    public class AppMain {

      public static void main(String[] args) {

        AppMain appMain = new AppMain();

        C c = null;
        D d = null;
        E e = null;
        F f = null;
        appMain.overload(c,d);
      }
      public void overload(D d, D dd) {
        System.out.println("dd");
      }

      public void overload(C c, F f) {
        System.out.println("cf");
      }

    }

    
    
  • 执笔,封心
    2019-07-19
    我还以为有重写和重载的具体哪些区别。讲的有点懵懵的

    作者回复: override(覆盖)和overload(重载)本身就是两个东西。

    override和继承有关,子类如果有签名相同的方法,会覆盖父类中的方法。overload是同一个类中的方法可以有不同的参数。

    这两个概念不难,难在实际代码中的应用。

    
    
我们在线,来聊聊吧