1. Class and Object (Instance)

    • A class is a blueprint for creating objects; an object is an instance of that blueprint.
    • A circle requires a center point and a radius, which become the Circle class’s data fields.
    • The center point is modeled as a Point class encapsulating x and y coordinates.
  2. Access Modifiers (public, private, package-default, protected)

    • private: Members are accessible only within their class. Instance variables should be private to maintain data integrity (bank account analogy).
    • public: Members are accessible from any class. Common for methods (like getters) that expose controlled access to private data. The main method must be public for the Java runtime to invoke it.
    • package (default): If no modifier is specified, the member is accessible only within the same package. (BTW, don’t include package declarations from some IDEs when submitting to OJ.)
    • protected: Mentioned in the context of inheritance (will be covered in a future lecture). Members are accessible to subclasses.
  3. Method Overriding vs. Overloading

    • Overriding: A subclass provides a specific implementation for a method defined in its parent. Example: overriding toString() in Point to return readable coordinates instead of a memory address.
    • Overloading: Multiple methods in the same class share a name but differ in parameters (number, type). Circle demonstrates this with two constructors: one taking a Point and a double (radius), and another taking three Point objects. The compiler selects the appropriate method based on arguments.
  4. A final variable cannot change after initialization, enabling immutable objects (e.g., fixed point coordinates).

  5. The static Keyword

    • static members belong to the class, not instances.
    • Static Variable: private static int count = 0; tracks the total number of Circle objects, incremented in each constructor and shared across instances.
    • Static Method: public static int getCount() returns the current count.
    • Static Context Constraint: Static methods cannot access instance members directly. E.g., attempting to access instance variable r in the static method getCount() causes a compiler error because no specific object instance is available.
  6. Implementation of the Class

    • Always use double to represent real numbers in Java as it has higher precision than float.
    • this is used when parameter names match instance variables (e.g., this.x = x;). Here, this.x references the field, x references the parameter. If parameters use different names (e.g., init_x), assignments like x = init_x; do not require this.
    • Handling Floating-Point Precision: Avoid direct equality checks (==) with double. Use a small tolerance EPS (epsilon) (e.g., $10^{-6}$).
  7. Code for the Robust Circle, throwing exception is not required in the simple Circle problem:

    class Point {
        private final double x;
        private final double y;
    
        public double getX() {
            return x;
        }
        public double getY() {
            return y;
        }
    
        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    
        @Override
        public String toString() {
            return x + " " + y;
        }
    
        public double dis(Point o) {
            double dx = x - o.x;
            double dy = y - o.y;
            return Math.hypot(dx, dy);
        }
    
        public static double dis(Point a, Point b) {
            double dx = a.x - b.x;
            double dy = a.y - b.y;
            return Math.hypot(dx, dy);
        }
    }
    class InvalidRadiusException extends Exception {
        public InvalidRadiusException() {
            super();
        }
    }
    
    class CollinearPointsException extends Exception {
        public CollinearPointsException() {
            super();
        }
    }
    
    public class Circle {
        private final Point c;
        private final double r;
        private static int cnt = 0;
    
        // public static void main(String[] args)
        // {
        // 	Point a = new Point(0.0, 0.1);
        // 	Point b = new Point(1.0, 2.0);
        //
        // 	a.dis(b);
        // 	Point.dis(a, b);
        // }
    
        public static int getCnt() {
            return cnt;
        }
    
        public Point getCenter() {
            return c;
        }
        public double getR() {
            return r;
        }
    
        public Circle(Point c, double r) throws Exception {
            if (c == null)
                throw new NullPointerException();
            if (r <= 0)
                throw new InvalidRadiusException();
            this.c = c;
            this.r = r;
            cnt++;
        }
        public Circle(Point a, Point b, Point c) throws Exception {
            if (a == null || b == null || c == null)
                throw new NullPointerException();
            double x1 = a.getX(), y1 = a.getY();
            double x2 = b.getX(), y2 = b.getY();
            double x3 = c.getX(), y3 = c.getY();
    
            double EPS = 1e-6;
            double D = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
            if (Math.abs(D) < EPS)
                throw new CollinearPointsException();
    
            double sq1 = x1 * x1 + y1 * y1;
            double sq2 = x2 * x2 + y2 * y2;
            double sq3 = x3 * x3 + y3 * y3;
    
            double Ux = (sq1 * (y2 - y3) + sq2 * (y3 - y1) + sq3 * (y1 - y2)) / D;
            double Uy = (sq1 * (x3 - x2) + sq2 * (x1 - x3) + sq3 * (x2 - x1)) / D;
    
            Point U = new Point(Ux, Uy);
            double R = U.dis(a);
            if (R <= 0)
                throw new InvalidRadiusException();
            this.c = U;
            r = R;
            cnt++;
        }
    
        public double circumference() {
            return Math.PI * 2 * r;
        }
    
        public double area() {
            return Math.PI * r * r;
        }
    
        public Boolean joins(Circle o) throws Exception {
            if (o == null)
                throw new NullPointerException();
            double EPS = 1e-6;
            double d = c.dis(o.c);
            return (Math.abs(r - o.r) <= d + EPS) && (d <= r + o.r + EPS);
        }
    }