A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 陈永赛 中级黑马   /  2014-10-9 03:00  /  4641 人查看  /  20 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

10黑马币
本帖最后由 陈永赛 于 2014-10-9 03:22 编辑

问题:当我用匿名内部类调用变量 x 时,无论父类中是否有定义变量 x ,程序都能运行,而匿名内部类不也是用多态的引用创建的子类对象么?为什么会编译通过,希望高手能解答一下,感激不尽;
代码如下:
class Super
{
         //当我注释掉这行代码时,用多态父类引用创建子类匿名对象还是能调用show方法,还是能输出子类的 x 变量值?
        int x = 4;
       //当我注释方法时,编译还是会失败,这说明匿名内部类还是具备多态的特性呀?为什么成员变量就不具备多态特性呢?
        void show()
        {
        }
}
class Demo extends Super
{
        static int x = 9;
        public static void main(String[] args)
        {
                int x = 8;
                Super s = new Super()        
                {
                        int x = 6;
                        void show()
                        {
                                System.out.println(x);
                        }
                };
                //下面函数的输出层级关系是:6(匿名子类对象中的变量)--4(父类中的变量)--8(主函数中的变量)--9(类中的静态变量)
                s.show();
                //当我注释掉父类中的成员变量 x 时,编译失败;而匿名内部类还是能正常运行;
                towDemo();
        }
        public static void towDemo()
        {
                int x = 5;
                //父类引用指向子类对象时,只能调用父类中的成员,不可以调用子类中特有的成员;
                Super s1 = new Demo();
                //输出的结果为父类中的变量 x = 4;
                System.out.println(s1.x);
        }
}









最佳答案

查看完整内容

楼主的问题很好解决啊,先分析下楼主有几点不清楚的吧: 1、21行为什么输出结果是学=6;因为你新new了个Super对象s,并且在对象中定义了一个成员x,对其赋值为6,当你调用s的show方法是,show第一时间是去这个心对象s中寻找有没有x,如果有就打印,如果没有再去父类中找,看有没有继承过来,本题就是s中自己定义了x=6,所以根本没运行多态的机制,这个事局部函数作用域决定的。 2、35行为什么s1.x就是父类定义时的x=4了;因为你在t ...

20 个回复

倒序浏览
楼主的问题很好解决啊,先分析下楼主有几点不清楚的吧:
1、21行为什么输出结果是学=6;因为你新new了个Super对象s,并且在对象中定义了一个成员x,对其赋值为6,当你调用s的show方法是,show第一时间是去这个心对象s中寻找有没有x,如果有就打印,如果没有再去父类中找,看有没有继承过来,本题就是s中自己定义了x=6,所以根本没运行多态的机制,这个事局部函数作用域决定的。
2、35行为什么s1.x就是父类定义时的x=4了;因为你在toDemo这个方法中新new的s2中未重新定义s2中具有x这个变量,如上一步所说,在s2这个对象中找不到x这个变量就去其父类中找,看有没有继承过来的,所以这一步找到的就是父类中的x=4;
希望楼主可以去关注下作用域这一块的知识点
回复 使用道具 举报
LZ你好,我今天刚好也看到匿名内部类这里  是不是可以这样认为:
你的twoDemo函数中打印的是s1.x,s1是属于Super的对象,sl.x自然指向Super中的变量x。如果把Super中的x注释掉,当然找不到 也就是会报错了。
而在你的匿名对象类里的show中,打印的是x。
这个x当然会先在本类中查找,本类中有就打印。   
本类中没有,就看本类的超类中看,因为本类继承有超类中的x。
如果超类也没有,就访问外部类的成员。先是静态的成员变量,然后局部变量重新给x赋值。作为定义在局部的内部类访问所在局部中的变量x。当然x要被final修饰。      如果局部中没有给局部变量x赋值,当然就要打印静态成员变量x。
所以函数的输出层级关系是:6(匿名子类对象中的变量)--4(父类中的变量)--8(主函数中的变量)--9(类中的静态变量)


所以问题并不是成员变量不具有多态性,而是twoDemo中的“System.out.println(s1.x);”寻找的直接是的超类中的变量。而匿名内部类中,复写了show,里面的“System.out.println(x);”寻找的则不一样   

如果想更清楚看到里面的不同,可以在twoDemo中复写show,里面内容是打印x。就一目了然了。
class Fu
{
        int x = 4;
      
        void show()
        {}
}
class Zi extends Fu
{
       
        //int x=6;
        public void show()
        {
                System.out.println(x);
        }
}

class Haha
{
        public static void main(String[] args)
        {
                Fu s=new Zi();
                s.show();
        }
}
结果如果子类自定义有x则打印子类中的x,如果没有则打印父类中的x。若父类没有定义x,子类有,也可以打印出子类的x。


刚开始看视频几天,菜鸟一个,有什么不对的希望指正。大家共同进步~~
回复 使用道具 举报
楼主你好,在多态中成员变量无论编译和运行参考的都是引用型所属的类,它是不具备多态性的。
新人一个,希望能解决你的问题
回复 使用道具 举报
楼主的问题很好,我努力给你解决问题
回复 使用道具 举报
因为你的匿名内部类中有定义x,变量是静态绑定,show方法中x前面省略了this.,本类复写了则打印本类的,没有复写就是你说的那个顺序依次取。
回复 使用道具 举报
dsh 中级黑马 2014-10-10 22:30:42
7#
package com.itheima;


class Super
{
         //当我注释掉这行代码时,用多态父类引用创建子类匿名对象还是能调用show方法,还是能输出子类的 x 变量值?
        //楼主  这里还是一样,编译看的是左边,show方法调用时要访问 x  如果父类中没有 x  就会报错
        int x = 4;
      //当我注释方法时,编译还是会失败,这说明匿名内部类还是具备多态的特性呀?为什么成员变量就不具备多态特性呢?
        //注释点此方法  编译失败,是因为,下面你重写此方法的原因造成的,   关于这句没有看懂你想说什么意思      为什么成员变量就不具备多态特性呢?
        void show()
        {
        }
}
class heima extends Super
{
        static int x = 9;
        public static void main(String[] args)
        {
                int x = 8;
                Super s = new Super()        
                {
                        int x = 6;
                        void show()
                        {
                                System.out.println(x);
                        }
                };
                //下面函数的输出层级关系是:6(匿名子类对象中的变量)--4(父类中的变量)--8(主函数中的变量)--9(类中的静态变量)
                s.show();   
                //------------------------------------------------------------------------
                //这个地方是  编译看左边,也就是父类,如果父类没有show方法报错,   运行看右边  执行原则是就近原则  所以是6
                //-----------------------------------------------------------------------------
                //当我注释掉父类中的成员变量 x 时,编译失败;而匿名内部类还是能正常运行;
                towDemo();
        }
        public static void towDemo()
        {
                int x = 5;
                //父类引用指向子类对象时,只能调用父类中的成员,不可以调用子类中特有的成员;
                Super s1 = new heima();
                //输出的结果为父类中的变量 x = 4;      
                //------------------------------------------
                //这个地方你注意,当时成员变量时,编译看左边,运行也是看左边,所以他访问的是父类的成员变量
                //-----------------------------------
                System.out.println(s1.x);
        }
}
回复 使用道具 举报
楼主的问题也是蛮不错的,还在解决中。。。。。
回复 使用道具 举报
看楼主问题:你纳闷的是什么Super类中没有了x的定义这个也能运行!
void show()
{
         System.out.println(x);
  }
但是你打印输出的只是个变量!你在匿名内部类中重写了x,你如果去掉这句重写int x = 6;然后父类中仍然没有变量x的话肯定报错。如果你父类中没有定义变量x,你就相当于重新在这个匿名内部类中定义了个x,肯定程序没问题啊。
最后一句:去掉父类中的x定义后,你可以在 s.show();后面再加一句,System.out.println(s.x);肯定报错啊!因为你不只是打印x,你是引用它,父类中必须有定义才可以。
回复 使用道具 举报
楼主你好,你把两个概念弄混了,用你父类引用s来调用子类中的show()方法,然后输出子类的成员变量,肯定是这样,子类被创建对象之后(匿名对象),成员变量已经被封装到了对象里。成员都具有多态性,变量和方法,如果你用父类引用s直接调用一下父类成员变量:s.x 那么输出的肯定是父类中的4:下面举个小例子来看一下:
class TestDemo
{
        public static void main(String[] args)
        {
                //System.out.println("Hello World!");
                Person p=new Student();
                p.show();//输出的肯定是子类中被封装在对象中的成员变量
                System.out.println("age="+p.age);//输出的肯定是父类中的成员变量
        }
}
class Person
{
        int age=6;
        void show()
        {}
}
class Student extends Person
{
        int age=10;
        void show()
        {
                System.out.println("age="+age);
        }
}
回复 使用道具 举报

System.out.println("age="+this.age);前面省略了this,this,代表本类对象,p就是本类对象new Student()的引用,而age成员属性封装在对象中
回复 使用道具 举报
SenGoo 中级黑马 2014-10-21 16:25:45
12#
匿名内部类和多态不是一回事吧!
回复 使用道具 举报
您好,当你在匿名内部类中同样定义了x变量的时候,就产生了变量的隐藏。并且在你的匿名匿名内部类中覆盖了父类的show方法,那么 s对象调用的是本类中定义的x 变量。所以此时父类中有没有成员变量x 是无关紧要的。另外你可以测试一下,在父类的show方法中加上输出x的语句,子类,或是匿名内部类中声明x变量,且子类不覆盖父类void方法,那么输出的将是父类的x 的值
回复 使用道具 举报
Jeik 中级黑马 2014-11-2 14:17:13
14#
首先多态是运行期不是编译期间的概念。
Super s = new Super()        
                {
                        int x = 6;
                        void show()
                        {
                                System.out.println(x);
                        }
                };
你这里的代码相当于又创建了一个匿名的super类。通过变量s指向这个super类。
解答疑问一:
当你把原始的super类中,成员变量x注释掉 当然会报编译错误呀。就好比一个模板,它上面没有x.你要通过这个模板来创建一个新的模板,新的模板肯定是和原来一样的呀。原来的都没有,新的肯定也没有呀。
解答疑问二:你注释super()里的方法之所以会报编译失败同上理;

回复 使用道具 举报
DamonZh 来自手机 中级黑马 2014-11-15 13:10:36
15#
对于变量和静态函数不会出现多态现象 多态的前提是 继承和复写。而变量和静态函数是覆盖 而不是复写  所以当你用父类引用调用x时就是调用的父类的x 如果父类没有 就报错
回复 使用道具 举报
菜鸟路过,学习下。a
回复 使用道具 举报
匿名内部类调用外部变量时,该变量需要被final修饰
回复 使用道具 举报
本帖最后由 1103--英伦风格 于 2014-11-20 21:09 编辑

我只能这么说,在多态中,是这么个情况存在,不管是父类还是子类的成员变量还是成员方法,它们都是这样个规律------成员变量看左边,就是用多态创建的变量调用父子类中相同名称的变量时看父类;成员方法看右边,就是调用相同方法时是看子类。。。而且匿名内部类其实准确的说,它是一个类的对象,而不是一个类。
回复 使用道具 举报
itDave 中级黑马 2014-11-21 03:44:40
19#
继承:继承域和方法。子类中可以覆盖,增加域和方法,但是一定不能删除域和方法。你的意思,我明白。你这样想:如果你注释掉了父类的域,你的子类可以重写一个同样的域,但性质已经变了。所以,一旦你注释了父类的x域,那么子类的x域只是子类自己用的,和父类没关系。你的匿名类的方法我感觉就相当于重载了父类方法(父类x域没了)。总之记住:子类不能删除父类任何东西,可以重写,但方法签名必须一致。
回复 使用道具 举报
内部类的访问规则:1,可以访问外部类中的成员,包括私有成员原因是该内部类中持有一个外部类的引用,格式outer.this.x,2,外部类访问内部必须建立内部类对象。3,内部类可以私有。外部类不能私有。System.out.println(outer.this.x);
当内部类定义在外部类的成员位置,而且非私有,可以在外部其他类。可以直接建立内部类对象。格式out.inner  in=new out().new inner();2,当内部类定义在外部类的成员位置就可以成员修饰符修饰比如私有perivate将内部类进行封装,static当内部类被被静态修饰后,只能直接访问外部类中的静态成员。访问局限。没有对象且非静态不能运行。
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马