Examples of the use of inner classes in conjunction with interfaces. Downward and upward conversion. The advantages of using upward conversion.

Examples of the use of inner classes in conjunction with interfaces. Downward and upward conversion. The advantages of using upward conversion


Contents


1. The essence of the downward conversion

If the inner class InClass, which has public access, is declared in OutClass

class OutClass {
    public class InClass {
        // implementation of the class InClass
        // ...

        // implementation of methods of class InClass
        int method1() {
            // instructions
            // ...
        }

        int method2() {
            // instructions
            // ...
        }
    }
}

then in the case of a downward conversion, use the methods method1(), method2() of the class InClass according to the following scheme

// demonstration of the use of downward conversion
// create an object of class OutClass in the standard way
OutClass oc = new OutClass();

// create an object of class OutClass.InClass using the instruction .new
OutClass.InClass ic = oc.new OutClass.InClass();

So, in a downward conversion, it is important that the inner class has public access.

 

2. Features of the implementation of the upward conversion in the case of an internal private class

If you need to take advantage of the upstream conversion for the inner class, then you need to follow the steps below. For example, the internal class is considered, which should provide the client programmer with two methods for using with limited access to other types and implementations of the internal class. Methods are named method1(), method2().

The sequence of steps is as follows.

1. Declare the private-inner class InClass in the outer class OutClass

class OutClass {
    private class InClass {
        // implementation of the class InClass
        // ...

        // implementation of methods that should be available to the client programmer
        int method1() {
            // instructons
            // ...
        }

        int method2() {
            // instructions
            // ...
        }
    }
}

After such a declaration, access to the internal private class InClass has only the external class OutClass. The client programmer does not have access to the InClass class. It is also impossible to perform a downward conversion to the private class InClass by calling

OutClass oc = new OutClass();
// OutClass.InClass ic = oc.new InClass(); - error!

2. Declare interface. At this step, you need to declare the interface and select internal methods that will be available to the client programmer and also modify the declaration of the InClass class. These methods are implemented in the class InClass according to the following sample

public interface InterfaceInClass {
    // interface methods that are presented for use by the client programmer
    int method1();
    int method2();
}

class OutClass {
    // data and methods of class OutClass
    // ...

    // implementation of the class InClass with the InterfaceInClass interface methods
    private class InClass implements InterfaceInClass {
        // ...

        // implementation of interface methods
        int method1() {
            // ...
        }

        int method2() {
            // ...
        }
    }
}

In the above code, two methods are provided to the client programmer.

int method1();
int mehtod2();

The names of the methods and their parameters are chosen at random.

3. Declare a method that implements an upstream conversion. At the third stage, a method is formed in the OutClass class that returns an object of the InClass class. After these changes, the interface declaration InterfaceInClass and class OutClass will look like this:

public interface InterfaceInClass {
    // interface methods that are provided for use by the client programmer
    int method1();
    int method2();
}

class OutClass {
    // data and methods of class OutClass
    // ...

    // implementation of the class InClass based on interface methods
    private class InClass implements InterfaceInClass {
        // ...

        // implementation of interface methods
        int method1() {
            // instructions
            // ...
        }

        int method2() {
            // instructions
            // ...
        }
    }

    // OutClass class method that returns an InterfaceInClass interface object
    public InterfaceInClass GetInterfaceInClass() {
        // some instructions (may be absent)
        // ...

        return new InClass(); // return the instance of class InClass
    }
}

The above implementation of the inner class InClass in the outer class OutClass defines the essence of the upstream conversion. The object of the inner class is obtained on a bottom-up basis.

For the above example, the client programmer can use the inner class as follows:

// get an object of class OutClass
OutClass oc = new OutClass();

// using the method GetInterfaceInClass get the object ic
InterfaceInClass ic = oc.GetInterfaceInClass();

// invoke the method through the received object ic
int res;
res = ic.method1();

 

3. The advantages of using upstream conversion in conjunction with inner classes

The implementation of the upstream conversion gives the developer the following advantages:

  • direct access to internal classes is prohibited;
  • hiding all the details of the implementation of the inner class;
  • the client-programmer is given access only to the necessary (limited) implementations of the inner class;
  • it will not make sense for the client programmer to extend the interface by adding new methods, since it will not have access to additional methods that do not belong to the open part of the class;
  • the Java compiler will be able to optimize the code.

 



4. Features of the implementation of the upward conversion in the case of the internal protected-class

The upward conversion for internal protected classes works according to the same principle as for internal private classes as described in Section 2. In the case of private classes, the outer class has access to the inner class. In the case of protected-classes, access to the inner class have:

  • external class;
  • the class inherited from an external class;
  • classes of its own package, in which the outer class is declared. The protected specifier gives access within its own package.
    For protected-classes, you can make a downward conversion only from the inherited class.

 

5. An example that demonstrates a downward conversion

The external class Calculation is declared, which implements many internal classes that perform mathematical calculations on numbers. One of the inner classes is called Complex. It implements basic operations on complex numbers. As a result of the declaration, the Calculation class has the form:

// external class that contains the implementation of the Complex class
class Calculation {
    // the inner class Complex
    public class Complex {
        double real; // real part
        double imag; // imaginary part

        // method that returns the modulus of a complex number
        double Abs() {
            return Math.sqrt(real*real+imag*imag);
        }
    }
}

Using the Complex class in another method demonstrates a downward conversion.

// downward conversion
// create an object of the class Complex using the object of the Calculation class
Calculation calc = new Calculation();
Calculation.Complex comp = calc.new Complex();
double res;

comp.imag = 3;
comp.real = 5;

// invoke the method of calculating the modulus of a complex number
res = comp.Abs(); // res = 5.830951894845301

 

6. An example that demonstrates an upward conversion

Given the Calculation class, which implements the hidden (private) inner class Complex. The Complex class declares its public Abs() method using the IComplex interface. The implementation of the Calculation class and the IntComplex interface is as follows:

// interface containing the Abs() method signature
interface IntComplex {
    double Abs();
}

// outer class that contains the inner hidden class Complex
class Calculation {
    // class implements IntComplex interface, handles complex numbers
    private class Complex implements IntComplex {
        // internal data of class Complex
        private double imag; // imaginary part of a complex number
        private double real; // real part

        // class constructor with two parameters
        public Complex(double _imag, double _real) {
            imag = _imag;
            real = _real;
        }

        // implementation of the method that is declared in the  IntComplex interface
        public double Abs() {
            return Math.sqrt(real*real+imag*imag);
        }
    }

    // return the object of class Complex
    public IntComplex GetComplex(double _imag, double _real) {
        // return the object of inner class
        return new Complex(_imag, _real); // call the constructor with 2 parameters
    }
}

The GetComplex() method of the Calculation class returns an object (instance) of the inner class Complex, thereby implementing an upward conversion. When creating an object of the Complex class in the GetComplex() method, a constructor with 2 parameters is called. The following demonstrates the use of the Complex class in another method.

// upward conversion
Calculation calc = new Calculation(); // create an object of the outer class
IntComplex ic = calc.GetComplex(5, 6); // get the object of inner class
double res;

// call inner class method
res = ic.Abs(); // res = 7.810249675906654

Using the IntComplex() interface, the client programmer has access to the methods of the internal hidden class Complex. Access is via the external object of class Calculation.

 

7. What is the difference between the downward conversion and the upward conversion? Example

The difference between ascending and descending conversion is manifested in the method of obtaining an object of the inner class. In a downward conversion, an inner class object is created using the .new operator by referring to the name of the outer class object

// downward conversion
OutClass oc = new OutClass(); // create an object of the outer class
OutClass.InClass ic = oc.new InClass(); // create the object of inner class

For an upward conversion, an inner class object is obtained using a special method of the outer class, as shown below

OutClass oc = new OutClass();
OutClass.InClass ic = oc.GetObjInClass();

here GetObjInClass() – method that creates an instance of the inner class OutClass.InClass. In this case, the inner class OutClass.InClass must have public or protected access for the inherited class. In the case of the implementation of the inner class in combination with the interface, the software code of the upward transformation may look as follows:

OutClass oc = new OutClass();
InterfaceInClass ic = oc.GetInterfaceInClass();

here

  • OutClass – external class for which an object is created with the name oc;
  • InterfaceInClass – an interface that declares inner-class methods for use by a client programmer;
  • GetInterfaceInClass() – a method that returns an object (a specific instance) of the inner class OutClass.InClass(), which implements the InterfaceInClass interface.

 


Related topics