求大佬详细告知此题为什么是3

 public class Foo
{
    public int a;
    public Foo()
    {
        a = 3;
    }

    public void adddFive()
    {
        a = a+5; 
    }

}

class Bar extends Foo
{
    public int a;
    public Bar()
    {
        a = 8;
    }

    public void adddFive()
    {
        this.a+=5; 
    }

    class TestFoo
{
    public static void main(String[] args)
    {
        Foo foo = new Bar();
        foo.adddFive();
        System.out.println(foo.a);

    }
}
}

再说详细一点吧。
Foo foo = new Bar();
System.out.println(foo.a);
为什么foo.a不是bar的那个a,因为编译器在编译System.out.println(foo.a);的时候不能假设foo是Foo的哪个派生类,虽然你这里写了Foo foo = new Bar();
看如下代码:
Foo foo = new Bar();
foo = getfoo(); //假设getfoo可以返回Foo或者Foo的另一个派生类,比如class Bar1 : extends Foo {} ,返回new Bar1,此时bar1和bar类型不兼容
System.out.println(foo.a); //因此foo.a不能假设是bar.a,因为foo不能假设是bar类型,还可能是foo类型,还可能是bar1类型

Foo foo = new Bar();执行的是bar的构造函数,然后还会调用基类的构造函数。
foo.adddFive();执行的是Bar里面的adddFive(),并且不会调用基类的adddFive()
但是以上两个函数修改的都是派生类的public int a;
而foo.a访问的是基类的a,在Foo foo = new Bar();的时候,它被设置为3,之后没有修改,所以输出3

如果把Bar里面的public int a;删除,那么结果是13

顺便说下,当有两个变量同名,java的原则是最近匹配。
你的代码中
a = 8;
此时本类有一个a
基类有一个a,那么访问的就是本类的a

再比如:
public int a;
void foo()
{
int a;
a = 123; //那么此时访问的就是foo里面定义的a,而不是作为成员变量的a(当然更不是基类的a)
}

foo.a的意思是调用foo方法里面的a的值 所以这个打印出来的是构造函数里面的a 和其他方法没有关系。

对这个地方也有点迷糊,对JAVA也不太懂,
猜测,foo的a和bar的a,程序认为不是一个a,继承后没有关键字表示a是被重写了,所以程序认为是两个不一样的a

public class TestFoo {
    public static void main(String[] args) {
        Foo foo = new Bar();//执行结果b =3;a =8;
        /**
         * 解释:new Bar()调用Bar的构造方法,
         *      Bar继承于Foo,所以首先调用父类的构造方法再执行子类本身的构造方法。
         *      调用Foo的构造方法初始化了b=3,然后调用Bar的构造方法初始化了a=8
         */
        foo.adddFive();//foo是子类Bar 的实例;子类实例调用子类的adddFive()方法,a = a+5 = 8+5 =13;不触发父类的方法。此时a 为13,b 仍然是3.
        System.out.println(foo.b);//这里将变量a,换成b,还是同一个变量是吧。所以你再看看

    }
}

class Foo {
    public int b;

    public Foo() {
        b = 3;
    }

    public void adddFive() {
        b = b + 5;
    }

}

class Bar extends Foo {
    public int a;

    public Bar() {
        a = 8;
    }

    public void adddFive() {
        this.a += 5;
    }

}

this.a+=5;等同与super.a+=5;而Java是通过拷贝传递值的,并不能改变Foo类中a的值

访问方法和访问变量是两种不同的情况,当访问的是方法时,是根据变量的实际类型决定的,所以foo.adddFive()调用的是之类方法,而访问属性时是根据引用类型决定的,所以foo.a只的是父类的a.
举个列子 假如子类有个void addddFive()方法,而父类没有这个方法,那么父类的引用是无法调用的foo.addddFive()就会出错。而bar中的a不会覆盖foo中的a,所以在foo.a时是无法访问到子类的a的,除非你将引用类型改成子类的类型才能访问子类的属性。以上是本人的一些理解,希望对你能够有些帮助。

父类引用子类对象,
Foo foo = new Bar();
foo.adddFive();//调用的是Bar对象中的addFive()方法,该方法中this.a是Bar对象中的,值为8,Bar对象的属性a经过方法调用后就为13
System.out.println(foo.a);//调用的是Foo对象中的属性a,值就为3

如果想输出Bar对象中计算过后的属性a值,可以这样:
System.out.println(((Bar)foo).a);//输出13