Home | | Web Programming | Constructor References - Java Lambda Expressions

Chapter: Java The Complete Reference : The Java Language : Lambda Expressions

Constructor References - Java Lambda Expressions

Similar to the way that you can create references to methods, you can create references to constructors.

Constructor References

 

Similar to the way that you can create references to methods, you can create references to constructors. Here is the general form of the syntax that you will use:

 

classname::new

 

This reference can be assigned to any functional interface reference that defines a method compatible with the constructor. Here is a simple example:

 

     //Demonstrate a Constructor reference.

 

     //MyFunc is a functional interface whose method returns

 

     //a MyClass reference.

 

interface MyFunc { MyClass func(int n);

}

 

class MyClass { private int val;

 

     //This constructor takes an argument.

     MyClass(int v) { val = v; }

 

     //This is the default constructor.

 

     MyClass() { val = 0; }

 

     ...

 

int getVal() { return val; };

 

}

 

class ConstructorRefDemo {

 

public static void main(String args[])

 

{

 

     Create a reference to the MyClass constructor.

 

     //Because func() in MyFunc takes an argument, new

 

     //refers to the parameterized constructor in MyClass,

 

     //not the default constructor.

 

     MyFunc myClassCons = MyClass::new;

 

     Create an instance of MyClass via that constructor reference.

      

     MyClass mc = myClassCons.func(100);

             

     // Use the instance of MyClass just created.

 

     System.out.println("val in mc is " + mc.getVal( ));

             

     }

             

     }

             

     The output is shown here:

 

val in mc is 100

 

In the program, notice that the func( ) method of MyFunc returns a reference of type MyClass and has an int parameter. Next, notice that MyClass defines two constructors. The first specifies a parameter of type int. The second is the default, parameterless constructor. Now, examine the following line:

 

MyFunc myClassCons = MyClass::new;

 

Here, the expression MyClass::new creates a constructor reference to a MyClass constructor. In this case, because MyFunc’s func( ) method takes an int parameter, the constructor being referred to is MyClass(int v) because it is the one that matches. Also notice that the reference to this constructor is assigned to a MyFunc reference called myClassCons. After this statement executes, myClassCons can be used to create an instance of MyClass, as this line shows:

 

MyClass mc = myClassCons.func(100);

 

In essence, myClassCons has become another way to call MyClass(int v).

 

Constructor references to generic classes are created in the same fashion. The only difference is that the type argument can be specified. This works the same as it does for using a generic class to create a method reference: simply specify the type argument after the class name. The following illustrates this by modifying the previous example so that MyFunc and MyClass are generic.

 

 

    //Demonstrate a constructor reference with a generic class.

    //MyFunc is now a generic functional interface.

 

interface MyFunc<T> { MyClass<T> func(T n);

}

 

class MyClass<T> { private T val;

 

     //A constructor that takes an argument.

     MyClass(T v) { val = v; }

 

     //This is the default constructor.

 

     MyClass( ) { val = null; }

 

...

 

T getVal() { return val; };

 

}

 

class ConstructorRefDemo2 {

 

public static void main(String args[])

 

{

 

//Create a reference to the MyClass<T> constructor.

     MyFunc<Integer> myClassCons = MyClass<Integer>::new;

 

     //Create an instance of MyClass<T> via that constructor reference.

 

     MyClass<Integer> mc = myClassCons.func(100);

 

     //Use the instance of MyClass<T> just created.

 

     System.out.println("val in mc is " + mc.getVal( ));

 

}

 

}

 

This program produces the same output as the previous version. The difference is that now both MyFunc and MyClass are generic. Thus, the sequence that creates a constructor reference can include a type argument (although one is not always needed), as shown here:

 

MyFunc<Integer> myClassCons = MyClass<Integer>::new;

 

Because the type argument Integer has already been specified when myClassCons is created, it can be used to create a MyClass<Integer> object, as the next line shows:

 

MyClass<Integer> mc = myClassCons.func(100);

 

Although the preceding examples demonstrate the mechanics of using a constructor reference, no one would use a constructor reference as just shown because nothing is gained. Furthermore, having what amounts to two names for the same constructor creates a confusing situation (to say the least). However, to give you the flavor of a more practical usage, the following program uses a static method, called myClassFactory( ), that is a factory for objects of any type of MyFunc objects. It can be used to create any type of object that has a constructor compatible with its first parameter.

 

 

// Implement a simple class factory using a constructor reference.

 

interface MyFunc<R, T> { R func(T n);

 

}

 

// A simple generic class. class MyClass<T> {

 

private T val;

 

// A constructor that takes an argument. MyClass(T v) { val = v; }

 

     //The default constructor. This constructor

 

     //is NOT used by this program.

 

MyClass() { val = null; }

 

// ...

 

T getVal() { return val; };

 

}

 

// A simple, non-generic class.

class MyClass2 {

 

String str;

 

     //A constructor that takes an argument.

     MyClass2(String s) { str = s; }

 

     //The default constructor. This

 

     //constructor is NOT used by this program.

 

     MyClass2() { str = ""; }

 

     ...

 

String getVal() { return str; };

 

}

 

class ConstructorRefDemo3 {

 

     //A factory method for class objects. The class must

 

//have a constructor that takes one parameter of type T.

 

//R specifies the type of object being created.

 

static <R,T> R myClassFactory(MyFunc<R, T> cons, T v) { return cons.func(v);

 

}

 

public static void main(String args[])

 

{

 

     //Create a reference to a MyClass constructor.

 

     //In this case, new refers to the constructor that

 

     //takes an argument.

 

MyFunc<MyClass<Double>, Double> myClassCons = MyClass<Double>::new;

 

     //Create an instance of MyClass by use of the factory method.

     MyClass<Double> mc = myClassFactory(myClassCons, 100.1);

 

     //Use the instance of MyClass just created.

 

      System.out.println("val in mc is " + mc.getVal( ));

 

     //Now, create a different class by use of myClassFactory().

 

     MyFunc<MyClass2, String> myClassCons2 = MyClass2::new;

 

//Create an instance of MyClass2 by use of the factory method.

MyClass2 mc2 = myClassFactory(myClassCons2, "Lambda");

 

// Use the instance of MyClass just created.

System.out.println("str in mc2 is " + mc2.getVal( ));

 

}

 

}

 

The output is shown here:

 

val in mc is 100.1 str in mc2 is Lambda

 

As you can see, myClassFactory( ) is used to create objects of type MyClass<Double> and MyClass2. Although both classes differ, for example MyClass is generic and MyClass2 is not, both can be created by myClassFactory( ) because they both have constructors that are compatible with func( ) in MyFunc. This works because myClassFactory( ) is passed the constructor for the object that it builds. You might want to experiment with this program a bit, trying different classes that you create. Also try creating instances of different types of MyClass objects. As you will see, myClassFactory( ) can create any type of object whose class has a constructor that is compatible with func( ) in MyFunc. Although this example is quite simple, it hints at the power that constructor references bring to Java.

 

Before moving on, it is important to mention a second form of the constructor reference syntax that is used for arrays. To create a constructor reference for an array, use this construct:

 

type[]::new

 

Here, type specifies the type of object being created. For example, assuming the form of MyClass as shown in the first constructor reference example (ConstructorRefDemo) and given the MyArrayCreator interface shown here:

 

interface MyArrayCreator<T> { T func(int n);

 

}

 

the following creates a two-element array of MyClass objects and gives each element an initial value:

 

MyArrayCreator<MyClass[]> mcArrayCons = MyClass[]::new; MyClass[] a = mcArrayCons.func(2);

 

a[0] = new MyClass(1); a[1] = new MyClass(2);

 

Here, the call to func(2) causes a two-element array to be created. In general, a functional interface must contain a method that takes a single int parameter if it is to be used to refer to an array constructor.


Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail
Java The Complete Reference : The Java Language : Lambda Expressions : Constructor References - Java Lambda Expressions |


Privacy Policy, Terms and Conditions, DMCA Policy and Compliant

Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.