java generic object construction within an anonymous subclass - java

I was playing around with anonymous subclasses and I found a problem that I can't get around.
EDIT: problem is solved thanks to thomas, the complete working code is on pastebin (Foo.java; FooTest.java)
2 Classes; Foo and FooTest...
Code first:
class Foo {
public Foo () {}
public void whichClassAmI () {
System.out.println(this.getClass());
}
public void say () {
System.out.println("Foo says: nothing");
}
public <T extends Foo> T getAnotherFoo () {
try {
Class<? extends Foo> c = this.getClass();
T r = (T)(c.getConstructor().newInstance());
return r;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
_
class FooTest {
public static String stuff = "";
public static void main (String[] args) {
Foo f1 = new Foo();
// instance of anon subclass
Foo f2 = new Foo(){
public void say () {
System.out.println("Modded Foo says: " + stuff);
}
};
f1.whichClassAmI();
f2.whichClassAmI();
stuff = "stuff";
f1.say();
f2.say();
Foo f3 = f1.getAnotherFoo();
f3.say();
Foo f4 = f2.getAnotherFoo(); // <-- exception here
}
}
So this code compiles with an unsafe operation warning, runs and throws an exception; output is:
Note: Foo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
class Foo
class FooTest$1
Foo says: nothing
Modded Foo says: stuff
Foo says: nothing
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: FooTest$1.<init>()
at Foo.getAnotherFoo(Foo.java:20)
at FooTest.main(FooTest.java:23)
Caused by: java.lang.NoSuchMethodException: FooTest$1.<init>()
at java.lang.Class.getConstructor0(Class.java:2723)
at java.lang.Class.getConstructor(Class.java:1674)
at Foo.getAnotherFoo(Foo.java:17)
... 1 more
what I don't understand is:
f2 class is FooTest$1 and this class seems to be not extending Foo
if (1) is true why does " Class c = [...] " can be set with FooTest$1
if (1) is false and (2) works correct, why doesn't it find the method?

To 1): f2 is of type FooTest$1 which extends Foo but that isn't printed, you just get the current class and no superclasses or interfaces.
To 2): Since 1) is false, there's not question here :)
To 3): The problem is that the annonymous inner class FooTest$1 needs an external FooTest instance to be created. Calling the constructor via reflection would try to create a new instance without an enclosing instance of FooTest and such a method is not available (i.e. a method that creates an instance of an inner class without an instance of the enclosing class).
What you need to do is get the constructor that takes an instance of the enclosing class as its parameter. For more information have a look at this question: Is it possible to create an instance of nested class using Java Reflection?
Edit:
I read your code again and am ashamed I missed this: the FooTest$1 class is actually a static inner class since it is created in the static main method. Thus it doesn't have a constructor taking an enclosing class instance.
However, since you create the class and its constructor inline that constructor isn't publicly visible. Thus getClass().getConstructor() won't return it (this class will only return public constructors. In that case you have to use getClass().getDeclaredConstructor(). The same is true for fields and methods, just for the record.

Related

Why is interface default method shadowed by parent private method? [duplicate]

Consider below class hierarchy.
class ClassA {
private void hello() {
System.out.println("Hello from A");
}
}
interface Myinterface {
default void hello() {
System.out.println("Hello from Interface");
}
}
class ClassB extends ClassA implements Myinterface {
}
public class Test {
public static void main(String[] args) {
ClassB b = new ClassB();
b.hello();
}
}
Running the program will give following error :
Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.testing.ClassA.hello()V from class com.testing.Test
at com.testing.Test.main(Test.java:23)
This is all because I marked ClassA.hello as private.
If I mark ClassA.hello as protected or remove the visibility modifier(i.e. making it default scope), then it shows a compiler error as :
The inherited method ClassA.hello() cannot hide the public abstract method in Myinterface
However, as per exception stacktrace above, I get a runtime IllegalAccessError.
I couldn't get why this is not detected at compile time. Any clues ?
Update: Seems like it's really a bug.
A class or super-class method declaration always takes priority over a default method!
default hello(...) method from the Myinterface allows you to write without errors:
ClassB b = new ClassB();
b.hello();
Until runtime, because at runtime hello(...) method from the ClassA takes the highest priority (but the method is private). Therefore, IllegalAccessError occurs.
If you remove the default hello(...) method from the interface, you get the same illegal access error, but now at compile time.

Can't seem to understand complex polymorphism

I'm studying CS and we have questions about polymorphism that I cant wrap my mind around. Here is an example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
public BB(){
foo();
}
public void foo(){
System.out.print("BB:foo ");
}
public void goo(){
System.out.print("BB::goo ");
}
public static void main(String[] args){
// Code goes here
}
}
When in void main i add the line:
AA a = new BB();
it goes first AA constructor prints AA:foo but then goo() sends it to BB's goo, why so?
Simple polymorphism such as "Animal -> cat/spider/dog" is easy to understand but when it comes to this I'm just lost. Can you guys give me any tips how to read this code? What are the rules are?
EDIT: there is no #Override annotation because this is a question from an exam.
Explanation
public class AA {
private void foo() { ... }
^^^^^^^
}
Polymorphism is not applied to private methods. A subclass does not inherit private methods, so they cannot be overridden:
A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:
m is a member of the direct superclass of C.
m is public, protected, or declared with package access in the same package as C.
No method declared in C has a signature that is a subsignature of the signature of m.
Java Language Specification - 8.4.8. Inheritance, Overriding, and Hiding
Therefore, the foo() call from the A constructor doesn't invoke BB#foo, it calls AA#foo.
But the goo() call within AA#foo refers to the overridden method BB#goo. Here, with public methods, method overriding and polymorphism were applied.
It's a bit tricky, so I would recommend you put the #Override annotation everywhere it's supposed to be.
public class BB extends AA {
#Override // it doesn't compile - no overriding here
public void foo() { ... }
#Override // it does override
public void goo() { ... }
}
It also might be helpful to detect another problem:
Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.
If a method declaration in type T is annotated with #Override, but the method does not override from T a method declared in a supertype of T, or is not override-equivalent to a public method of Object, then a compile-time error occurs.
Java Language Specification - 9.6.4.4. #Override
Illustration
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation super();, an invocation of the constructor of its direct superclass that takes no arguments.
Java Language Specification - 8.8.7. Constructor Body
To put it simply,
public BB() {
foo();
}
turns into
public BB() {
super();
foo();
}
Keeping super(); in mind, we can make the next illustration:
new BB()
AA() // super(); -> AA constructor
A#foo() // private method call
B#goo() // polymorphic method call
BB() // BB constructor
B#foo() // plain method call
It's explained very well in the official docs:
https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
So, the Java compiler is adding super() without args for you.
In fact, if the class you are extending doesn't have a default constructor you will be required to call this constructor with args before.
Otherwise, the reason why AA:goo is not being called is because is override by BB even if it doesn't have the #Override annotation, if you want to see that call you need to use super(); in your b:goo method. In fact, the foo is not override because it private so it's not possible to override it, if you try to add the annotation #Override you'll se you have a compilation failure.
AA::foo() is private so AA::foo() and BB::foo() aren't the same.
new BB()
will call AA::Constructor first, calling AA::foo().
AA::foo() call goo() and since you instantiated BB class it'll be BB::goo().
Please use "override" keyword on method when you want to do something like this
There is also a serious design flaw in the example code: it is calling an overridable method from a constructor. This means that object BB might not be fully initialized at the time that this method is called on it. For example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
private Date timestamp;
public BB() {
super();
foo();
timestamp = new Date();
}
public void foo() {
System.out.print("BB:foo ");
}
public void goo() {
// goo() gets called before timestamp is initialized
// causing a NullPointerException
System.out.print("BB::goo " + timestamp.getYear());
}
public static void main(String[] args){
AA obj = new BB();
}
}
Remember this: NEVER CALL AN OVERRIDABLE METHOD FROM A CONSTRUCTOR (even not indirectly as in this example)
Polymorphism is Simple yet Confusing at times when we use different set of names [Which is the case here].
Polymorphism is basically a Parent Child Relationship. Key here is, if you are trying hard to place the names of the classes, use yourself instead i.e. give comment line next to class names as below
public class AA{} //your Parent name
public class BB extends AA{} // yourself i.e. your name
When it comes to the code like this, AA a = new BB(); , decode the code as below:
BB is you, AA is your parent.
new keyword is with YOU(i.e. BB), so a new object of YOU would be created or born. In order to for YOU to born, without your parents(i.e. AA), you cannot exist and so, first they will be born or created (i.e. AA constructor would run). Once your Parents (i.e. AA) are created, then it is time for YOU to born(i.e. BB constructor would run).
In your example,
public AA(){
foo(); -- line A
}
private void foo() {
System.out.print("AA::foo ");
goo(); -- line B
}
public void goo(){
System.out.print("AA::goo "); -- line C
}
As I told earlier, Line A would be called when you say AA a = new BB(); as Line A is in Constructor of AA, Line A calls foo() method and so the control lands in foo(), prints "AA::foo " and executes Line B. Line B calls goo() method and so on it reaches Line C. After Line C is executed, there is nothing left to execute in AA constructor (i.e. Object is created) and so the control flows down to the child Constructor ( As parent is created, it is time for the child to born) and so the child Constructor would be called next.
For Students/Beginners, I strongly recommend to go through Head First Java Edition. It really helps you in laying the Java Foundation Strong.

Can't access methods in sub class when using the super as the reference type

I have a problem where I have some class say
public class Foo {
public Foo() {
// Do stuff
}
public void generalMethod() {
//to general stuff
}
}
public class Bar extends Foo {
public Bar() {
//do stuff
}
public void uniqueMethod() {
//do stuff
}
}
public class Driver() {
public static void main(String[] args) {
Foo test = new Bar();
test.uniqueMethod(); //this causes an error
}
}
So i get an error which says, that the method uniqueMethod() is undefined for Foo, but when I change the assignment to Bar test = new Bar(); the problem goes away. I dont understand as it should work with Foo test = new Bar();
Can someone suggest a reason for which why this error occurs?
Thank you in advance.
Although the method is there at runtime, the compiler only sees that the object test of type Foo DOES NOT have the method uniqueMethod. Java works with virtual method, where the method that will be invoked is determined at runtime. So, again, the compiler does not see that this specific instance's type is a Bar. If you really need to invoke that method, you could a cast and invoke the method:
((Bar)test).uniqueMethod();
Now, to the compiler, you have the type Bar, and he can see all the methods that are available at Bar type
Think like the compiler and JVM
Example 1
Foo test = new Bar();
So, I have one variable that is of type Foo. I MUST validate that all subsequent calls to members of this class are OK - It will look for all members in Foo class, the compiler doesnt even look for the instance type.
In runtime, the JVM will know that we have a variable of type Foo, but with instance type Bar. The only difference here is that it, JVM, will look to the instance to make the virtual calls to the methods.
Example 2
Bar test = new Bar();
So, I have one variable that is of type Bar. I MUST validate that all subsequent calls to members of this class are OK - It will look for all members in Foo and 'Bar' classes, the compiler, again, doesnt even look for the instance type.
In runtime, the JVM will know that we have a variable of type Bar, and an instance of the same type:Foo. Now we again, have access to all the members defined in Foo and Bar classes.
useing late binding you must have the same method in the super class "Fathor" , or it will not work !
this work with me
//
public class foo {
public void print(){
System.out.println("Super,"+2);}
}
class bo extends foo {
public void print(){
System.out.println("Sup,"+9);
}
}
Test //
public abstract class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
foo t = new bo();
t.print();
}
}
///
output
Sup,9
This error occurs because the compiler does not know that test is of type Bar, it only knows the declared type of Foo.
public void test(Foo foo) {
// error! this method can accept any variable of type foo, now imagine if you passed it
// another class that extends Foo but didnt have the uniqueMethod. This just wont work
foo.uniqueMethod();
}

Local class instance creation expression in a static-context

The JLS 15.9.2 tells us how to determine an enclosing instance:
Let C be the class being instantiated, and let i be the instance being created.
If C is an inner class, then i may have an immediately enclosing
instance (ยง8.1.3), determined as follows:
[...]
If C is a local class, then:
If C occurs in a static context, then i has no immediately enclosing
instance.
Otherwise, if the class instance creation expression occurs in a
static context, then a compile-time error occurs.
Otherwise, let O be the immediately enclosing class of C. Let n be an
integer such that O is the n'th lexically enclosing type declaration
of the class in which the class instance creation expression appears.
The immediately enclosing instance of i is the n'th lexically
enclosing instance of this.
I didn't get what the bolded case means. Let me provide the example I wasn't supposed to be compiled:
class A{
int a;
public static void main (String[] args) throws java.lang.Exception{
class Foo{
void bar(){
}
}
Foo f = new Foo(); //Instance creation expression occured in the static context
}
}
DEMO
What's wrong with that? Couldn't you provide an actual example describing the second point?
You should read these two lines :
If C occurs in a static context, then i has no immediately enclosing instance.
Otherwise, if the class instance creation expression occurs in a static context, then a compile-time error occurs.
Your case is the first case - you defined the class Foo in a static context (the main method), and therefore the instance f has no enclosing instance.
If, however, you'd define the class Foo outside the main method, and try to create the instance of Foo in the main method, you'll get an error, unless you change Foo to be a static class.
class A
{
int a;
class Foo
{
void bar()
{
}
}
public static void main (String[] args) throws java.lang.Exception
{
Foo f = new Foo(); // this should fail
}
}
I guess the following case is meant:
public class A {
public class B { /* ... */ }
public static void createB() {
new B(); // <<=== This should fail
}
}
The marked line should fail, since the inner class B is not static, so it requires en enclosing instance of A. There is no such enclosing instance, since the method createB() is static.
UPDATE: I mistook the question beeing about inner classes in general, which is what my example shows. In the context of Local Classes I also can't interpret the documentation.

NullPointerException : Overriding constructor calling method of Base class in Derived class

I've this code snippet:
class Base {
public Base() {
method();
}
void method() {
System.out.println("In Base");
}
}
class Derived extends Base {
private String bar;
public Derived() {
bar="bar";
}
public void method() {
System.out.println(bar.length());
}
public static void main(String[] args) {
Base base=new Derived();
base.method();
}
}
On executing the code I got an exception:
Exception in thread "main" java.lang.NullPointerException
at Derived.method(Main.java:22)
at Base.<init>(Main.java:5)
at Derived.<init>(Main.java:17)
at Derived.main(Main.java:27)
I'm unable to understand why there is NullPointerException and the stackTrace of the exception. Anyone could help me to understand?
You can check the code here.
new Derived() creates a Derived object, which implies calling its super class constructor first, which in turn calls method - but you have overriden method so it is the child version of that method which is called. In that method, you call bar.length which has not been initialised yet.
Conclusion: it is almost never a good idea to call an overridable method in a constructor.
The code you have given is an antipattern. We should never invoke a method handling fields from a constructor for a simple reason that it might create unexpected results.
From your code, your are trying to initialize a field called bar in the Derived constructor. Now when you say Base b = new Derived(), the call happens in following fashion
Base static initializer -- If you have
Derived Static Initializer -- If you have
Base block initializer -- If you have
Base Constructor --> this is
the place you are calling method()
Derived Block initializer -- If you have
Derived constructor -->
this is the place where you are initializing bar
Now due to run time polymorphism, in to No. 4, when the Derived's method() gets called, the bar is not yet initialized to the value "bar" (since initialization happens at No. 6) , the NPE occurs

Categories