Can a Java class have awareness of its instantiator? - java

Is there a way for a Java class to have an awareness of its instantiator? For example:
public class Foo() {
public Foo() {
// can I get Bar.myInteger from here somehow
// without passing it in to the constructor?
}
}
public class Bar {
private int myInteger;
public Bar() {
myInteger = 0;
Foo foo = new Foo();
}
}

Is there any particular reason you don't want to pass anything in the constructor?
Simply put, this violates the encapsulation principle... and probably several others as well.

With inner classes, you can.
public class Bar {
private int myInteger;
public class Foo() {
public Foo() {
// you can access myInteger
}
}
public Bar() {
myInteger = 0;
Foo foo = new Foo();
}
}

No, you can't.
What are you trying to do?

You can get some information with a stack trace:
Throwable t = new Throwable();
t.fillInStackTrace();
StackTraceElement[] stt = t.getStackTrace();
then explore the elements of stt[].

You cannot access it the way you want to. But using an inner class might be appropriate here, depending on what problem you are trying to solve. The inner class can access private variables of the outer one.

If they're in the same package, you can change the access level of myInteger to protected and Foo can access it directly, but you still need a reference to Bar unless myInteger is also static. I don't like to do that though, it makes them harder to test.
Aside from that, your options are using setters after instantiating the Foo or passing it to the constructor.

You can only access a private member of another class if you either explicitly pass it to the constructor if you provide getter/setter functions. So the answer to your question is no.

You could force "Instantiators" to use a Factory. But in any case, the "identity" of the object requesting a new instance should be passed as a parameter.
And careful in defining what kind of identity you want to trace. An instance ID? a Class ID?

If Foo were an inner class to Bar, it could see Bar's members.

you can work with inner classes, like this:
public class Bar {
private int myInteger;
public Bar() {
myInteger = 0;
Foo foo = new Foo();
}
class Foo {
Foo() {
int i = Bar.this.myInteger;
}
}
}
regards.

Keeping it simple...
1.
If Foo always needs to know myInteger from Bar then pass it into the constructor.
2.
If Foo only occasionally needs to know myInteger then call a setter after the constructor.
If Foo needs more than myInteger, i.e. the whole Bar object then Bar can pass itself in using the "this" keyword.
public class Foo
{
public Foo(Bar bar)
{
//Do something with Bar
}
}
// Somewhere in Bar (in a non-static method)
new Foo(this);

Related

How to allow a user to choose what class to initialise

I have an abstract class Foo, which contains a function a(Object o).
Depending on what implementation of Foo you use, a(Object o) is implemented slightly differently.
I want the user of the program to be able to determine what implementation of Foo is used (eg., aFoo,bFoo, cFoo, etc), but I want to cut down on my use of conditional logic so that I can add to my program more safely in the future.
I currently have an Enum eBar that holds the names of all the implementations of Foo, which the user can choose from, but I am unable to determine how to use that to initialise the class.
Store the instance of Foo to use, or add a method creating the Foo to use, in each enum instance:
public enum FooType {
A {
#Override
public Foo createFoo() {
return new AFoo();
}
},
B {
#Override
public Foo createFoo() {
return new BFoo();
}
}
public abstract Foo createFoo();
}
Then, once the user has chosen the type, all you need to do is
selectedFooType.createFoo().a(object);
[EDIT] You can do that using an Enum like below
public enum FooType {
FOO_A(aFoo::new),
FOO_B(bFoo::new),
FOO_C(cFoo::new);
//add as much as you want here
private final Supplier<Foo> fooSupp; //the aim of using a supplier is to create a new instance each time you call the create method as mentioned in the comment.
FooType(final Supplier<Foo> fooSupp) {
this.fooSupp = fooSupp;
}
public final Foo create(){
return this.fooSupp.get();
}
}
Then you can use it like this
final Foo myFoo = FooType.FOO_A.create();
myFoo.o(Object);

Static Factories Methods

One advantage of static factories method states that:
Unlike constructors they can return an object of any subtype of their return type which gives you great flexibility in choosing the class of returned object.
What does this mean exactly?
Can someone explain this with code?
public class Foo {
public Foo() {
// If this is called by someone saying "new Foo()", I must be a Foo.
}
}
public class Bar extends Foo {
public Bar() {
// If this is called by someone saying "new Bar()", I must be a Bar.
}
}
public class FooFactory {
public static Foo buildAFoo() {
// This method can return either a Foo, a Bar,
// or anything else that extends Foo.
}
}
Let me break your question in two parts
(1) Unlike constructors they can return an object of any subtype of their return type (2) which gives you great flexibility in choosing the class of returned object.Let say You have two classes Extended from Player which are PlayerWithBall and PlayerWithoutBall
public class Player{
public Player(boolean withOrWithout){
//...
}
}
//...
// What exactly does this mean?
Player player = new Player(true);
// You should look the documentation to be sure.
// Even if you remember that the boolean has something to do with a Ball
// you might not remember whether it specified withBall or withoutBall.
to
public class PlayerFactory{
public static Player createWithBall(){
//...
}
public static Player createWithoutBall(){
//...
}
}
// ...
//Now its on your desire , what you want :)
Foo foo = Foo.createWithBall(); //or createWithoutBall();
Here you get the both answers Flexability and unlike constructor behaviour
Now You can see through these factory methods its upto you that WHICH TYPE OF PLAYER YOU NEED

Inheritance in Java

If I have an abstract class in java named Foo and it has an implementor named Bar then I want to know the following.
lets say Foo looks something like
public abstract class Foo {
Service serviceFoo
...
}
And Bar is
public class Bar extends Foo {
...
}
Also, lets assume I have an instance with Foo, named foo, currently that has serviceFoo instantiated
If I then declare:
Foo foo = new Bar();
will this create a a new instance of Bar that has serviceFoo instantiated or not? E.g. will that field be inherited and instantiated or just inherited?
When you call new Bar();, the constructor for Foo is called implicitly. If Foo's constructor instantiates serviceFoo then so will Bar. If Foo relies on someone else to instantiate serviceFoo then Bar will do the same.
Existing instances of either Foo or Bar have no bearing on what goes on when a new instance is made. Only what code gets executed in the constructor (or what gets passed in as a parameter) has an impact on the new object.
No, inheritance does not happen between instances; only between class definitions.
When you instantiate new Bar(), serviceFoo will be instantiated according to its declaration in Foo. In the current case, it has no instantiation in Foo, so it would be a null reference in the new instance of Bar.
Also, you should know that all non-primitives in Java are reference types. That is, foo is not a Foo, but a reference to a Foo. When you assign your new Bar() to foo, you are reassigning its reference to a new object entirely.
Edit: One more, minor nitpick - if you already have an instance of Foo named foo as you claim, then the line
Foo foo = new Bar();
would not compile as it is a redeclaration of foo.
No, serviceFoo won't be instantiated. The line
Foo foo = new Bar();
drops the reference to the "old" object referenced by foo and creates a brand new one. In particlar, it does not "convert" the old foo (of type Foo) into an object of type Bar.
When you say Foo foo = new Bar(), you are creating a brand new object. This means that Bar is created from scratch and any instance variables are also initialized. If it inherits from a super class, like Foo, then those inherited variables are also initialized.
There is no way the parameterless constructor Bar() can know about an outside Service serviceFoo and somehow set it to that value.
If you want to do that, you need to pass in the reference to serviceFoo in the constructor.
Foo foo1 = new Bar();
foo1.serviceFoo = new Service();
// do something with that serviceFoo
Foo foo2 = new Bar(foo1.serviceFoo); // make sure you define this constructor
Since serviceFoo is an instance variable (i.e. it's not declared static) any existing instances of Foo that have set this field will not have any effect on any new instances you create.
Assuming Bar doesn't set it, all you'll get is the field inherited and not instantiated with the new instance.
If you change your base class' code to
public abstract class Foo {
Service serviceFoo = new Service(...);
......
}
Then bar will have an instance of Service when bar is instantiated.
Inheritance is used for:
to enable code reuse
to promote polymorphism
Inheritance means when a child class extends or inherit class know as inheritance.
public class Parent {
public void dostuff() {
System.out.println("i am in parent");
}
}
public class Child extends Parent {
public void dostuff() {
System.out.println("i am in child");
}
}
public class Test {
public static void main(String[] args) {
Parent p = new Parent();
Parent p1 = new Child();
p.dostuff();
p1.dostuff();
}
}

How to use AOP to intercept a method call in super on an argument?

I'm extending a class and overriding a method. All I want to do is to call super, but with a modified argument that gets intercepted upon one of its methods is called. An example makes it more clear:
// Foo is an interface and also this method is part of an interface
#Override
public void foo(Foo foo) {
// I want to intercept the call to foo.bar() in super
super.foo(foo);
}
I'd rather use a tool that doesn't require a compiler of its own. What would be the optimal one?
Given that Foo is an interface, you might consider using a dynamic proxy that would:
Wrap the original foo
Intercept all message and forward them to the original foo
There is a complete example in the above link. Here is just the idea:
public class DebugProxy implements java.lang.reflect.InvocationHandler {
private Object obj;
private DebugProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
{
System.out.println("before method " + m.getName());
return m.invoke(obj, args);
}
}
Foo original = ... ;
Foo wrapper = (Foo) java.lang.reflect.Proxy.newProxyInstance(
original.getClass().getClassLoader(),
original.getClass().getInterfaces(),
new DebugProxy(original));
wrapper.bar(...);
Note that if Foo was not an interface, you could still subclass Foo and override all methods manually so as to forward them.
class SubFoo extends Foo
{
Foo target;
SubFoo( Foo target ) { this.target = target };
public void method1() { target.method1(); }
...
}
It's pseudo-code, and I haven't tested it. In both cases, the wrapper allows you to intercept a call in super.
Of course, the wrapper has not the same class as the original Foo, so if super uses
reflection
instanceof
or access instance variables directly (not going through getter/setter)
, then it might be problematic.
Hope that I understood your problem right and that it helps.

What's wrong with my factory?

I've got some code like this:
public abstract class Foo {
public static Foo getFoo() {
return new FooImpl();
}
abstract void DoFoo();
private class FooImpl extends Foo {
public FooImpl() { }
#Override
void DoFoo() { }
}
}
But Eclipse is telling me No enclosing instance of type Foo is accessible. So how can I get this to work?
I attempted to make it as simple as possible to see if it would compile:
public abstract class Foo {
public static Foo getFoo() {
return new FooImpl();
}
private static class FooImpl extends Foo {
public FooImpl() { }
}
}
And I still get the same error. What am I missing?
FIXED! I changed the line return new FooImpl(); to return new Foo.FooImpl();
Excellent explanation here -- in brief, you need to make class FooImpl static, so it's only tied to the outer class, not to a specific instance of the outer class (which you don't have). The getFoo method also looks like it should be static, btw -- otherwise, what instance of Foo were you planning on calling it on?
How do you intend people to call getFoo()?
Unless you're doing something completely funky and radical, you'll need to make it static.
Make the FooImpl class static and it will work.

Categories

Resources