Using Generics to Construct Instances of Child Classes - java

While looking at some Java 8 code I saw some use of generics that I didn't quite understand, so I wrote my own code to emulate what was going on:
public class GenericsTest {
public static void main(String[] args) {
TestBuilder tb = TestBuilder.create(Test_Child::new);
Product<Test_Child> p = tb.build();
Test tc = p.Construct("Test");
}
static class TestBuilder<T extends Test> {
private final Factory<T> f;
public TestBuilder(Factory<T> f) {
this.f = f;
}
public static <T extends Test> TestBuilder<T> create(Factory<T> f){
return new TestBuilder<>(f);
}
public Product<T> build(){
return new Product<>(f);
}
}
static class Test {
public Test(){
}
}
static class Test_Child extends Test{
public Test_Child(String s){
System.out.println("Test_Child constructed with string '"+s+"'");
}
}
interface Factory<T extends Test> {
T create(String s);
}
static class Product<T extends Test>{
private Factory<T> f;
public Product(Factory<T> f) {
this.f = f;
}
public T Construct(String s){
return f.create(s);
}
}
}
Running this prints:
Test_Child constructed with string 'Test'
What I don't understand is:
Why don't you have to provide arguments to Test_Child::new
How calling
f.create() in the Product instance refers to the
constructor of the Test_Child class.

How you don't have to provide arguments to Test_Child::new
Since its a method reference for a representation of a lamda s -> new Test_Child(s) which is possible to create as the Factory interface ends up being a FunctionalInterface by its definition.
How calling f.create() in the Product instance refers to the
constructor of the Test_Child class.
Since that's the instance type passed through the TestBuilder, to Product both having an attribute Factory<Test_Child>. It would be much clear when you rewrite the assignment as
TestBuilder<Test_Child> tb = TestBuilder.create(Test_Child::new)
To explain further as comments inlined with the code
TestBuilder tb = TestBuilder.create(Test_Child::new); TestBuilder
// TestBuilder<Test_Child> is build with a Factory<Test_Child> attribute
Product<Test_Child> p = tb.build();
// We have build a Product<Test_Child> which has a Factory<Test_Child> attribute from above
Test tc = p.Construct("Test");
// invokes the 'create' method of the Factory which calls 'new Test_Child(s)' to print the output

The method awaits Factory<T> as the input parameter:
public static <T extends Test> TestBuilder<T> create(Factory<T> f)
And Factory is an interface with only one method:
interface Factory<T extends Test> {
T create(String s);
}
That makes it effectively a functional interface, that can be implemented by simply passing a lambda: Function<String, T> (a function that creates an instance of type T from String). Test_Child::new is such a lambda, because it consumes String and produces T.
As stated Factory is a function, that takes a String and creates T. By calling the method create, we're invoking the function.

Related

Call base method on generic object of derived class

Trying to add a base interface with method so all derived classes have to implement the method or use default method. What's the best way to going about getting this method callable? See comment in code block below.
public interface IA{}
public interface IB{
public Integer doWork();
}
public interface IC extends IB{
}
class B implements IB{
Integer doWork(){
return 2;
}
}
class C extends B implements IC{
#Override
Integer doWork(){
return 7;
}
}
//What do I need to do to cast clazz to an object so I can call the derived class' doWork method?
private Integer newClient(Class<T> clazz){
((B) clazz).doWork();
}
Ended up finding a solution:
B.class.cast(clazz);
As for how to ensure you call the derived class' method that overrides the base, that is a native behavior of Java.
Example Program:
public class Foo {
static class A {
int get() { return 0; }
}
static class B extends A {
#Override
int get() { return 1; }
}
public static void main(final String[] args)
{
A a = new A();
B b1 = new B();
A b2 = new B();
printA(a);
printA(b1);
printA(b2);
}
public static <T extends A> void printA(T bObj) {
System.out.println(bObj.get());
}
}
Output:
0
1
1
Note that the output returned from b2::get()::int is the same as b1::get()::int, even though b2 is type A and b1 is type B. This is because even though we only have a reference to the A class in b2, the object implementation is still B.
It seems that you only want to know how to instantiate the Class. Assuming it has a default constructor you can do it this way:
private Integer newClient(Class<B> clazz){
try {
((B) (clazz.getConstructor().newInstance())).doWork();
} catch ...
}

Cannot get value of property from extending class

I have two Java classes, one of which inherits from other. They are somewhat like the following:
A.java:
public class A {
public String invocations[] = {"foo"};
public A() {
// do stuff
}
}
B.java:
public class B extends A {
public String invocations = {"bar", "baz"};
public B() {
super();
}
}
In this example, assuming I create an instance of B and get its invocations property, it returns {"foo"} instead of the expected {"bar", "baz"}. Why is this, and how can I get the {"bar", "baz"}?
You have one variable hiding another one. You can refer to a variable in a super class by using a cast to the type explicitly. (I am assuming you fix the syntax errors)
public class Main {
static class A {
public String[] invocations = {"foo"};
}
static class B extends A {
public String[] invocations = {"bar", "baz"};
}
public static void main(String... args) {
B b = new B();
System.out.println("((A)b).invocations=" + Arrays.toString(((A) b).invocations));
System.out.println("b.invocations=" + Arrays.toString(b.invocations));
}
}
prints
((A)b).invocations=[foo]
b.invocations=[bar, baz]

anonymous class as generic parameter

I want to create a class that gets an object from anonymous class definition to store. I used a generic typed class to achieve that. Then i want to define some operations using functional interfaces that gets this object as a parameter to work with.
Code says more than words. So have a look at this:
public class Test<T> {
#FunctionalInterface
public interface operation<T> {
void execute(T object);
}
private T obj;
public Test(T _obj){
obj = _obj;
}
public void runOperation(operation<T> op){
op.execute(obj);
}
public static void main(String[] args){
Test<?> t = new Test<>(new Object(){
public String text = "Something";
});
t.runOperation((o) -> {
System.out.println(o.text); // text cannot be resolved
});
}
}
My problem is that o.text in the implementation of the functional interface cannot be resolved. Is this some kind of type erasure consequence?
The interesting thing is that I can get this code working when I implement the functional interface in the constructor.
Have a look at this code:
public class Test<T> {
#FunctionalInterface
public interface operation<T> {
void execute(T object);
}
private T obj;
private operation<T> op;
public Test(T _obj, operation<T> _op){
obj = _obj;
op = _op;
}
public void runOperation(){
op.execute(obj);
}
public static void main(String[] args){
Test<?> t = new Test<>(new Object(){
public String text = "Something";
}, (o) -> {
System.out.println(o.text);
});
t.runOperation();
}
}
This works perfect and prints out "Something". But what is wrong with my first approach? I really don't get the problem here.
The problem is that your anonymous class still has to conform to (extend or implement) some type, and the type you've chosen is Object which doesn't have your text property. In order to refer to properties of some kind, you'll need an actual class or interface to work with, so the compiler can make guarantees about what properties and methods are available on the object.
This works.
public class Test<T> {
public static class Data {
public String text;
}
#FunctionalInterface
public interface Operation<K> {
void execute(K object);
}
private T obj;
private Operation<T> op;
public Test(T obj) {
this.obj = obj;
}
public void runOperation(Operation<T> op) {
op.execute(obj);
}
public static void main(String[] args) {
Test<Data> t = new Test<>(new Data() {{
this.text = "Something";
}});
t.runOperation((o) -> {
System.out.println(o.text);
});
}
}
In the second piece of code,
new Test<>(new Object(){
public String text = "Something";
}, (o) -> {
System.out.println(o.text);
});
compiles because the type argument of Test for the constructor call is inferred (since the diamond operator is used), and it is inferred to the anonymous type that the first argument evaluates to (the anonymous class type), and thus the second argument's type is operation<that anonymous class type>, which works.
In the first piece of code, the expression
t.runOperation((o) -> {
System.out.println(o.text); // text cannot be resolved
})
does not compile. Here, the type of the lambda is inferred based on the type of the variable t, which is Test<?>. Thus, the argument of runOperation must be operation<some unknown type>. The only argument to runOperation that will work here is null.
Test<?> t = new Test<>(new Object(){
public String text = "Something";
}, (o) -> {
System.out.println(o.text);
});
The compiler here is replacing T in Test with your anonymous class and since that class contains a variable text that's why the 2nd case works.

Confusion with generics, java

I have generic class :
public class Test<T> {
private Test<? extends T> myInstance;
public Test<? extends T> getInstance () {
return myInstance;
}
public void setInstance (Test<? extends T> argType) {
this.myInstance = argType;
}
}
And I have two classes in my class hierarchy relations:
public abstract class Alphabet {
//code here
}
and
public class A extends Alphabet{
public A() {
super();
System.out.print("This is A call");
}
}
Finally I have a class where I want to store make generic class Test with particular type and set new Instance of Object -> A through setInstance() method:
public static void main(String[] args) {
List<Alphabet> list = new ArrayList<Alphabet>();
Test<Alphabet> tAlphabet = new Test<Alphabet>();
tAlphabet.setInstance(new A()); //Here is compilation ERROR
}
But I have got the compilation error in line tAlphabet.setInstance(new A());
What is the issue with my generic class?
Your instance is a Test object as it's currently written, and you are supplying it with an Alphabet object instead. You probably want your instance to be of type Alphabet:
public class Test<T> {
private T myInstance;
public T getInstance() {
return myInstance;
}
public void setInstance(T argType) {
myInstance = argType;
}
}
This way, your Test stores an Alphabet instead of another Test.
It seems you have made things more complicated than needed. You probably want this in your Test class instead of what you actually have:
private T myInstance;
public T getInstance () {
return myInstance;
}
public void setInstance (T argType) {
this.myInstance = argType;
}
With this arrangement you would be free to setInstance(new A()) on a Test<Alphabet> instance.

Why do I get StackOverflowError here?

Why does this java code produce StackOverflowError? I understand that this somehow connected with recursive generic type parameter. But I don't understand clear the whole mechanism.
public class SomeClass<T extends SomeClass> {
SomeClass() {
new SomeClassKiller();
}
private class SomeClassKiller extends SomeClass<T> {
}
public static void main(String[] args) {
new SomeClass();
}
}
The generic part doesn't matter - nor does it really matter that the class is nested. Look at this mostly-equivalent pair of classes and it should be more obvious:
public class SuperClass
{
public SuperClass()
{
new SubClass();
}
}
public class SubClass extends SuperClass
{
public SubClass()
{
super();
}
}
So the subclass constructor calls the superclass constructor - which then creates a new subclass, which calls into the superclass constructor, which creates a new subclass, etc... bang!
Here it is invoking one constructor from another and from it the previous one, cyclic constructor chain, see the comments below
public class SomeClass<T extends SomeClass> {
SomeClass() {//A
new SomeClassKiller();// calls B
}
private class SomeClassKiller extends SomeClass<T> {//B
//calls A
}
public static void main(String[] args) {
new SomeClass(); //calls A
}
}
This is because of the Recursive constructor calls happening between the classes SomeClass and
SomeClassKiller.
public class SomeClass<T extends SomeClass> {
SomeClass() {
new SomeClassKiller();
}
private class SomeClassKiller extends SomeClass<T> {
public SomeClassKiller()
{
super(); //calls the constructor of SomeClass
}
}
public static void main(String[] args) {
new SomeClass();
}
}
The code produced by the compiler is something like this, so when u create an object it recursivly calls the SomeClass and SomeClassKiller for ever.
Constructors are invoked top-to-bottom, that is if a class A derives from B, A's constructors will first invoke the parent constructor (B).
In you case, new SomeClassKiller() recursively calls the constructor of SomeClass which in turn constructs another SomeClassKiller … there it is.
The main() method is creating a new instance of SomeClass which calls the SomeClass constructor that creates a new instance of SomeClassKiller that by default calls the parent constructor and the stackoverflow occurs.
To avoid the stackoverflow. Change the code to look as follows:
public class SomeClass<T extends SomeClass> {
SomeClass() {
new SomeClassKiller();
}
private class SomeClassKiller extends SomeClass<T> {
public SomeClassKiller(){
//super(); does this by default, but is now commented out and won't be called.
}
}
public static void main(String[] args) {
new SomeClass();
}
}

Categories