`
yanricheng
  • 浏览: 37141 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

如何避免陷阱并正确的重载Object类中的方法

阅读更多

[转载]     How to avoid traps and correctly override methods from java.lang.Object   

Avoid incorrect implementations and bugs by following these guidelines

All Java classes eventually have java.lang.Object, hereafter referred to simply as Object, as a base class. Because of this, all Java classes inherit methods from Object. Half of these methods are final and cannot be overridden. However, the other methods in Object can be and are overridden, often incorrectly. This article explains why it's important to implement these methods correctly and then explains how to do so.

Object declares three versions of the wait method, as well as the methods notify, notifyAll and getClass. These methods all are final and cannot be overridden. This article discusses the remaining methods that are not final and that often must be overridden:

  • clone
  • toString
  • equals
  • hashCode
  • finalize


I'll discuss the clone method first, as it provides a nice collection of subtle traps without being excessively complicated. Next, I'll consider equals and hashCode together. These are the most difficult to implement correctly. Wrapping up the article, I'll describe how to override the comparatively simple toString and finalize methods.

Why this matters

Why is it important to implement these methods correctly? In a small application written, used, and maintained by one individual, it may not be important. However, in large applications, in applications maintained by many people and in libraries intended for use by other people, failing to implement these methods correctly can result in classes that cannot be subclassed easily and that do not work as expected.

It is, for example, possible to write the clone method so that no child classes can be cloned. This will be a problem for users who want to extend the class with the improperly written clone method. For in-house development this mistake can result in excess debug time and rework when the problem is finally discovered. If the class is provided as part of a class library you sell to other programmers, you may find yourself rereleasing your library, handling excess technical support calls, and possibly losing sales as customers discover that your classes can't be extended.

Erroneous implementations of equals and hashcode can result in losing elements stored in hashtables. Incorrect implementation of these methods can also result in intermittent, data-dependent bugs as behavior changes over time. Again, this can result in excess debugging and extra software releases, technical support calls, and possibly lost sales. Implementing toString improperly is the least damaging, but can still result in loss of time, as you must debug if the name of the object is wrong.

In short, implementing these methods incorrectly can make it difficult or impossible for other programmers to subclass and use the classes with the erroneous implementation. Less serious, but still important, implementing these methods incorrectly can result in time lost to debugging.

Two themes

Two themes will reappear throughout this article. The first theme is that you must pay attention to whether your implementations of these methods will continue to be correct in child classes. If not, you should either rewrite your implementations to be correct in child classes or declare your class to be final so that there are no child classes.  

 

 

The second theme is that methods have contracts -- defined behavior -- and when implementing or overriding a method, the contract should be fulfilled. The equals method of Object provides an example of a contract: the contract states that if the parameter to equals is null, then equals must return false. When overriding equals, you are responsible for ensuring that all the specifics of the contract are still met.

Implementing clone

The clone method allows clients to obtain a copy of a given object without knowing the precise class of the original object. The clone method in Object is a magic function that generates a shallow copy of the entire object being cloned.

To enable shallow cloning of your class, you implement the Cloneable interface. (For a full discussion of shallow copying versus deep copying, see the sidebar below.) Since Cloneable is a tagging interface with no methods, it's simple to implement:

    public class BaseClass implements Cloneable
    {
        // Rest of the class.

// Notice that you don't even have to write the clone method! }



clone is a protected method. If you want objects from other packages to be able to call it, you must make clone public. You do this by redeclaring clone and then calling the superclass's clone method:

    public class BaseClass implements Cloneable
    {
        // Rest of the class.

public Object clone () throws CloneNotSupportedException { return super.clone(); } }



Finally, if you want some of the member data in the class to be copied deeply, you must copy these members yourself:

    public class BaseClass implements Cloneable
    {
        // SomeOtherClass is just an example.  It might look like
        // this:
        //
        //     class SomeOtherClass implements Cloneable
        //     {
        //         public Object clone () 
                        throws CloneNotSupportedException
        //         {
        //             return super.clone();
        //         }
        //     }
        //
        private SomeOtherClass data;

// Rest of the class.
public Object clone () throws CloneNotSupportedException { BaseClass newObject = (BaseClass)super.clone();
// At this point, newObject shares the SomeOtherClass // object referred to by this.data with the object // running clone. If you want newObject to have its own // copy of data, you must clone this data yourself.

if (this.data != null) newObject.data = (SomeOtherClass)this.data.clone();
return newObject; } }



That's it. So, what mistakes should you look out for?

  1. Don't fail to implement the Cloneable interface if you want your class to be cloneable. The clone method from Object checks that the Cloneable interface has been implemented. If the Cloneable interface hasn't been implemented, a CloneNotSupportedException is thrown when clone is called.

  2. Don't implement clone by using a constructor. The javadoc for the clone method states that it:

    Creates a new object of the same class as this object. It then initializes each of the new object's fields by assigning it the same value as the corresponding field in this object. No constructor is called.


    Notice that "no constructor is called." Avoid implementing clone as follows:

        public class BaseClass implements Cloneable
        {
            public BaseClass (/* parameters */)
            {
                // Code goes here...
            }
    
    // Rest of the class.
    public Object clone () throws CloneNotSupportedException { return new BaseClass (/* parameters */); } }


    There are two reasons to avoid such an approach: First, the contract for clone states that no constructor is called. Second, and more importantly, child classes now return the wrong type from clone. In the example below, the object returned by clone is a BaseClass, not a ChildClass!

        public class ChildClass extends BaseClass
        {
            // Use clone from BaseClass
        }
    


    Further, the child class cannot override clone to make a deep copy of the member variables in the ChildClass. The following code demonstrates this problem:

        public class ChildClass extends BaseClass
        {
            private SomeOtherClass data; 
    
    // Rest of the class.
    public Object clone () throws CloneNotSupportedException { // The cast in the line below throws an exception! // ChildClass newObject = (ChildClass)super.clone();
    // You _never_ get here because the line above throws // an exception. if (this.data != null) newObject.data = (SomeOtherClass)this.data.clone();
    return newObject; } }


    The first line in clone throws an exception because the clone method in BaseClass returns a BaseClass object not a ChildClass object.

    Summary: Don't implement clone by using a copy constructor.

  3. Avoid using constructors to copy subobjects when possible. Another mistake is to use constructors to copy subobjects when implementing clone. Consider the following example class, which uses Dimension as the subobject:

        import java.awt.Dimension;
    
    public class Example implements Cloneable { private Dimension dim;
    public void setDimension (Dimension dim) { this.dim = dim; }
    public Object clone () throws CloneNotSupportedException { Example newObject = (Example)super.clone();
    // Notice the use of a constructor below instead of // a clone method call. If you have a sub-class of // Dimension, any data in the sub-class (e.g. a third // dimension value like z) will be lost. // if (this.dim != null) newObject.dim = new Dimension (dim);
    return newObject; } }


    If a child class of Dimension is passed to setDimension, the object returned by clone will be different from the original object. The preferred way to write this clone method would be:

        import java.awt.Dimension;
    
    public class Example implements Cloneable { private Dimension dim;

    public void setDimension (Dimension dim) { this.dim = dim; }
    public Object clone () throws CloneNotSupportedException { Example newObject = (Example)super.clone();
    // Call 'this.dim.clone()' instead of // 'new Dimension(dim)' // if (this.dim != null) newObject.dim = (Dimension)this.dim.clone();
    return newObject; } }


    Now, if a child class of Dimension is passed to setDimension, it is copied properly when clone is called.

    Unfortunately, while the preferred code above compiles under the Java 2 platform (formerly known as JDK 1.2), it won't compile under JDK 1.1.7. Dimension doesn't implement Cloneable in JDK1.1 and the clone method for Dimension is protected so Example can't call it anyway. This means that under JDK 1.1 you must write Example's clone method using a copy constructor for the Dimension member variable even though you don't want to. If a child of Dimension is passed to setDimension, you'll have a problem if you try to clone an Example object.   

  4. Testing explicitly for Dimension in the clone method is one workaround:

        import java.awt.Dimension;
    
    public class Example implements Cloneable { private Dimension dim;
    public void setDimension (Dimension dim) { this.dim = dim; }
    public Object clone () throws CloneNotSupportedException { Example newObject = (Example)super.clone();
    if (this.dim != null) { // Test explicitly for Dimension here. Don't test // using the instanceof operator -- it doesn't do // what you want it to. // if (this.dim.getClass() != Dimension.class) throw new CloneNotSupportedException("Wrong sub-class for 'dim'");
    newObject.dim = new Dimension (dim); } return newObject; } }



    This is better than returning a clone object with the wrong data for dim, but it still isn't a good solution.

    Summary: Make copies of member variables using their clone methods if possible.

  5. Pay attention to synchronization on the clone method. clone is a method just like any other. In a multithreaded environment you want to synchronize clone so that the underlying object stays internally consistent while being copied. You must then also synchronize the mutator methods. Note that this is different from a constructor, which almost never needs synchronization.

  6. Sometimes you should treat clone like a constructor. Even though the clone method isn't a constructor, sometimes you should treat it like one. If you do something special in each constructor, like incrementing an "objects created" count, you probably want to do the same thing in the clone method.

  7. Classes used by others should usually implement clone. This is most important when the class is part of a class library used by others who don't have access to the source code. Failing to implement the clone method can cause problems for clients attempting to write their own clone methods -- see the problems with Dimension in (2) above. If you're producing a third-party library, don't force your customers to work around a lack of cloning.

    If you're not producing a third-party library, waiting to implement clone until it's needed for each class is reasonable. This is especially true because once you've overridden clone, you must pay careful attention to overriding clone in all the child classes.

  8. Child classes must pay attention to clone methods inherited from parent classes. Well-written third-party library classes will often implement clone. However, once a class becomes cloneable, that class's children become cloneable, too. If you extend a class that is cloneable, you must consider whether the clone method you inherit (which will make a shallow copy of all of the data in your subclass) does what you want it to. If it doesn't, you must override clone.



    Implementing equals and hashCode

    Because of their contracts, if you override either the equals or hashCode methods from Object, you must almost certainly override the other method as well. The complicated contracts that go with these methods make overriding them correctly very difficult. Some of the code shipped with the standard Java libraries gets it wrong.

    Here are the important contract requirements for the two methods, as documented in the javadoc documentation for java.lang.Object:

    1. The hashCode method must return the same integer value every time it is invoked on the same object during the entire execution of a Java application or applet. It need not return the same value for different runs of an application or applet. The Java 2 platform (Java 2) documentation further allows the hashCode value to change if the information used in the equals method changes.

    2. If two objects are equal according to the equals method, they must return the same value from hashCode.

    3. The equals method is reflexive, which means that an object is equal to itself: x.equals(x) should return true.

    4. The equals method is symmetric: If x.equals(y) returns true, then y.equals(x) should return true also.

    5. The equals method is transitive: If x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.

    6. The equals method is consistent. x.equals(y) should consistently return either true or false. The Java 2 javadoc clarifies that the result of x.equals(y) can change if the information used in the equals comparisons change.

    7. Finally, x.equals(null) should return false.


    Object provides a simple implementation of equals. It just tests the two objects for referential equality: does x equal y? Some of the standard Java classes override this to provide a more useful notion of equality -- usually content equality (i.e., is some or all of the data in the two objects identical?).

    The equals implementation of java.lang.String, for example, returns true if the two objects are both String objects containing exactly the same characters in exactly the same order. The equals method of java.awt.Dimension returns true if the passed-in object is a dimension with the same width and height as the Dimension object executing the equals method.

    The default implementation of hashCode provided by Object returns something corresponding to the object's address in memory or location in the Java virtual machine's global object array. Again, some of the standard Java classes override this method.

    String, for example, overrides the hashCode implementation in Object to return a hash of some or all of the characters making up the String. This allows two String objects with the same characters in the same order to return the same hash value. Dimension uses the hashCode method provided by Object.

    Now for the bad news: It's almost impossible to override equals and hashCodefor mutable classes and provide useful, correct and safe implementations for both methods.  

 

To see why, consider the class java.awt.Dimension. This class overrides equals, but not hashCode. Dimension's JDK 1.1 implementation of equals looks like this:

    public boolean equals(Object obj)
    {
        if (obj instanceof Dimension)
        {
            Dimension d = (Dimension)obj;
            return (width == d.width) && (height == d.height);
        }

return false; }



This is a fairly reasonable implementation of content equality: if two Dimension objects have the same width and height they're equal, otherwise they aren't. So, what's wrong?

The first problem is that because Dimension doesn't override hashCode, it's possible to have two Dimension objects that are equal, but return different hashCode values. This violates requirement (2) from above.

Second, testing the input parameter using instanceof Dimension creates problems of its own. Consider a child class: ThreeDeeDimension. Objects of type ThreeDeeDimension should test as equal only if they have identical height, width and depth. ThreeDeeDimension might look like this:

    import java.awt.Dimension;

public class ThreeDeeDimension extends Dimension { // I don't like public data, but I'll make this public // to be similar to Dimension's width and height. // public int depth;
public ThreeDeeDimension (int width, int height, int depth) { super (width, height); this.depth = depth; }
public boolean equals (Object o) { if ((super.equals (o) == true) &&(o.getClass().equals(this.getClass()))) return ((ThreeDeeDimension)o).width == this.width; else return false; } }



Unfortunately, this implementation of equals doesn't meet requirement (4) listed above. The following code snippet shows this:

    import java.awt.Dimension;

public class Main { static public void main (String[] args) { Dimension dim = new Dimension (1, 2); ThreeDeeDimension threeDeeDim = new ThreeDeeDimension (1, 2, 3);
// This will print out that the two objects are equal. System.out.println ("dim.equals(threeDeeDim) = " +dim.equals(threeDeeDim));
// And this will print out that the two objects are not equal. System.out.println ("threeDeeDim.equals(dim) = " +threeDeeDim.equals(dim));
// And requirement (4) is that both tests should return the // same result. } }



I can fix this problem by rewriting the equals method of Dimension. If I write equals in Dimension like this, the ThreeDeeDimension class above meets requirement (4):

    public boolean equals(Object obj)
    {       
        if (obj != null && (obj.getClass().equals(this.getClass())))
        {
            Dimension d = (Dimension)obj;
            return (width == d.width) && (height == d.height);
        }

return false; }



Now, objects of type ThreeDeeDimension won't return true when compared to objects of type Dimension. You still have a problem with both Dimension and ThreeDeeDimension because they don't meet requirement (2): objects that test as equal should have identical hashCode values. So, how is content-equality implemented in mutable classes? One example with both equals and hashCode is:

    public class MutableExample
    {
        private int x;

// Constructors and other methods.
public boolean equals (Object o) { // Test for null to meet requirement (7) and also to // avoid a NullPointerException when calling getClass() // below. // // Comparing classes ensures that parent class objects won't test // equal to child class objects. Parent objects should almost // never test equal to child objects. This makes meeting requirements // (4) and (5) possible. // if ((o != null) && (o.getClass().equals(this.getClass()))) { // If you were inheriting directly from a class that // overrode equals, you would insert a line here that // looked like this: // if (super.equals (o) == false) // return false; // // If overriding the equals method from Object, don't // call super.equals(). //
// This is the point. We have already tested the equality // of our parent class. Now we test for equality of the // data added by _this_ child class. This also meets requirement (3).
return ((MutableExample)o).x == this.x; }
return false; }
public int hashCode () { // This meets requirements (1) and (2). You always return the // same value for each object because you always return the // same value for all objects. You also return identical // hashCode values when two objects test as equals because // you always return identical hashCode values. There is no // requirement to return different hashCode values when // two objects test as not equal. // // The only real problem with this implementation is that it // is an almost totally useless implementation of hashCode. // It can turn a Hashtable lookup into a linear search. // // With JDK 1.1 you can't return 'x', because it can change // and the requirements for hashCode are that the same value // must be returned each time hashCode is called on the same object. // // Java 2 (formerly JDK 1.2) allows 'return x'; because Java 2 allows the hashCode // value to change if the underlying data changes. This is more // friendly, but still allows data to be lost in hashtables // if the underlying hashCode value changes. // return 0; } }



This implementation meets all the requirements, including requirement (6) with the clarification provided by Java 2.

Immutable classes make implementing a useful and safe hashCode easier. In this case, you can use the data in the class to generate a hash value because that data will never change. In the example above, if "x" was guaranteed to never change, I could have implemented hashCode like this:

    public int hashCode()
    {
        // Legal, useful and safe, but only because 'x' never changes.
        //
        return x;
    }



The key points to remember when implementing equals and hashCode:

  • These are not simple methods to implement. There are many details specified in each method's contract.

  • You must implement these two methods together. You can rarely implement just one of them.

  • It is difficult to implement a correct, useful, and safe hashCode method for mutable classes. Making classes immutable makes implementing the hashCode and equals methods much easier. Java 2 allows the value returned by hashCode to change if the underlying data changes, but you should be wary of doing this because data can then be stranded in hashtables.

  • You must pay attention to inheritance, especially when implementing equals. This means comparing classes with getClass rather than with instanceof.

  • Once a class has overridden equals and hashCode, the child classes may also require their own implementations.



Implementing toString

The toString method is the easiest of all the methods in Object to override correctly. This is because the contract is so loosely defined. The javadoc for toString reads:

[toString] returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object. The result should be a concise but informative representation that is easy for a person to read. It is recommended that all subclasses override this method.

The toString method for class Object returns a string consisting of the name of the class of which the object is an instance, the at-sign character `@', and the unsigned hexadecimal representation of the hash code of the object.



All of the above requirements are fuzzy. The method must return a "string representation" that in general "textually represents" the objects and should be "concise," but "informative." None of these requirements are as precise as the requirements for clone, hashCode or equals. Nevertheless, it is still possible to implement this method somewhat incorrectly. Consider the following example:

    public class BaseClass
    {
        private int x;

// Constructors and other member data and methods ...
public String toString() { // This implementation is not quite correct.
return "BaseClass[" + x + "]"; } }



Calling toString on objects of this class will result in output that looks something like this (assuming x equals 4):

    BaseClass[4]



The problem here is that someone might extend BaseClass and might not override toString. An example of this is:

    public class Extension extends BaseClass
    {
        // Constructors, member data and methods ...
    }



Now, calling toString on objects of class Extension results in output that looks like this:

    BaseClass[4]



The class name reported by toString is wrong! The object is an Extension object and the toString method is reporting it as a BaseClass object. You could blame the Extension class for not implementing toString itself, but the contract for toString only recommends that child classes implement their own version. There is no requirement that child classes do so.

Instead, you should write toString in BaseClass so that it behaves correctly in child classes. You can do this by writing the toString implementation like this:

    public String toString()
    {
        // This implementation behaves properly in child classes.

return getClass().getName() + "[" + x + "]"; }



Now calling toString on objects of class Extension results in this output:

    Extension[4]



which is correct.

Implementing finalize

There are only three relatively simple things to remember if you choose to override finalize. First, you should call the finalize method of the parent class in case it has cleanup to do.   

 

    protected void finalize() throws Throwable
    {
        super.finalize();
    }



Second, you should not depend on the finalize method being called. There is no guarantee of when (or if) objects will get garbage collected and thus no guarantee that the finalize method will be called before the running program exits. Finally, remember that code in finalize might fail and throw exceptions. You may want to catch these so the finalize method can continue.

    protected void finalize() throws Throwable
    {
        try
        {
            // Do stuff here to clean up your object.
        }
        catch (Throwable t)
        {
        }

super.finalize(); }



In general, finalize doesn't need to be overridden.

Conclusion

There are traps to overriding all of the nonfinal methods inherited from java.lang.Object. Some of them are subtle enough that even classes provided in the core Java libraries get them wrong. Nevertheless, with a bit of care, you can implement the methods correctly.

When building large products and when constructing third-party class libraries, it is important to take the care needed to get these implementations right. After all, some developer might read the documentation and assume your code does what the documentation says. Failing to implement these methods correctly for large projects can result in extra time spent debugging. When implementing these methods in libraries sold commercially, it is even more important to implement these methods correctly; you cannot easily fix things once the library has been released. Failing to implement these methods properly can result in your library being harder to use and extend than it should be. Finally, for smaller projects, it can sometimes be reasonable to meet most, but not all, of the requirements for these methods. In those cases you should at least make your decision consciously and document it.

Author Bio

Mark Roulo has been programming professionally since 1989 and has been using Java since the alpha-3 release. He has been programming almost exclusively in Java for the past few years. His interests include portable, multithreaded, and distributed programming.

分享到:
评论

相关推荐

    java面试中的陷阱java面试中的陷阱

    - **Overloading**:在同一类中,方法名相同但参数列表不同(包括参数类型、个数或顺序不同),这种情况称为方法重载。重载提高了代码的复用性。 - **Overriding**:发生在子类中重写父类的方法。重写要求子类中的...

    Java Scjp 陷阱大全.doc

    18. **Dictionary与Hashtable**:`Dict`类在Java中并未定义,可能是笔误,但`Hashtable`是一个古老的同步的键值对存储类,实现了`Dictionary`接口。 这些知识点涵盖了Java语言的基础语法、面向对象特性、异常处理、...

    如何在Java中避免equals方法的隐藏陷阱(上)

     本文描述重载equals方法的技术,这种技术即使是具现类的子类增加了字段也能保证equal语义的正确性。  在《Effective Java》的第8项中,Josh Bloch描述了当继承类作为面向对象语言中的等价关系的基础问题,要...

    Java面试中的陷阱

    - **重载**(Overloading):在同一类中,多个同名方法但参数列表不同(参数个数、类型或顺序不同),这些方法之间相互独立,可以根据传入的不同参数调用相应的方法版本。 - **重写**(Overriding):发生在子类...

    V20-Java笔记整理-重要概念和常见陷阱梳理.docx

    - **重载**:在同一类中定义多个同名方法,但参数列表不同。 - **构造器重载**:在同一个类中定义多个构造器,每个构造器的参数列表不同。 **5.5 多态** - 多态性允许程序以统一的方式处理不同的子类型对象。 - ...

    Java解惑ppt5

    《Java解惑PPT5》深入探讨了Java编程中的一些常见困惑和陷阱,特别是关于类、构造器重载以及静态域的使用。以下是对其中两个关键Puzzle的详细解析: **Puzzle 46:令人混淆的构造器** 在这个谜题中,作者展示了...

    SCJP 陷阱大全

    《SCJP陷阱大全:深入解析Java认证考试中的关键知识点》 ...通过深入了解并掌握这些知识点,开发者不仅能提高通过SCJP或类似Java认证考试的可能性,还能在日常编码实践中避免常见错误,提升代码质量和效率。

    vc编程系列之Addison Wesley - Inside the C++ Object Model

    书中介绍了如何正确地重载运算符以及需要注意的陷阱。 5. **模板**:模板是C++的泛型编程工具,允许创建不依赖特定类型的功能。函数模板和类模板分别用于泛型函数和泛型类的设计。书中详细探讨了模板的实例化、模板...

    Java陷阱一箩筐.doc

    - wait():使线程等待,释放对象锁,属于 Object 类,需要在同步环境中使用。 13. **goto**:Java 没有 goto 关键字。 14. **length()**: - 数组使用 `length` 属性获取长度。 - String 使用 `length()` 方法...

    C#中重载相等(==)运算符示例

    在C#编程中,运算符重载是一种强大的特性,允许我们自定义基本操作符的行为,如加法、减法以及本文关注的相等比较运算符`==`。...如果你决定重载`==`,确保正确处理`null`引用,并避免可能导致无限递归的逻辑。

    java面试宝典

    Java语言中并没有提供传统的`goto`语句,这是为了防止程序逻辑混乱,提高代码的可读性和维护性。虽然`goto`在C/C++等语言中很常见,但在Java中它被视为保留关键字,但并未实际使用。 #### 3\. `&`和`&&`的区别 `&`...

    Java面试宝典2011版

    `Overload`指方法重载,允许在同一个类中声明多个同名方法,只要它们的参数列表不同即可。`Override`指方法重写,是在子类中重新定义父类的方法,要求方法名、参数列表和返回类型完全一致。 ### 19. 构造器的重写 ...

    Java程序员面试宝典2011最新出炉

    Java语言中并没有传统的`goto`语句,这是为了提高代码的可读性和避免潜在的错误。但是,Java提供了标记化的`break`和`continue`语句,可以在一定程度上模拟`goto`的功能。 #### 3\. & 和 && 的区别 `&` 是位运算符...

    Exceptional C++/More Exceptional C++

    1. **异常处理(Exception Handling)**:C++中的异常处理机制是其强大的错误处理工具,允许在程序的任何地方抛出异常,并在适当的点捕获并处理。《Exceptional C++》详细讲解了如何正确使用try、catch和throw关键字...

    C#类型转换之初级篇

    ### C#类型转换之初级篇 ...了解并掌握这些转换机制不仅有助于编写更高效的代码,还能避免许多常见的编程陷阱。在实际应用中,应根据具体情况选择合适的类型转换策略,以确保程序的正确性和性能。

    程序员面试宝典(变态级Java程序员面试32问)pdf

    - **finalize**:是`Object`类中的一个方法,用于垃圾回收机制中,在对象被垃圾回收前提供最后一次机会清理资源,但不建议依赖此方法进行资源管理。 ### 2. 匿名内部类的特性 匿名内部类可以实现接口或继承其他类...

    C++ Object Oriented Programming Pei-yih Ting NTOU CS

    2. **CPP15-CommonMemoryErrors_4up.pdf**:这部分内容可能着重讲解了C++中的内存管理问题,如内存泄漏、野指针等常见错误,强调了在C++中正确管理和使用内存的重要性。 3. **CPP02-AbstractDataType_4up.pdf**:...

    More Effective C++

    4. **运算符重载(Operator Overloading)**:介绍了何时和如何安全地重载运算符,以及避免常见陷阱,如不要滥用赋值运算符(=)的重载。 5. **异常安全(Exception Safety)**:讨论了在处理异常时如何保持代码的...

    More Effecitve C++

    书中讲解了何时以及如何正确地重载运算符,同时提醒了可能导致混淆和错误的潜在陷阱。 5. **常量与引用(Constants and References)**:书中强调了常量和引用在提高代码安全性上的作用,以及如何通过它们来强制...

Global site tag (gtag.js) - Google Analytics