There are a lot of design ideas that Java practices that are worth learning. Many of Java’s major concepts are guided by practical ideas and created in conjunction with the way the design is implemented.

There are collision and choice of ideas and compromise between ideas and reality. It is impossible for everything to be perfect. Java is the same, but we must know what perfection looks like before we can pursue it.

  • All information in this article is based on the author’s practice verification, if there is any mistake, please correct, thank you very much.
  • 【Java】 Main ideas and confusing concepts (juejin. Cn)
  • The article is a record article, content will continue to expand and supplement.

Java is not passing by reference

The rules adopted by programs in the process of obtaining parameters of functions or methods are called Evaluation strategies, which fall into three categories. Let’s first define the way variables are used in programs, and then discuss the three evaluation strategies.

Variables and References

In Java, the use of basic data types does not need to be referenced, but the use of object types is by reference. For example, a = 8, the variable slot A directly stores the value of 8, rather than the address of 8. For a = “Java”, the variable slot A stores the address of “Java”, and the program values according to the address.

However, in other high-level languages, some choose to use all variables in the “reference + variable” way, there is no certain type of value store. For example, if a = 8, the variable slot stores the address of 8. To use the value of 8, you need to remove the value in memory according to the address.

Evaluation strategy

There are three evaluation strategies, depending on how the caller passes the variable to the callee. Here we use “reference + variable” to explain the three strategies more clearly.

  1. Value passing: The caller makes a copy of the variable, passing the address of the copy variable to the caller. No matter what changes the called party makes to the variable or address, the caller will not be affected.

    func foo() { Object o = new Object(12); // o.hashCode = 001; o.a = 12; bar(o); // o.hashCode = 001; o.a = 12; } func bar(Object obj) {obj.a = 10; obj = new Object(13); }Copy the code
  2. Passing by reference: The caller passes the address of a variable to the caller, and the caller’s changes to the variable must affect the caller. At the same time, changes made by the called party to the address also affect the caller.

    func foo() { Object o = new Object(12); // o.hashCode = 001; o.a = 12; bar(o); // o.hashCode = 002; o.a = 13; } func bar(Object obj) {obj. A = 10; obj = new Object(13); }Copy the code
  3. Shared object passing: The caller makes a copy of the address of the variable and passes the copy of the address to the callee. At this time, the callee’s modification of the variable will definitely affect the caller. However, the callee’s modification of the address does not affect the caller.

    func foo() { Object o = new Object(12); // o.hashCode = 001; o.a = 12; bar(o); // o.hashCode = 001; o.a = 12; The object has not been changed, but the A data field has been modified. } func bar(Object obj) { obj.a = 10; obj = new Object(13); }Copy the code

    TODO: complement schematic diagram.

By analogy, you have a box and the key to the box, and you (the caller) give the box to your friend (the caller).

Value transfer is the equivalent of getting a new identical box and giving a new identical key to your friend, so whatever your friend does with the key or box doesn’t affect you.

Reference-passing is the equivalent of giving your keys and boxes directly to your friend, and your friend enscribing the keys they receive, or replacing the keys with keys in another box, or changing the contents of the box, which affects you.

The shared object passes the same key and the original box to your friend. Anything your friend does with the box affects you, but anything your friend does with the key is none of your business.

The definition of value passing is different in Java, where the contents of a variable are copied directly into the called method because there is no reference address for primitive data types. For objects, Java actually stores all object variables as reference addresses. For example, String STR = “Java”, STR is the Java reference address. To use the JAVA object, the JVM needs to get the value of STR and then use that value to find JAVA. Unlike C++ or other languages, STR is an object that points directly to JAVA.

Java uses value passing

For primitive data types, there is no doubt that Java copies values directly for parameter passing.

For objects, in fact, during Java runtime, variables are always stored as references to the object, that is, the address of the object. You can’t pass the whole object directly when you pass parameters, always pass the address. The question is, how is this address delivered? Check it out:

public class Test {

    private static class MyObj {
        int a;
        public MyObj(int a) {this.a = a;}
    }

    public static void main(String[] args) {
        MyObj o = new MyObj(10);
        System.out.println(o.hashCode() + "," + o.a); / / 325040804, 10
        testParameterTransfer(o);
        System.out.println(o.hashCode() + "," + o.a); / / 325040804, 11
    }

    private static void testParameterTransfer(MyObj obj) {
        obj.a = 11;
        obj = new MyObj(12); }}Copy the code

At first glance you might think it’s shared object passing, but it’s actually value passing, because you’re passing this O variable, and the content of that variable is actually the address of the object. So the way it’s passed is actually value passed. It doesn’t matter if you don’t understand, but you can already tell that Java is not pass-by.

The Java™ Tutorials also introduced Java’s evaluation strategy and highlighted The fact that Java only existed in value passing:

Primitive arguments, such as an int or a double, are passed into methods by value. This means that any changes to the values of the parameters exist only within the scope of the method. When the method returns, the parameters are gone and any changes to them are lost.

Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object’s fields can be changed in the method, if they have the proper access level.

For a discussion of this problem, see methods-is Java “pass-by-reference” or “pass-by-value”? – Stack Overflow

Returns different values, actually can be overloaded

In the JVM, the uniqueness of a method is determined by the method name + the method descriptor, which is described as a list of arguments followed by a return value. Such as:

public void foo(String param1, int param2, int[] param3) {}
Copy the code

Its descriptor is in the descriptor field:

public void foo(java.lang.String, int, int[]); descriptor: (Ljava/lang/String; I[I)V flags: ACC_PUBLICCopy the code

I is the descriptor of an int, [is the descriptor of an array, so [I describes an integer array. L is the descriptor of an object type, and Ljava/lang/String describes a String object.

Rules for overloading

In the Java language, overloading allows method names to be the same, as long as the argument lists are different. Differences in argument lists include the order of arguments and the type of arguments (differences in the number of arguments are actually included in differences in the type of arguments).

So in Java, if two methods have the same name and argument list, they cannot be overridden and will not compile:

public static void foo(int num) {}
public static char foo(int num) {}
Copy the code

Compile result:

. /Main.java:14:24 java: ... / main.java :14: Foo (int) has been defined in MainCopy the code

Method signature

In fact, the essence of the overload rule is to observe method uniqueness, meaning that no two methods of the same type can occur in a class. In Java, the uniqueness of a method is determined by the method signature.

According to the Java Language Specification, methods can coexist as long as their signature is different, which refers to the method name, parameter order, and parameter type. That is, two methods with the same name and argument list cannot coexist in the same class.

However, this is not necessarily the case. In fact, the concept of method signature defined in JVM Specification is inconsistent with that defined in Java Language Specification. The JVM Specification defines method signature including method name, parameter order, parameter type, method return value and checked exception list. That is, from the JVM’s point of view, two methods with the same name and argument list can coexist as long as the methods return different values.

How do you verify that? In addition to writing section code directly and using other JVM languages, Java testing can trick compilers. Some compilers allow code with the same method name and parameter to compile without strict checks. 1

List

and List

public static char foo(List<String> list) {
    System.out.println("foo(List<String> list)");
    return ' ';
}

public static long foo(List<Integer> list) {
    System.out.println("foo(List<Integer> list)");
    return 0L;
}
Copy the code

‘Run result after compilation:

foo(List<String> list)
foo(List<Integer> list)
Copy the code

The two descriptors are :(Ljava/util/List;) C and (Ljava/util/List) J, which returns C and J are not the same and can therefore be executed in any JVM.

So, in fact, methods that only return different values can be overridden in the JVM. However, as defined by the Java Language Specification, no compiler will allow methods that simply return different values to compile successfully, but the JVM is not just for Java.

Therefore, when talking about whether a different return value can be overloaded, you must first decide whether it is for the Java language or the JVM.


  1. Understanding the Java Virtual Machine in depth: Advanced FEATURES and Best Practices for the JVM (3rd edition) [M]. Beijing: China Machine Press,2019.373↩