Java object oriented

Keywords: Java jvm

Java objects are instances of the Object class, so you can directly call the methods defined in the class

toString()

class Person
{
    private String name;
    public Person(String name)
    {
        this.name = name;
    }
}
public class PrintObject
{
    public static void main(String[] args)
    {
        // Create a Person object and assign it to the p variable
        var p = new Person("Sun WuKong");
        // Print the Person object referenced by p
        System.out.println(p);
    }
}

The execution result is: Person@123772c4
Parsing: @ sign is followed by 8-digit hexadecimal number, which may change every time it is executed. We can only output string on the console using println() method, while P is the object in memory. When we use println() method to output object, what we actually output is the result of converting object p to string, just like calling toString() method to output the return value of the method That is to say, the following two lines of code have exactly the same effect

System.out.println(p);
System.out.println(p.toString());

toString() method is an instance method in the Object class. All Java classes are subclasses of the Object class. Therefore, all Java objects have toString() method. Not only that, all Java objects can be connected with strings. When Java objects and character strings are connected, the system automatically calls the return value and strings of toString() method of Java objects Link operation, that is, the results of the following two lines of code are exactly the same.

String pStr = p + "";
String pStr = p.toString() + "";

toString() is a very special method, which is a "self description" method. This method is usually used for implementation: when the programmer prints the object directly, the system will output the "self description" information of the object, which is used to tell the outside world the state information of the object.

class Apple
{
    private String color;
    private double weight;
    public Apple(){    }
    //Provide a constructor with parameters
    public Apple(String color, double weight)
    {
        this.color = color;
        this.weight = weight;
    }

    // setter and getter methods of color
    public void setColor(String color)
    {
        this.color = color;
    }
    public String getColor()
    {
        return this.color;
    }

    // setter and getter methods of weight
    public void setWeight(double weight)
    {
        this.weight = weight;
    }
    public double getWeight()
    {
        return this.weight;
    }

    // Override the toString method to implement the self description of Apple objects
    public String toString()
    {
        return "An apple, the color is:" + color
            + ",The weight is:" + weight;
    }

}
public class ToStringTest
{
    public static void main(String[] args)
    {
        var a = new Apple("Red", 5.68);
        // Print Apple objects
        System.out.println(a);
    }
}

The execution result is: an apple, color: red, weight: 5.68
In the program, the toString() method is overridden, so this output is obtained. In general, the purpose of overriding the toString() method is to return a string composed of all the interesting information of the object, such as:
Class name [field1=value1, filed2=value2,...]
So we can change toString() method in Apple class to:

public String toString()
{
    return "Apple[color=" + color + ",weight=" + weight + "]";
}

==And equals

==

There are two ways to judge whether two variables are equal in Java programs. One is to use the operator = =, the other is to use the equals() method.
If two variables are of basic type and both are of numerical type (not necessarily the same data type), true will be returned as long as the values of the two variables are equal; however, if they are reference variables, true will be returned only when they point to the same object.
==Cannot be used to compare two objects of type that do not have a parent-child relationship.

public class EqualTest
{
    public static void main(String[] args)
    {
        var it = 65;
        var fl = 65.0f;
        // Will output true
        System.out.println("65 And 65.0f Is it equal?" + (it == fl));
        var ch = 'A';
        // Will output true
        System.out.println("65 and'A'Is it equal?" + (it == ch));
        var str1 = new String("hello");
        var str2 = new String("hello");
        // Will output false
        System.out.println("str1 and str2 Is it equal?" + (str1 == str2));
        // Will output true
        System.out.println("str1 Whether equals str2?" + (str1.equals(str2)));
        // Because java.lang.String has no inheritance relationship with EqualTest class,
        // So the following statement causes compilation errors
        System.out.println("hello" == new EqualTest());
    }
}

What's the difference between String str1 = "davieyang"; and var str1 = new String("davieyang")?

  • When Java programs directly use string literals, including string values that can be computed at compile time, the JVM will use constant pools to manage these strings
  • When new String("davieyang") is used, the JVM will first use constant pool to manage the "davieyang" direct quantity, and then call String constructor to create a new String object, which will be saved in heap memory. In other words, new String("davieyang") generates two String objects

Constant pool is specially used to manage some data determined at compile time and saved in compiled. class files. It includes constants in classes, methods, interfaces, and string constants

public class StringCompareTest
{
    public static void main(String[] args)
    {
        // s1 direct reference to "crazy Java" in constant pool
        var s1 = "Insane Java";
        var s2 = "Insane";
        var s3 = "Java";
        // The string value after s4 can be determined at compile time
        // s4 direct reference to "crazy Java" in constant pool
        var s4 = "Insane" + "Java";
        // The string value after s5 can be determined at compile time
        // s5 directly refers to "crazy Java" in constant pool
        var s5 = "crazy" + "Crazy" + "Java";
        // The string value after s6 cannot be determined at compile time,
        // Cannot reference string in constant pool
        var s6 = s2 + s3;
        // Calling the constructor with new will create a new String object,
        // s7 references the newly created String object in heap memory
        var s7 = new String("Insane Java");
        System.out.println(s1 == s4); // Output true
        System.out.println(s1 == s5); // Output true
        System.out.println(s1 == s6); // Output false
        System.out.println(s1 == s7); // Output false
    }
}

The JVM constant pool guarantees that there is only one direct quantity of the same string, and multiple copies will not be generated. The strings referenced by s1, s4 and s5 in the code can be determined at the compile time, so they will all refer to the same string object in the constant pool
Using new String() to create a string object is created at runtime and is saved in the runtime memory area (heap memory) and will not be put into the constant pool

equals

  • In many cases, when a program judges whether two reference variables are equal, it hopes to have a judgment rule similar to "equal value", which does not strictly require that two reference variables point to the same object, such as two String variables, but only requires that the String objects they reference contain the same sequence of characters, which can be regarded as equal. In this case, use the equals() Method, for example, str1.equals(str2) of the upper program will return true
  • The equals() method is an instance method provided by the Object class. Therefore, all reference variables can call this method to determine whether they are equal to other reference variables. However, there is no difference between using this method to determine whether two objects are equal and using the = = operator. It also requires that two reference variables point to the same Object to return true. Therefore, the equals() method provided by the Object class It doesn't have much practical significance. If you want to adopt a custom equality standard, you can override the equals () method to achieve it
  • String has overridden the equality() method of Object. The equality() method of string judges that two strings are equal by the following criteria: as long as two strings contain the same sequence of characters, it will return true, otherwise it will return false

If the equals() method is to judge that the values of two objects are equal, this statement is very inaccurate. What is the value of an object? How are the values of objects equal? In fact, overriding the equals method is to provide a custom equality standard. What do you think is equality? In extreme cases, the Person object and the Dog object are equal.

// Define a Person class
class Person
{
    // Override the equals() method to provide a custom equality standard
    public boolean equals(Object obj)
    {
        // Always return true without judgment, that is, the Person object is equal to any object
        return true;
    }
}
// Define an empty Dog class
class Dog{}
public class OverrideEqualsError
{
    public static void main(String[] args)
    {
        var p = new Person();
        System.out.println("Person Are objects equals Dog Objects?"
            + p.equals(new Dog()));
        System.out.println("Person Are objects equals String Objects?"
            + p.equals(new String("Hello")));
    }
}
class Person
{
    private String name;
    private String idStr;
    public Person(){}
    public Person(String name, String idStr)
    {
        this.name = name;
        this.idStr = idStr;
    }
    // The setter and getter methods of name and idStr are omitted here.
    // name's setter and getter methods
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    // setter and getter methods of idStr
    public void setIdStr(String idStr)
    {
        this.idStr = idStr;
    }
    public String getIdStr()
    {
        return this.idStr;
    }
    // Override the equals() method to provide a custom equality standard
    public boolean equals(Object obj)
    {
        // If two objects are the same
        if (this == obj)
            return true;
        // Only if obj is a Person object
        if (obj != null && obj.getClass() == Person.class)
        {
            var personObj = (Person) obj;
            // Only when the idStr of the current object is equal to that of the obj object can we judge that the two objects are equal
            if (this.getIdStr().equals(personObj.getIdStr()))
            {
                return true;
            }
        }
        return false;
    }
}
public class OverrideEqualsRight
{
    public static void main(String[] args)
    {
        var p1 = new Person("Sun WuKong", "12343433433");
        var p2 = new Person("Monkey King", "12343433433");
        var p3 = new Person("Gohan", "99933433");
        // The idStr of p1 and p2 are equal, so the output is true
        System.out.println("p1 and p2 Is it equal?" + p1.equals(p2));
        // The idStr of p2 and p3 are not equal, so the output is false
        System.out.println("p2 and p3 Is it equal?" + p2.equals(p3));
    }
}

Override the equals() method of the Person class, and specify the standard for the equality of the Person object and other objects: the other object must be an instance of the Person class, and the idStr of the two Person objects is equal, so the two Person objects can be judged to be equal. For another scenario description, we can think that as long as the ID strings of two Person objects are equal, we can judge the equality

Why different obj instanceof Person to judge

When judging whether obj is an instance of Person class, why not use obj instanceof Person?
For the instanceof operator, it will return true when the previous object is an instance of the following class or an instance of a subclass, so it is problematic to use instanceof when overriding the equals() method to determine whether two objects are instances of the same class. For the requirement of overriding the equals() method, it is generally required that two objects are instances of the same class.

Override equal() standard

  • Negativity: for any x, x.equals(x) must return true
  • Symmetry: for any X and y, if y.equals(x) returns true, x.equals(y) also returns true
  • Transitivity: for any x,y,z, if x.equals(y) returns true and y.equals(z) returns true, x.equals(z) must return true
  • Consistency: for any X and y, no matter how many times x.equals(y) is called, the returned result should be consistent if the information used for equivalence comparison in the object has not changed
  • x.equals(null) must return false for any x that is not null

The equals() provided by Object by default is just the address of the comparison Object. That is to say, the result of the equals() method comparison of Object class is exactly the same as that of the = = operator. Therefore, the equals() method is often overridden.

155 original articles published, 43 praised, 20000 visitors+
Private letter follow

Posted by Nicholas Reed on Fri, 21 Feb 2020 05:11:18 -0800