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.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.