Java Object类
Java面向对象设计 - Java Object类
Java在java.lang包中有一个Object类。
所有Java类都直接或间接扩展Object类。
所有Java类都是Object类的子类Object类是所有类的超类。
Object类本身没有超类。
Object类的引用变量可以保存任何类的对象的引用。
以下代码声明对象类型的引用变量obj:
Object obj;
方法
Object类有九个方法,可以在Java中的所有类中使用。
- public String toString()
它是实现在Object类中,我们可以自定义它。
它返回对象的字符串表示形式。
通常,它用于调试目的。 - public boolean equals(Object obj)
它在Object类中实现,我们可以自定义它。
它用于比较两个对象的相等性。 - public int hashCode()
它在Object类中实现,我们可以自定义它。
它返回对象的哈希码(整数)值。 - protected Object clone() throws
CloneNotSupportedException
它不在Object类中实现,我们可以通过覆盖克隆方法来自定义它。
它用于创建对象的副本。 - protected void finalize() throws Throwable
它不是在Object类中实现,我们可以自定义它
它在对象被销毁之前被垃圾收集器调用。 - public final Class getClass()
它在Object类中实现,我们不能自定义它。
它返回对对象的Class对象的引用。 - public final void notify()
它是在Object类中实现的,我们不能自定义它。
此方法通知对象的等待队列中的一个线程。 - public final void notifyAll()
它是在Object类中实现的,我们不能自定义它。
此方法通知对象的等待队列中的所有线程。 - public final void wait() throws InterruptedException
public final void wait(long timeout) throws InterruptedException
public final void wait (long timeout, int nanos) throws InterruptedException
它是在Object类中实现的,我们不能自定义它。
使对象的等待队列中的线程等待,无论是否超时。
例子
以下代码显示如何重新实现Object类的toString()方法。
public class Test { public String toString() { return "Here is a string"; } }
什么是对象类?
Java中的每个对象都属于一个类。
Object类的getClass()方法返回Class对象的引用。
以下代码显示了如何获取Cat对象的Class对象的引用:
Cat c = new Cat(); Class catClass = c.getClass();
Class类是通用的,其形式类型参数是由其对象表示的类的名称。
我们可以使用泛型重写上面的语句。
Class<Cat> catClass = c.getClass();
Java HashCode(哈希码)
Java面向对象设计 - Java哈希码
Object的哈希码
哈希码是一个整数值。计算整数的算法称为散列函数。
Java使用散列码从基于散列的集合中有效地检索数据。
Object类有一个返回int的hashCode()方法,它是对象的哈希码。
该方法的默认实现通过将对象的内存地址转换为整数来计算对象的哈希码。
下面是我们在类中重写hashCode()方法时必须遵循的规则。
假设有两个对象引用,x和y。
如果x.equals(y)返回true,x.hashCode()必须返回一个整数,它等于y.hashCode()。
如果两个对象使用equals()方法相等,则它们必须具有相同的哈希码。
如果x.hashCode()等于y.hashCode(),则x.equals(y)不必返回true。
如果对同一个对象多次调用hashCode()方法,则该方法必须返回相同的整数值。
如果一个类覆盖这两个方法中的任何一个,它必须覆盖该类的对象在基于散列的集合中正确工作。
Java 7添加了一个实用程序类java.lang.Objects。它包含一个hash()方法,用于计算任意数量值的哈希码。
从java 7,使用Objects.hash()方法来计算对象的哈希码。
例子
以下代码显示如何计算哈希值。
class Book { private String title; private String author; public int hashCode() { int hash = 37; int code = 0; // Use title code = (title == null ? 0 : title.hashCode()); hash = hash * 59 + code; // Use author code = (author == null ? 0 : author.hashCode()); hash = hash * 59 + code; return hash; } }
Java Object.Equals方法
Java面向对象设计 - Java Object.Equals方法
以下代码显示如何实现equals()和hashCode()方法
class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } /* implement the equals() method */ public boolean equals(Object otherObject) { // Are the same? if (this == otherObject) { return true; } // Is otherObject a null reference? if (otherObject == null) { return false; } // Do they belong to the same class? if (this.getClass() != otherObject.getClass()) { return false; } // Get the reference of otherObject in a SmartPoint variable Point otherPoint = (Point) otherObject; // Do they have the same x and y co-ordinates boolean isSamePoint = (this.x == otherPoint.x && this.y == otherPoint.y); return isSamePoint; } /* * implement hashCode() method of the Object class, which is a requirement * when you implement equals() method */ public int hashCode() { return (this.x + this.y); } } public class Main { public static void main(String[] args) { Point pt1 = new Point(10, 10); Point pt2 = new Point(10, 10); Point pt3 = new Point(12, 19); Point pt4 = pt1; System.out.println("pt1 == pt1: " + (pt1 == pt1)); System.out.println("pt1.equals(pt1): " + pt1.equals(pt1)); System.out.println("pt1 == pt2: " + (pt1 == pt2)); System.out.println("pt1.equals(pt2): " + pt1.equals(pt2)); System.out.println("pt1 == pt3: " + (pt1 == pt3)); System.out.println("pt1.equals(pt3): " + pt1.equals(pt3)); System.out.println("pt1 == pt4: " + (pt1 == pt4)); System.out.println("pt1.equals(pt4): " + pt1.equals(pt4)); } }
上面的代码生成以下结果。
注意
这里是equals()方法的实现的规范。假设x,y和z是三个对象的非空引用。
- 自反性。表达式x.equals(x)应该返回true。
- 对称性。如果x.equals(y)返回true,y.equals(x)必须返回true。
- 传递性。如果x.equals(y)返回true,y.equals(z)返回true,则x.equals(z)必须返回true。
- 一致性。如果x.equals(y)返回true,它应该保持返回true,直到x或y的状态被修改。如果x.equals(y)返回false,它应该保持返回false,直到x或y的状态被修改。
- 与空引用的比较:任何类的对象不应等于空引用。表达式x.equals(null)应始终返回false。
- 与hashCode()方法的关系:如果x.equals(y)返回true,x.hashCode()必须返回与y.hashCode()相同的值。
Java Object.toString方法
Java面向对象设计 - Java Object.toString方法
对象的字符串表示应以可读格式包含有关对象状态的足够信息。
Object类的toString()方法表示字符串中类的对象。
Object类提供了toString()方法的默认实现。它返回一个以下格式的字符串:
<fully qualified class name>@<hash code of object in hexadecimal>
例子
考虑下面的代码及其输出。您可能会得到不同的输出。
public class Main{ public static void main(String[] argv){ Object obj = new Object(); String objStr = obj.toString(); System.out.println(objStr); } }
上面的代码生成以下结果。
例2
以下代码显示了如何创建自己的toString方法。
public class Main{ public static void main(String[] argv){ MyClass obj = new MyClass(123); String objStr = obj.toString(); System.out.println(objStr); } } class MyClass { private int value; public MyClass(int value) { this.value = value; } public void setValue(int value) { this.value = value; } public int getValue() { return value; } /* override toString() method of the Object class */ public String toString() { // Return the stored value as a string String str = String.valueOf(this.value); return str; } }
上面的代码生成以下结果。
注意
您需要确保它被声明为public,它的返回类型是String,并且它不接受任何参数。
类的toString()方法非常重要。当需要对象的字符串表示时,Java会自动调用toString()方法。
有两种情况值得一提:
当你连接一个字符串和一个对象
String str = "Hello" + new Point(10, 20);
Java在Point对象上调用toString()方法,并将返回的值连接到“Hello"字符串。
上述语句与以下语句相同:
String str = "Hello" + new Point(10, 20).toString();
Java Object.Clone方法
Java面向对象设计 - Java Object.Clone方法
Java不提供克隆(复制)对象的自动机制。
克隆对象意味着逐位复制对象的内容。
要支持克隆操作,请在类中实现clone()方法。
Object类中的clone()方法的声明如下:
protected Object clone() throws CloneNotSupportedException
clone()方法声明为protected。因此,我们不能从客户端代码调用它。以下代码无效:
Object obj = new Object(); Object clone = obj.clone(); // Error. Cannot access protected clone() method
我们需要在类中声明clone()方法public克隆类的对象。
它的返回类型是Object。这意味着您将需要转换clone()方法的返回值。
假设MyClass是可克隆的。克隆代码将如下所示:
MyClass mc = new MyClass(); MyClass clone = (MyClass)mc.clone(); // Need to use a cast
Object类中的clone()方法会抛出CloneNotSupportedException。
要调用clone()方法,我们需要将调用放在try-catch块中,或者重新抛出异常。
例子
以下代码显示了如何实现克隆方法。
class MyClass implements Cloneable { private double value; public MyClass(double value) { this.value = value; } public void setValue(double value) { this.value = value; } public double getValue() { return this.value; } public Object clone() { MyClass copy = null; try { copy = (MyClass) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copy; } } public class Main { public static void main(String[] args) { MyClass dh = new MyClass(100.00); MyClass dhClone = (MyClass) dh.clone(); System.out.println("Original:" + dh.getValue()); System.out.println("Clone :" + dhClone.getValue()); dh.setValue(200.00); dhClone.setValue(400.00); System.out.println("Original:" + dh.getValue()); System.out.println("Clone :" + dhClone.getValue()); } }
上面的代码生成以下结果。
Original:100.0
Clone :100.0
Original:200.0
Clone :400.0
例2
以下代码不从clone方法返回对象类型,该方法仅在Java 5或更高版本中编译。
class MyClass implements Cloneable { public MyClass clone() { Object copy = null; return (MyClass)copy; } }
下面的代码展示了如何做浅层克隆。
class MyClass implements Cloneable { private double value; public MyClass(double value) { this.value = value; } public void setValue(double value) { this.value = value; } public double getValue() { return this.value; } public Object clone() { MyClass copy = null; try { copy = (MyClass) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copy; } } class ShallowClone implements Cloneable { private MyClass holder = new MyClass(0.0); public ShallowClone(double value) { this.holder.setValue(value); } public void setValue(double value) { this.holder.setValue(value); } public double getValue() { return this.holder.getValue(); } public Object clone() { ShallowClone copy = null; try { copy = (ShallowClone) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copy; } } public class Main { public static void main(String[] args) { ShallowClone sc = new ShallowClone(100.00); ShallowClone scClone = (ShallowClone) sc.clone(); System.out.println("Original:" + sc.getValue()); System.out.println("Clone :" + scClone.getValue()); sc.setValue(200.00); System.out.println("Original:" + sc.getValue()); System.out.println("Clone :" + scClone.getValue()); } }
上面的代码生成以下结果。
例3
ShallowClone类的clone()方法中的代码与MyClass类的clone()方法相同。
当ShallowClone类使用super.clone()调用Object类的clone()方法时,它会接收自身的浅拷贝。也就是说,它与其克隆共享其实例变量中使用的DoubleHolder对象。
在深层克隆中,您需要克隆对象的所有引用实例变量引用的所有对象。
class MyClass implements Cloneable { private double value; public MyClass(double value) { this.value = value; } public void setValue(double value) { this.value = value; } public double getValue() { return this.value; } public Object clone() { MyClass copy = null; try { copy = (MyClass) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copy; } } class DeepClone implements Cloneable { private MyClass holder = new MyClass(0.0); public DeepClone(double value) { this.holder.setValue(value); } public void setValue(double value) { this.holder.setValue(value); } public double getValue() { return this.holder.getValue(); } public Object clone() { DeepClone copy = null; try { copy = (DeepClone) super.clone(); copy.holder = (MyClass) this.holder.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return copy; } } public class Main { public static void main(String[] args) { DeepClone sc = new DeepClone(100.00); DeepClone scClone = (DeepClone) sc.clone(); System.out.println("Original:" + sc.getValue()); System.out.println("Clone :" + scClone.getValue()); sc.setValue(200.00); System.out.println("Original:" + sc.getValue()); System.out.println("Clone :" + scClone.getValue()); } }
上面的代码生成以下结果。
Java Object.Finalize方法
Java面向对象设计 - Java Object.Finalize方法
Java提供了一种在对象即将被销毁时执行资源释放的方法。
在Java中,我们创建对象,但是我们不能销毁对象。
JVM运行一个称为垃圾收集器的低优先级特殊任务来销毁不再引用的所有对象。
垃圾回收器给我们一个机会,在对象被销毁之前执行清理代码。
Object类有一个finalize()方法,声明如下:
protected void finalize() throws Throwable { }
Object类中的finalize()方法不会做任何事情。
你需要覆盖你的类中的方法。
您的类的finalize()方法将在您的类的对象销毁之前由垃圾回收器调用。
例子
以下代码显示了如何创建一个Finalize类覆盖对象类的finalize()方法。
class Finalize { private int x; public Finalize(int x) { this.x = x; } public void finalize() { System.out.println("Finalizing " + this.x); } } public class Main { public static void main(String[] args) { for (int i = 0; i < 20000; i++) { new Finalize(i); } } }
上面的代码生成以下结果。
Java Immutable(不可变)对象
Java面向对象设计 - Java不可变对象
在创建状态后无法更改其状态的对象称为不可变对象。
一个对象不可变的类称为不可变类。
不变的对象可以由程序的不同区域共享而不用担心其状态改变。
不可变对象本质上是线程安全的。
例子
以下代码创建了不可变类的示例。
public class IntWrapper { private final int value; public IntWrapper(int value) { this.value = value; } public int getValue() { return value; } }
注意
这是如何创建IntWrapper类的对象:
IntWrapper wrapper = new IntWrapper(101);
在这一点上,包装器对象保持101,并且没有办法改变它。
因此,IntWrapper类是一个不可变的类,它的对象是不可变的对象。
最好将所有实例变量声明为final,这样Java编译器将在编译期间强制实现不可变性。
Java Objects类
Java面向对象设计 - Java Objects类
Java在java.util包中有一个实用程序类Objects用于处理对象。
它由所有静态方法组成。 Objects类中的大多数方法都会优雅地处理空值。
以下是类中的方法列表。他们的描述遵循列表。
- int compare(T a, T b, Comparator c)
如果参数相同,则返回0,否则返回c.compare(a,b)。因此,如果两个参数都为null,则返回0。 - boolean deepEquals(Object a, Object b)
检查两个对象是否相等。如果两个参数都相等,则返回true。否则,它返回false。如果两个参数都为null,则返回true。 - boolean equals(Object a, Object b)
比较两个对象是否相等。如果两个参数相等,则返回true。否则,它返回false。如果两个参数都为null,则返回true。 - int hash(Object... values)
为所有指定的对象生成哈希码。它可以用于计算对象的哈希码,该哈希码基于多个实例字段。 - int hashCode(Object o)
返回指定对象的哈希码值。如果参数为null,则返回0。 - boolean isNull(Object obj)
如果指定的对象为null,isNull()方法返回true。否则,它返回false。您还可以使用比较运算符==检查对象是否为null,例如,obj == null返回obj的true为null。 - boolean nonNull(Object obj)
执行与isNull()方法相反的检查。 - T requireNonNull(T obj)
T requireNonNull(T obj, String message)
T requireNonNull(T obj, Supplier messageSupplier)
检查参数是否为null。如果参数为null,它会抛出一个NullPointerException异常。此方法设计用于验证方法和构造函数的参数。
第二个版本可以指定当参数为null时抛出的NullPointerException的消息。
第三个版本的方法将一个Supplier作为第二个参数。 - String toString(Object o)
String toString(Object o, String nullDefault)
如果参数为null,则toString()方法返回一个“null”字符串。对于非空参数,它返回通过调用参数的toString()方法返回的值。
HashCode
下面的代码演示了如何使用来自Objects类的方法来计算哈希码。
import java.util.Objects; public class Main { public static void main(String[] args) { // Compute hash code for two integers, a char, and a string int hash = Objects.hash(10, 800, "\u20b9", "Hello"); System.out.println("Hash Code is " + hash); } }
上面的代码生成以下结果。
equals
以下代码显示了如何使用Objects类中的equals方法来比较两个对象。
import java.util.Objects; public class Main { public static void main(String[] args) { // Test for equality boolean isEqual = Objects.equals(null, null); System.out.println("null is equal to null: " + isEqual); isEqual = Objects.equals(null, "XYZ"); System.out.println("null is equal to XYZ: " + isEqual); } }
上面的代码生成以下结果。
toString
以下代码显示如何使用toString方法从对象将对象转换为字符串。
import java.util.Objects; public class Main { public static void main(String[] args) { // toString() method test System.out.println("toString(null) is " + Objects.toString(null)); System.out.println("toString(null, \"XXX\") is " + Objects.toString(null, "XXX")); } }
上面的代码生成以下结果。
requireNonNull
以下代码显示如何使用Objects类中的requireNonNull。
import java.time.Instant; import java.util.Objects; import java.util.function.Supplier; public class Main { public static void main(String[] args) { try { printName("A"); printName(null); } catch (NullPointerException e) { System.out.println(e.getMessage()); } try { Supplier<String> messageSupplier = () -> "Name is required. Error generated on " + Instant.now(); printNameWithSuplier("asdf", messageSupplier); printNameWithSuplier(null, messageSupplier); } catch (NullPointerException e) { System.out.println(e.getMessage()); } } public static void printName(String name) { Objects.requireNonNull(name, "Name is required."); System.out.println("Name is " + name); } public static void printNameWithSuplier(String name, Supplier<String> messageSupplier) { Objects.requireNonNull(name, messageSupplier); } }
上面的代码生成以下结果。