/**
 Class for a simple sale of one item with no tax, discount, or other adjustments.
 Class invariant: The price is always nonnegative; the name is a nonempty string.
*/
public class Sale
{

    private String name; //A nonempty string
    private double price; //nonnegative

    public Sale( )
    {
        name = "No name yet";
        price = 0;
    }

    /**
     Precondition: theName is a nonempty string; thePrice is nonnegative.
    */
    public Sale(String theName, double thePrice)
    {
        setName(theName);
        setPrice(thePrice);
    }

    public Sale(Sale originalObject)
    {
        if (originalObject == null)
        {
            System.out.println("Error: null Sale object.");
            System.exit(0);
        }
        //else
        name = originalObject.name;
        price = originalObject.price;
    }

    public Object clone( )
    {
        return new Sale(this );
    }

    public static void announcement( )
    {
        System.out.println("This is the Sale class.");
    }

    public double getPrice( )
    {
        return price;
    }

   /**
     Precondition: newPrice is nonnegative.
    */
    public void setPrice(double newPrice)
    {
        if (newPrice >= 0)
            price = newPrice;
        else
        {
            System.out.println("Error: Negative price.");
            System.exit(0);
        }
    }

    public String getName( )
    {
        return name;
    }

    /**
     Precondition: newName is a nonempty string.
    */
    public void setName(String newName)
    {
        if (newName != null && newName != "")
            name = newName;
        else
        {
            System.out.println("Error: Improper name value.");
            System.exit(0);
        }
    }

    public String toString( )
    {
        return (name + " Price and total cost = $" + price);
    }

    public double bill( )
    {
        return price;
    }

    /*
     Returns true if the names are the same and the bill for the calling
     object is equal to the bill for otherSale; otherwise returns false.
     Also returns false if otherObject is null.
    */
    public boolean equalDeals(Sale otherSale)
    {
        if (otherSale == null)
            return false;
        else
            return (name.equals(otherSale.name)
                && bill( ) == otherSale.bill( ));
    }

    /*
     Returns true if the bill for the calling object is less
     than the bill for otherSale; otherwise returns false.
    */
    public boolean lessThan (Sale otherSale)
    {
        if (otherSale == null)
        {
            System.out.println("Error: null Sale object.");
            System.exit(0);
        }
        //else
        return (bill( ) < otherSale.bill( ));
    }

    public boolean equals(Object otherObject)
    {
        if (otherObject == null)
            return false;
        else if (getClass( ) != otherObject.getClass( ))
            return false;
        else
        {
            Sale otherSale = (Sale)otherObject;
            return (name.equals(otherSale.name)
               && (price == otherSale.price));
        }
    }
}
---------------------------------------------------------------

/**
 Class for a sale of one item with discount expressed as a percent of the price,
 but no other adjustments.
 Class invariant: The price is always nonnegative; the name is a
 nonempty string; the discount is always nonnegative.
*/
public class DiscountSale extends Sale
{
    private double discount; //A percent of the price. Cannot be negative.

    public DiscountSale( )
    {
        super( );
        discount = 0;
    }

    /**
     Precondition: theName is a nonempty string; thePrice is nonnegative;
     theDiscount is expressed as a percent of the price and is nonnegative.
    */
    public DiscountSale(String theName,
                                  double thePrice, double theDiscount)
    {
        super(theName, thePrice);
        setDiscount(theDiscount);
    }

    public DiscountSale(DiscountSale originalObject)
    {
        super(originalObject);
        discount = originalObject.discount;
    }

    public Object clone( )
    {
        return new DiscountSale(this );
    }

    public static void announcement( )
    {
        System.out.println("This is the DiscountSale class.");
    }

    public double bill( )
    {
        double fraction = discount/100;
        return (1 - fraction)*getPrice( );
    }

    public double getDiscount( )
    {
        return discount;
    }

    /**
     Precondition: Discount is nonnegative.
    */
    public void setDiscount(double newDiscount)
    {
        if (newDiscount >= 0)
            discount = newDiscount;
        else
        {
            System.out.println("Error: Negative discount.");
            System.exit(0);
        }
    }

    public String toString( )
    {
        return (getName( ) + " Price = $" + getPrice( )
                + " Discount = " + discount + "%\n"
                + "   Total cost = $" + bill( ));
    }

    public boolean equals(Object otherObject)
    {
        if (otherObject == null)
            return false;
        else if (getClass( ) != otherObject.getClass( ))
            return false;
        else
        {
            DiscountSale otherDiscountSale =
                             (DiscountSale)otherObject;
            return (super.equals(otherDiscountSale)
                && discount == otherDiscountSale.discount);
        }
   }

}

-----------------------------------------------------------------------------



/**
 Demonstrates late binding.
*/
public class LateBindingDemo
{

    public static void main(String[] args)
    {
        Sale simple = new Sale("floor mat", 10.00);//One item at $10.00.
        DiscountSale discount = new DiscountSale("floor mat", 11.00, 10);
                                 //One item at $11.00 with a 10% discount.
        System.out.println(simple);
        System.out.println(discount);

        if (discount.lessThan(simple))
            System.out.println("Discounted item is cheaper.");
        else
            System.out.println("Discounted item is not cheaper.");

        Sale regularPrice = new Sale("cup holder", 9.90);//One item at $9.90.
        DiscountSale specialPrice = new DiscountSale("cup holder", 11.00, 10);
                                 //One item at $11.00 with a 10% discount.
        System.out.println(regularPrice);
        System.out.println(specialPrice);

        if (specialPrice.equalDeals(regularPrice))
            System.out.println("Deals are equal.");
        else
            System.out.println("Deals are not equal.");
    }
}

----------------------------------------------------------------------
Static methods do not use late binding


/**
 Demonstrates that static methods use static binding.
*/
public class StaticMethodsDemo
{

    public static void main(String[] args)
    {
        Sale.announcement( );
        DiscountSale.announcement( );
        System.out.println(
             "That showed that you can override a static method definition.");

        Sale s = new Sale( );
        DiscountSale discount = new DiscountSale();
        s.announcement( );
        discount.announcement( );
        System.out.println("No surprises so far, but wait.");

        Sale discount2 = discount;
        System.out.println(
              "discount2 is a DiscountSale object in a Sale variable.");
        System.out.println( "Which definition of announcement( ) will it use?");
        discount2.announcement( );
        System.out.println(
              "It used the Sale version of announcement( )!");
   }
}