anonymous的Java学习笔记(16)——处理Java中的对象

@[toc]

处理Java对象

Java对象都是Object类的实例,都可直接调用该类中定义的方法,这些方法提供了处理Java对象的通用方法。

打印对象和toString()方法

toString()方法是Object类里的一个实例方法,所有的Java类都是Object类的子类,因此所有的Java对象都具有toString()方法。

package com.abc.part5;

public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person("小花花");
        //com.abc.part5.Person@60e53b93
        System.out.println(p);
        /**
         * 所有的 Java 对象都可以和字符串进行连接运算,当 Java 对象和字符串进行连接运算时,
         * 系统自动调用 Java 对象 toString()方法的返回值和字符串进行连接运算。
         */
        //com.abc.part5.Person@60e53b93
        System.out.println(p + "");
        //com.abc.part5.Person@60e53b93
        System.out.println(p.toString() + "");
    }
}
  • toString()方法功能:当程序员直接打印该对象时,系统将会输出该对象的"自我描述"信息,用以告诉外界该对象具有的状态信息。
  • Object类提供的toString()方法总是返回该对象实现类类名+@+hashCode值,这个返回值并不能真正实现自我描述的功能,因此如果用户需要自定义类能实现自我描述的功能,就必须重写Object类toString()方法。

代码示例

package com.abc.part5;

public class Apple {
    private String color;
    private double price;

    public Apple(String color, double price) {
        this.color = color;
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }


    /**
     * @return String
     */
    @Override
    public String toString() {
        return "水果市场里的" + color + "的苹果的价格是每斤" + price + "元。";
    }
}
package com.abc.part5;

public class AppleTest {


    public static void main(String[] args) {
        Apple apple = new Apple("红色", 3.99);
        //水果市场里的红色的苹果的价格是每斤3.99元。
        System.out.println(apple.toString());
    }
}

从上面运行结果可以看出,通过重写Apple类的toString()方法,就可以让系统在打印Apple对象时打印出该对象的"自我描述"信息。

  • 大部分时候,重写toString()方法总是返回该对象的所有令人感兴趣的信息所组成的字符串。通常可返回如下格式的宇符串:
    类名[field1=value1, field2=value2]
    

==和equals()方法

Java程序中测试两个变量是否相等的两种方式

  • ==运算符
    • 当使用==来判断两个变量是否相等时
      • 两个变量是基本类型变量时,只要两个变量的值相等,就将返回true。
      • 两个变量是引用类型变量时,只有它们指向同一个对象时,==判断才会返回true==不可用于比较类型上没有父子关系的两个对象
  • equals()方法
    • 判断两个引用类型变量是否相等

代码示例

package com.abc.part5;

/**
 * @Auther: ABC
 * @Date: 2020/5/24 15:36
 * @Description:
 */
public class EqualTest {

    public static void main(String[] args) {
        int aa = 65;
        float ab = 65.0f;
        //aa是否与ab相等?true
        System.out.println("aa是否与ab相等?" + (aa == ab));
        char ac = 'A';
        //aa是否与ac相等?true
        System.out.println("aa是否与ac相等?" + (aa == ac));
        String s1 = new String("hello");
        String s2 = new String("hello");
        //s1是否与s2相等?false
        System.out.println("s1是否与s2相等?" + (s1 == s2));
        //s1是否equals s2?true
        System.out.println("s1是否equals s2?" + (s1.equals(s2)));
        //由于java.laηg.String与EqualTest类没有继承关系,所以下面语句导致编译错误
        //System.out.println("hello" = new EqualTest());

    }
}

"hello"直接量和new String("hello")有什么区别?

  1. 当Java程序直接使用形如"hello"的字符串直接量(包括可以在编译时就计算出来的字符串值)时,JVM将会使用**常量池**来管理这些字符串;
  2. 当使用new String("hello")时,JVM会先使用常量池来管理"hello"直接量,再调用String类构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中。

总结一下,new String("hello")共产生了两个字符串对象。

常量池

常量池(constant pool)专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据。它包括了关于方法接口中的常量,还包括字符串常量

JVM使用常量池管理字符串直接量代码示例

package com.abc.part5;

/**
 * @Auther: ABC
 * @Date: 2020/5/24 15:55
 * @Description:
 */
public class StringComapareTest {
    public static void main(String[] args) {
        //s1直接引用常量池中的"疯狂Java"
        String s1 = "疯狂Java";
        String s2 = "疯狂";
        String s3 = "Java";
        //s4后面的字符串值可以在编译时就确定下来
        //s4直接引用常量池中的"疯狂Java"
        String s4 = "疯狂" + "Java";
        //s5后面的字符息值可以在编译时就确定下来
        //s5直接引用常量池中的"疯狂Java"
        String s5 = "疯" + "狂" + "Java";
        //s6后面的字符串值不能在编译时就确定下来
        //s6不能引用常量池中的字符串
        String s6 = s2 + s3;
        //使用new调用构造器将会创建一个新的String对象
        //s7引用堆内存中新创建的String对象
        String s7 = new String("疯狂Java");
        //输出 true
        System.out.println(s1 == s4);
        //输出 true
        System.out.println(s1 == s5);
        //输出 false
        System.out.println(s1 == s6);
        //输出 false
        System.out.println(s1 == s7);
    }

}

例子中的s1,s4,s5所引用字符串可以在编译期就确定下来,因此它们都将引用常量池中的同一个字符串对象。

使用new String()创建的字符串对象运行时创建出来的,它被保存在运行时内存区(即堆内存)内,不会放入常量池中。

equals()方法

  1. equals()方法是Object类提供的一个实例方法,因此所有引用变量都可调用该方法来判断是否与其他引用变量相等。
  2. equals()方法判断两个对象相等的标准与使用==运算符没有区别,同样要求两个引用变量指向同一个对象才会返回true
    • 因此这个Object类提供的equals()方法没有太大的实际意义,如果希望采用自定义的相等标准,则可采用重写equals()方法来实现。
  3. String已经重写了Object类的equals()方法,String的equals()方法判断两个字符串相等的标准是:只要两个字符串所包含的字符序列相同,通过equals()比较将返回true,否则将返回false。

通常正确地重写equals()方法应该满足下列条件

  1. 自反性:对任意x, x.equals(x)一定返回true
  2. 对称性:对任意x, y, 如果y.equals(x)返回true,则x.equals(y)也返回true
  3. 传递性:对任意x, y, z, 如果x.equals(y)返回归true,y.equals(z)返回true,则x.equals(z)一定返回true
  4. 一致性:对任意 x, y, 如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false
  5. 对任何不是nullx, x.equals(null)一定返回false

总结

  • Object类默认提供的equals()只是比较对象的地址,即Object类的equals()方法比较的结果与==运算符比较的结果完全相同。
  • 在实际应用中常常需要重写equals()方法,重写equals()方法时,相等条件是由业务要求决定的,因此equals()方法的实现也是由业务要求决定的。