You may not be aware of this and super.

1. to reproduce the problem

When watching "java concurrent programming combat", when speaking reentrant lock, subclass rewrite synchronized method of the parent class, and then call the synchronized methods in the parent class, if the built-in lock is not re-entrant would lead to a deadlock.

public class Widget{
    public synchronized void doSomething(){
        ···
    }
}
public class LoggingWidget extends Widget{
    public synchronized void doSomething(){
        ···
    }
}
复制代码

We know synchronized modification instance method, the object is to lock this object. Subclass should be synchronized subclass object is locked, synchronized parent class should be locked in the parent class object. Two fundamentally different methods lock object, it is no need to re-enter the lock. Why this need to say a reentrant lock?
1. The book was wrong
2. In fact, the lock object and subclasses of the parent class for the same, then in the end is a subclass of object or parent object?

2. Verify

Since the modification synchronized instance method, the object is to lock the current instance of the object, we are printing about this subject in the parent class and subclass, look at what they actually is.

public class Father{
    public synchronized void test(){
        System.out.println("father'this="+this);
        System.out.println("father'super"+super.toString());
    }
}
public class Son extends Father{
    @override
    public synchronized void test(){
        System.out.println("son's this="+this);
        System.out.println("son's super="+super.toString());
        super.test();
    }
}
public static void main(String[] args){
    Son son = new Son();
    son.test();
}
//结果
son's this=Son@39b43cbc
son's super=Son@39b43cbc
father's this=Son@39b43cbc
father's super=Son@39b43cbc
复制代码

We can see that when you call the parent class method sub-class, subclass the parent class this is a reference point to the same subclass and then lock object for the same parent class and subclass objects. We use an example to test,

//改进一下代码
public class Father{
    public synchronized void test(){
        System.out.println("father test");
    }
    public synchronized void test2(){
        System.out.println("father test2");
        while(true);
    }
}
public class Son extends Father{
    @override
    public synchronized void test(){
        System.out.println("son test");
    }
    @override
    public  void test2(){
        super.test2();
    }
}
 public static void main(String[] args) {
        Son son = new Son();
        Thread thread1= new Thread(()->{
            son.test2();
        });
        Thread thread2 = new Thread(()->{
            son.test();
        });
        thread1.start();
        try {
            Thread.sleep(1000);//这里可能休眠的时线程1,但是不重要,只要线程1能先启动,获得锁就好
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.start();
    }
    //结果
    son test2
    father test2
    //因为thread1中son通过没有被synchronized修饰的test2()调用父类被synchronized修饰的test2()方法
    ,如果父类synchronized获取的锁不是和子类不是同一个,那么,thread2通过son调用被synchronized修饰
        的test()方法,必然能够进入该方法,因为锁对象不是同一个,然而根据验证结果,锁对象为同一个,并且为子类对象。
复制代码

3.this and super

In the top of the experiment, we see this and super point to the same reference. We generally understood that this refers to an object that the present example, super class instance is a reference to the parent object. But why this and super point to the same reference?

//对于this,jls中这样描述
When used as a primary expression, the keyword this denotes a value that is a reference to the object 
for which the instance method or default method was invoked (§15.12), or to the object being constructed.
The value denoted by this in a lambda body is the same as the value denoted by this in the surrounding context.
//对于super的一些描述
The form super.Identifier refers to the field named Identifier of the current object, but with the current
object viewed as an instance of the superclass of the current class.
复制代码

As can be seen, this represents a reference point to call the current object instance methods, and explain the super top is not obvious, we look at one other explanation

The usage of the super reference when applied to overridden methods of a superclass is special; 
it tells the method resolution system to stop the dynamic method search at the superclass, 
instead of at the most derived class (as it otherwise does).
复制代码

That has to stop super dynamic invocation process. And that is why this has been the key, as well as the super keyword, and super, and this points to the same reference. By way of example look

public class Son extends Father{
    public void test(){
        this.test2();
        super.test2();
    }
}
public class Father{
    public void test(){
        
    }
    public void test2(){
        System.out.println("father test2");
    }
}
main()方法:
Son son = new Son();
son.test2();
//结果
father test2
father test2
//字节码
 public void test();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokevirtual #2                  // Method test2:()V
         4: aload_0
         5: invokespecial #3                  // Method Father.test2:()V
         8: return
      LineNumberTable:
        line 4: 0
        line 5: 4
        line 6: 8
}

复制代码

We can see through this, super can call the method or field in the parent class
because the object contains its inherited instance data in the instance data stored in the heap, the sub-class object holds information about the parent class, before understanding of the super "point to the parent class object reference" is wrong, there is simply no parent objects, so-called parent class object, in fact, is a subclass inherits the instance data over the data. That is only one object in the heap, and no parent object.

So super and this can only point to an object that is a subclass of the object (in fact, it should be a pointer to indicate the current instance of the object that calls the method of reference).
Well, since the sub-class has a parent class instance data, this can be called directly, so why do super and super and this point is the same object?
Careful observation will find top of the byte code,

this.test2()->invokevirtual
super.test2()->invokespecial
复制代码

this is a dynamic invocation, supers is at compile time which method has been invoked to know.
So the purpose of this, super is this: when there is a method to prevent calls to rewrite confusion, this keyword method call to go through a process of dynamic analysis, and variable or method call is to determine the super keyword, which is inherited instance data the parent class member variable or member method

Interpretation parent class and subclass of this same method

Learn jvm knows method first parameter is actually this, we call the parent class method by subclasses, this is actually a pass in this subclass

//jvms中的解释
Note that methods called using the invokespecial instruction always pass this to the invoked method as its first argument. As usual, it is received in local variable 0.

复制代码
//伪代码
public class Father{
    public void test(){
    }
}
public Class Son extends Father{
    public void test(){
    //实际上test参数中的第一个为this,jvm自动帮我们加入的(我这里显式的写上),所以在父类test方法中获取的是同一个this
     super.test(this);   
    }
}
复制代码

So the question is, and this is very similar to super, then jvm whether the method's parameter list is also automatically add a super it?
the answer is negative

 public void test2(){
     
 }
 //字节码
 public void test2();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
    //这里 locals=1,说明只有一个变量那就是this
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 5: 0
}

复制代码

In one example jsl see

public class son extends Father{
    int a=10;
    @Override
    public  void test() {
        System.out.println("son test");
        System.out.println("super.a="+super.a);
        System.out.println("((Father)this).a="+((Father)this).a);
        super.test2();
        ((Father)this).test2();
    }

    @Override
    public void test2() {
        System.out.println("son test2");
    }
}
public class Father{
    int a=20;
    public  void test(){
        System.out.println("father test");
    }
    public  void test2(){
        System.out.println("father test2");

    }
}
main():
new Son().test();
\\结果
son test
super.a=20
((Father)this).a=20
father test2
son test2
复制代码

In fact, here it is the result of a dynamic binding.
The key point of dynamic binding:
subclass method area maintains a virtual method table (Vtable, to complete the connection phase), all objects share a vtable

1.如果子类没有重写父类的方法,子vtable直接指向父vtable
2.如果子类重写了父类的方法,子vtable和父vtable索引相同方便查找
复制代码

Using the virtual method table for each object pointers do not need extra space to hold a reference to each method, improves the efficiency.

4. problem

Some portions of the above analysis is based on personal understanding bytecode, jvm memory partition may exist on some misunderstanding, hope chiefs can help guide.

Guess you like

Origin juejin.im/post/5d84db6a518825636c0d289b