The nature and function of the difference between Scala method - decompile resolve

The nature and function of the difference between Scala method - decompile resolve

1. Method - Analysis

1.1 common method

  1. Conventional method, i.e., the usual method defined in the class, object in the following example
 object Demo01 {
 
  def sum1(a:Int, b: Int) : Int = a + b
  
  def main(args: Array[String]): Unit = {
    println(sum1(1, 2))
  }
  
}
  1. And methods defined in the class object definition is slightly different: the method in object will generate a static method of multi-
  2. Let me take a look at the results decompile the code above:
  • Demo01.class
import scala.reflect.ScalaSignature;
	
@ScalaSignature(bytes="\006\001U:Q!\001\002\t\002-\ta\001R3n_B\n$BA\002\005\003\tigM\003\002\006\r\005!A/Z:u\025\t9\001\"\001\003tW\026L(\"A\005\002\007\r|Wn\001\001\021\0051iQ\"\001\002\007\0139\021\001\022A\b\003\r\021+Wn\034\0312'\ti\001\003\005\002\022)5\t!CC\001\024\003\025\0318-\0317b\023\t)\"C\001\004B]f\024VM\032\005\006/5!\t\001G\001\007y%t\027\016\036 \025\003-AQAG\007\005\002m\tAa];ncQ\031AdH\021\021\005Ei\022B\001\020\023\005\rIe\016\036\005\006Ae\001\r\001H\001\002C\")!%\007a\0019\005\t!\rC\003%\033\021\005Q%\001\003nC&tGC\001\024*!\t\tr%\003\002)%\t!QK\\5u\021\025Q3\0051\001,\003\021\t'oZ:\021\007Eac&\003\002.%\t)\021I\035:bsB\021qF\r\b\003#AJ!!\r\n\002\rA\023X\rZ3g\023\t\031DG\001\004TiJLgn\032\006\003cI\001")
public final class Demo01 {
  public static void main(String[] paramArrayOfString) {
    Demo01..MODULE$.main(paramArrayOfString);
  }
  
  public static int sum1(int paramInt1, int paramInt2) {
    return Demo01..MODULE$.sum1(paramInt1, paramInt2);
  }
}
  • Demo01$.class
import scala.Predef.;
import scala.runtime.BoxesRunTime;

public final class Demo01$ {
    
    public static final  MODULE$;

    static {
        new ();
    }

    public int sum1(int a, int b) {
        return a + b;
    }

    public void main(String[] args) {
        Predef..MODULE$.println(BoxesRunTime.boxToInteger(sum1(1, 2)));
    }

    private Demo01$() {
        MODULE$ = this;
    }
}
  1. Demo01.class JVM is really calling the entrance, which it then call Demo01 $ in the main. The method is also responsible for maintaining a static method, sum1 call Demo01 $ actually here via static methods of sum1
  2. Demo01 $ .class responsible for maintaining the value of the actual use of the method
  3. As it can be seen in the general methods Scala and Java methods are not very different, there are only subtle differences in statically compiled at the object of

1.2 Nested Method

  1. Nested-method, i.e. a method defined in the method, the following example
object Demo01 {
	
  def main(args: Array[String]): Unit = {
    def sum2(a:Int, b: Int) : Int = a + b

    println(sum2(3, 4))
  }
	
}
  1. Nesting method is a method, just use common methods and scope of different, then why do they have different scopes of it? What is the difference, in essence, have it?
  2. Let me take a look at the results decompile the code above:
  • Demo01.class
import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="\006\001-:Q!\001\002\t\002-\ta\001R3n_B\n$BA\002\005\003\tigM\003\002\006\r\005!A/Z:u\025\t9\001\"\001\003tW\026L(\"A\005\002\007\r|Wn\001\001\021\0051iQ\"\001\002\007\0139\021\001\022A\b\003\r\021+Wn\034\0312'\ti\001\003\005\002\022)5\t!CC\001\024\003\025\0318-\0317b\023\t)\"C\001\004B]f\024VM\032\005\006/5!\t\001G\001\007y%t\027\016\036 \025\003-AQAG\007\005\002m\tA!\\1j]R\021Ad\b\t\003#uI!A\b\n\003\tUs\027\016\036\005\006Ae\001\r!I\001\005CJ<7\017E\002\022E\021J!a\t\n\003\013\005\023(/Y=\021\005\025BcBA\t'\023\t9##\001\004Qe\026$WMZ\005\003S)\022aa\025;sS:<'BA\024\023\001")
public final class Demo01 {
  public static void main(String[] paramArrayOfString) {
    Demo01..MODULE$.main(paramArrayOfString);
  }
}
  • Demo01$.class
import scala.Predef.;
import scala.runtime.BoxesRunTime;

public final class Demo01$ {
  public static final  MODULE$;
  
  private final int sum2$1(int a, int b) {
    return a + b;
  }
  
  public void main(String[] args) {
    Predef..MODULE$.println(BoxesRunTime.boxToInteger(sum2$1(3, 4)));
  }
  
  private Demo01$() {
    MODULE$ = this;
  }
  
  static {
    new ();
  }
}
  1. Demo01.class JVM is really calling the entrance, which it then call Demo01 $ in the main. Where there is no static methods sum2
  2. Demo01 $ .class responsible for maintaining the value of the actual use of the method. Wherein the method has sum2 while being renamed. 1 $ sum2
  3. In view of this, in fact, use a nested method renamed way to ensure that does not conflict with the general method of the same name, in fact, external calls sum2 call is class, the ordinary method sum2 object, can not be called sum2 $ 1, thereby leading to the limit scope. In fact, from the point of view of Java, nested method or an ordinary method.

2. Functions - Analysis

2.1 Function Example

object Demo01 {

  def main(args: Array[String]): Unit = {
    val max = (a: Int, b:Int) => if (a > b) a else b

    println(max(5, 6))
  }

}

2.2 decompile results

  • Demo01.class
import scala.reflect.ScalaSignature;

@ScalaSignature(bytes="\006\001-:Q!\001\002\t\002-\ta\001R3n_B\n$BA\002\005\003\tigM\003\002\006\r\005!A/Z:u\025\t9\001\"\001\003tW\026L(\"A\005\002\007\r|Wn\001\001\021\0051iQ\"\001\002\007\0139\021\001\022A\b\003\r\021+Wn\034\0312'\ti\001\003\005\002\022)5\t!CC\001\024\003\025\0318-\0317b\023\t)\"C\001\004B]f\024VM\032\005\006/5!\t\001G\001\007y%t\027\016\036 \025\003-AQAG\007\005\002m\tA!\\1j]R\021Ad\b\t\003#uI!A\b\n\003\tUs\027\016\036\005\006Ae\001\r!I\001\005CJ<7\017E\002\022E\021J!a\t\n\003\013\005\023(/Y=\021\005\025BcBA\t'\023\t9##\001\004Qe\026$WMZ\005\003S)\022aa\025;sS:<'BA\024\023\001")
public final class Demo01 {
  public static void main(String[] paramArrayOfString) {
    Demo01..MODULE$.main(paramArrayOfString);
  }
}
  • Demo01$.class
import scala.Function2;
import scala.Predef.;
import scala.Serializable;
import scala.runtime.AbstractFunction2.mcIII.sp;
import scala.runtime.BoxesRunTime;

public final class Demo01$ {
  public static final  MODULE$;
  
  static {
    new ();
  }
  
  public void main(String[] args) {
    Function2 max = new AbstractFunction2.mcIII.sp() {
      public static final long serialVersionUID = 0L;
      
      public int apply$mcIII$sp(int a, int b) {
        return a > b ? a : b;
      }
      
      public final int apply(int a, int b) {
        return apply$mcIII$sp(a, b);
      }
    };
    Predef..MODULE$.println(BoxesRunTime.boxToInteger(max.apply$mcIII$sp(5, 6)));
  }
  
  private Demo01$() {
    MODULE$ = this;
  }
}

2.3 decompile analytic function

  1. Demo01.class, say nothing of this, and as before
  2. Demo01 $ .class out in a multi-type variable max scala.Function2, in fact, it is our function.
  3. View scala source seen scala.Function2 is a trait, while the corresponding new AbstractFunction2 an abstract class, this class extends Function2. The specific function corresponding to the function actually is a concrete realization of this class AbstractFunction2 to apply the method of trait Function2.
  4. Here, the fact will be appreciated that, in a scala trait function is actually defined, and has a corresponding abstract implementation class to implement function-specific
  5. Extended:
    • scala actually tuples corresponding class, class named Tuple, with up to 22 parameters, i.e. Tuple22. Max example function corresponding Function2 herein actually refers to two parameters can be transferred, while the functions defined in the source 22 can pass parameters, called Function22
    • If you are familiar Java8, we can look at the lambda expression, the lambda expression usually also pass an anonymous class that implements an interface, such as new Thread (() -> System.out.println ( "Hello World!") ) .start () ;. Meanwhile, Java8 defined Function, Consumer, Supplier, Predicate Stream several interfaces for processing, and it is a function of corresponding Scala.
    • In Scala trait after decompile, in fact Interface + abstract class. Java interface corresponds to the interface of the abstract class for implementing trait own methods, variables,

3. Why methods and functions can be converted to each other?

Exemplary methods and functions mix 3.1

object Demo01 {

  def main(args: Array[String]): Unit = {
    // 一些单词
    val words= List("java", "scala", "python", "rust", "go", "c", "c++")
    
    // 定义转换字母大写的函数
    val toUpperFunc = (word: String) => word.toUpperCase()
    // 定义转换字母大写的方法
    def toUpperMethod(word: String): String = word.toUpperCase()
    
    // 方法和函数混用
    // map方法在源码中明确标注,需要的参数的类型是函数A => B
    words.map(toUpperFunc).foreach(println)
    words.map(toUpperMethod).foreach(println)
    // 结果一样
  }

}

After reading the above example may be a bit confusing. After all, we already said, methods and functions are two different things in nature, the method Why can pass into the method parameter types as a function of it?

3.2 Conversion Methods and Function - Analysis

  1. No hurry, let's look at a simple example below (as a function of the conversion method)
object Demo01 {
  
  def sum2(a:Int, b: Int) : Int = a + b

  def main(args: Array[String]): Unit = {
    val func1: (Int, Int) => Int = sum2 _
    println(func1(9, 10))
    
// 你还可以写成如下形式
//    val func2: (Int, Int) => Int = sum2
//    println(func2(9, 10))
//
//    val func3 = sum2 _
//    println(func3(9, 10))
  }

}
  1. Let me take a look at the results decompile the code above:
  • Demo01.class (omitted)
  • Demo01$.class
import scala.Function2;
import scala.Predef.;
import scala.Serializable;
import scala.runtime.AbstractFunction2.mcIII.sp;
import scala.runtime.BoxesRunTime;

public final class Demo01$ {
  public static final  MODULE$;
  
  static {
    new ();
  }
  
  public int sum2(int a, int b) {
    return a + b;
  }
  
  public void main(String[] args) {
    Function2 func1 = new AbstractFunction2.mcIII.sp() {
      public static final long serialVersionUID = 0L;
      
      public int apply$mcIII$sp(int a, int b) {
        return Demo01..MODULE$.sum2(a, b);
      }
      
      public final int apply(int a, int b) {
        return apply$mcIII$sp(a, b);
      }
    };
    Predef..MODULE$.println(BoxesRunTime.boxToInteger(func1.apply$mcIII$sp(9, 10)));
  }
  
  private Demo01$() {
    MODULE$ = this;
  }
}
  1. Or generating function and foregoing description, as an example of the abstract class implements an object AbstractFunction2 Function2 to apply method. However, note that there is a subtle difference, apply invoked apply $ mcIII $ sp method, and apply $ mcIII $ sp turn invokes a method sum2! ! ! Yes, the conversion method is a function, in fact, function did not re-implement this function in-house, but directly call sum2 method!

Example 3.3 mix - Analysis

  1. Now ready, look at the previous example mix "turn capitalized word" of the decompiled results:
  • Demo01.class (omitted)
  • Demo01$.class
import scala.Function1;
import scala.Predef.;
import scala.Serializable;
import scala.collection.immutable.List;
import scala.collection.immutable.List.;
import scala.runtime.AbstractFunction1;
import scala.runtime.BoxedUnit;

public final class Demo01$ {
  public static final  MODULE$;
  
  public final String com$skey$test$mf$Demo01$$toUpperMethod$1(String word) {
    return word.toUpperCase();
  }
  
  public void main(String[] args) {
    List words = List..MODULE$.apply(Predef..MODULE$.wrapRefArray((Object[])new String[] { "java", "scala", "python", "rust", "go", "c", "c++" }));
    
    Function1 toUpperFunc = new AbstractFunction1() {
      public static final long serialVersionUID = 0L;
      
      public final String apply(String word) {
        return word.toUpperCase();
      }
    };
    ((List)words.map(toUpperFunc, List..MODULE$.canBuildFrom())).foreach(new AbstractFunction1() {
      public static final long serialVersionUID = 0L;
      
      public final void apply(Object x)
      {
        Predef..MODULE$.println(x);
      }
    });
    
    ((List)words.map(new AbstractFunction1()  {
      public static final long serialVersionUID = 0L;
      
      public final String apply(String word) {
        return Demo01..MODULE$.com$skey$test$mf$Demo01$$toUpperMethod$1(word);
      }
    }, List..MODULE$.canBuildFrom())).foreach(new AbstractFunction1() {
      public static final long serialVersionUID = 0L;
      
      public final void apply(Object x) {
        Predef..MODULE$.println(x);
      }
    });
  }
  
  private Demo01$() {
    MODULE$ = this;
  }
  
  static {
    new ();
  }
}

  1. First part of the normal function defined and we imagine, in line with the rules, was introduced to toUpperFunc function to map, the final call was printed foreach
  2. And we passed part toUpperMethod method to the map, in fact, is an instance of an anonymous function (this function is called toUpperMethod apply methods that the previous "method of converting a function"), this function will be introduced to the map, the final print was calling foreach
  3. This time, we know, only the map data is indeed received words of type A => B is a function, not passed to the method to produce the map of the cause of the error is due to the method is converted to function toUpperMethod
  4. In short, the method of converting a function, in fact, generate a new function, which then calls by the function!
Published 128 original articles · won praise 45 · Views 150,000 +

Guess you like

Origin blog.csdn.net/alionsss/article/details/89323520