Honestly, I'm not sure the title fits this correctly; But I will try to explain my problem with examples.
Say I have two classes
public class Entity {
private static int lastID = 0;
private int ID;
private Entity(){};
public static Entity create(){
lastID++;
Entity ent = new Entity();
ent.ID = lastID;
return ent;
}
}
public class Blob extends Entity {
private int x,y;
pubic void setPos(int X,int Y){;
x = X;
y = Y;
}
}
The way I'd like to interface with the Entity factory would be in the form of
Blob b = Entity.create<Blob>();
Or something in that nature.
My best attempt was
public static <E extends Entity> E create(){
E ent = new E();
...
but that doesn't want to work.
I am afraid it can't be done without actually passing a class or its name as an argument.
You can then use a generic construction <E extends Entity<E>> to make it typesafe and avoid manual type casting.
public class Entity<E extends Entity<E>> {
private static int lastID = 0;
protected int ID;
protected Entity() {
}
public static <E extends Entity<E>> E create(Class<E> clazz) {
lastID++;
E newItem;
try {
newItem = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e); // let's hope your child classes will have a working default constructor
}
newItem.ID = lastID;
return newItem;
}
public int getID() {
return ID;
}
}
public class Blob extends Entity<Blob> {
private int x,y;
public Blob() {
}
public void setPos(int X,int Y){;
x = X;
y = Y;
}
}
public class AnotherBlob extends Entity<AnotherBlob> {
String help = "Help!";
public String help() {
return help;
}
}
// TEST!
public class Test {
public static void main(String[] args) {
Blob blob = Entity.create(Blob.class);
AnotherBlob anotherBlob = Entity.create(AnotherBlob.class);
System.out.println("Blob: " + blob.getClass() + " ID = " + blob.getID() +
"\nAnother blob: " + anotherBlob.getClass() + " ID = " + anotherBlob.getID());
}
}
A simple factory method might look something like this. Keep it in its own class (not in Entity class) and have the name Factory someplace in name so it has context
public static final Entity getInstance(String id){
Entity instance = null;
if(id.equals("Blob")) {
instance = new Blob();
}
else if(id.equals("Another Blob")) {
instance = new AnotherBlob();
}
// more Entity types here
return instance;
}
Related
I want to be able to pass Object from any class to a specific class. How do i do this? I pass the object in the constructor of the receiving class. One workaround i know is using static variables, but i need the whole object not just the variables.
public class tryitout
{
public static void main(String[] args) {
A a = new A();
B b = new B(a);
b.print();
}
}
class A implements Serializable
{
public int a;
public String b;
A()
{
this.a = 12;
this.b =" nach";
}
}
class B
{
Object obj;
B(Object o)
{
obj = o;
}
void print()
{
System.out.println(obj.a + " "+ obj.b);
}
}
Using Generics :
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class tryitout {
public static void main(String[] args) {
ClassA a = new ClassA("sap",11);
ClassB<ClassA> b = new ClassB<ClassA>(a);
b.print();
}
}
public class ClassA {
private String name;
private int id;
public ClassA(String name, int id) {
super();
this.name = name;
this.id = id;
}
#Override
public String toString() {
return "ClassA [name=" + name + ", id=" + id + "]";
}
}
public class ClassB<T> {
private T genericObj;
public ClassB(T genericObj){
this.genericObj = genericObj;
}
public void print() {
Field nameField = getField("name");
Field idField = getField("id");
try {
System.out.println(nameField.get(genericObj));
System.out.println(idField.getInt(genericObj));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private Field getField(String FieldName) {
Field fld = null;
try {
fld = genericObj.getClass().getDeclaredField(FieldName);
if(Modifier.isPrivate(fld.getModifiers())) {
fld.setAccessible(true);//To get access over private fields
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return fld;
}
}
using generics you can access method also.
I don't know your exact purpose,otherwise other classes can extend any particular Abstract class and you can use that Abstract class as a type inside classB.
public class TypeClass {
protected String name;
protected int id;
protected void paint(){
System.out.println("name: " + name + " | id: " + id);
}
}
public class ClassC extends TypeClass{
public ClassC(String name, int id) {
super();
this.name = name;
this.id = id;
}
#Override
public String toString() {
return "ClassA [name=" + name + ", id=" + id + "]";
}
}
package javaConcept.generics;
public class ClassD {
private TypeClass typeClass;
public ClassD(TypeClass typeClass) {
this.typeClass = typeClass;
}
public void newPaint() {
typeClass.paint();
}
}
public class TempoClass {
public static void main(String[] args) {
ClassC c = new ClassC("sap",11);
ClassD b = new ClassD(c);
b.newPaint();
}
}
maybe use static blocks and anonymous blocks some thing like this
public class HelloWorld{
public static void main(String []args){
B ob1= new B();
C ob2= new C(B.ob);
D ob3= new D();
C ob4= new C(ob3.ob);
}
}
class A
{
//this is empty class just for sake of object to be created
public void imWorking()
{
System.out.println("test");
}
}
class B
{
public static A ob;
static{ob=new A();}//static called once class gets loaded
}
class C
{
public C(){}//Default constructor
public C(A a){a.imWorking();}
}
class D
{
public A ob;
{ob=new A();}//ananomous block calls everytime a new object is created
}
more info Static Initialization Blocks blocks & anonymous blocks][1]
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc1 = new ImClass(mc);
System.out.println("imc1 = "+imc1);
mc.setId(2);
ImClass imc2 = new ImClass(mc);
System.out.println("imc2 = "+imc2);
}
}
final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = mClass;
}
public MClass getmClass() {
return mClass;
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
class MClass {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
I want to provide complete immutablity to the class IMClass, As we can see IMclass is immutable but it has an instance variable mclass that is the reference of MClass and MClass is a mutable class.
I have tried changing the getter method getmClass() as below
public MClass getmClass() {
return (MClass) mClass.clone();
}
but it is not allowing me to do so, Could some one please correct it that where i am getting wrong.
Thanks in advance
I have tried this but still getting the same result, values are getting updated
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc1 = new ImClass(mc);
System.out.println("imc1 = "+imc1);
mc.setId(2);
ImClass imc2 = new ImClass(mc);
System.out.println("imc2 = "+imc2);
}
}
final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
public MClass getmClass() {
return (MClass)mClass.clone();
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
class MClass implements Cloneable{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
There are a lot of good ideas floating around. Here is how I would summarize it:
Avoid using clone if possible, and favor using a copy-constructor instead. See Joshua Bloch's thoughts on this matter.
To ensure immutability, you need to make sure you copy the MClass instance that is passed to the ImClass constructor. Otherwise, whoever originally passed the MClass instance can still make changes to it.
Consider creating an immutable wrapper around the MClass class, perhaps by using inheritance.
This is one way that this can be achieved. There are certainly other ways:
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc1 = new ImClass(mc);
System.out.println("imc1 before = " + imc1);
mc.setId(2);
System.out.println("imc1 after = " + imc1); // continues printing 1.
imc1.getmClass().setId(3); // changes not allowed on the immutable copy, throws exception.
}
}
public final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = (mClass == null ? null : mClass.createImmutableCopy());
}
public MClass getmClass() {
return mClass;
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
public class MClass {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public MClass createImmutableCopy() {
return new ImmutableMClass(this);
}
private static class ImmutableMClass extends MClass {
public ImmutableMClass(MClass src) {
super.setId(src.getId());
}
#Override
public void setId(int id) {
throw new UnsupportedOperationException("immutable instance.");
}
}
}
EDIT: How to make the clone method work
If you still want to do it the cloning way, make sure you follow these 2 steps:
Expose the clone as a public method (as already suggested), but, ideally, without swallowing the exception so that you don't get an inexplicable NullPointerException if something doesn't work. Although, technically, the CloneNotSupportedException exception should never happen if you don't forget step #2.
Like this:
#Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
Make sure that the MClass implements the Cloneable interface.
Like this:
public class MClass implements Cloneable {
// ...
}
But again, to make sure that the private MClass instance within the ImClass is "immutable", you'll need to call clone in 2 places:
In the ImClass.getmClass() method, as you are already doing.
Also in the ImClass constructor. If you forget this one, then it is still possible to modify it, so immutability hasn't been achieved fully.
Like this:
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
EDIT 2: About why it appears that your code is still not working
The code should be working now, but if I look at your current main method, you are not testing immutability correctly. You are checking the values from 2 different instances of ImClass.
The following is a more valid test:
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc = new ImClass(mc);
System.out.println("imc = " + imc); // should print 1
mc.setId(2);
System.out.println("imc = " + imc); // should still print 1 if immutability works
imc.getmClass().setId(3);
System.out.println("imc = " + imc); // should still print 1 if immutability works
}
If you are trying to achieve some kind of immutable wrapper around an a mutable class, perhaps better idea would be extending it and overriding all the places where it is mutated.
class IMWrapper extends MClass {
public IMWrapper(int id) {
super.setId(id);
}
#Override
void setId(int id) {
throw new UnsupportedOperationException("you can't modify this instance");
}
...
}
Defensive copying is a good idea, you should just implement copy constructor for MClass:
class MClass {
// ...
public MClass(MClass copied) {
this.id = copied.id;
}
}
You already narrowed down the problem to copying/cloning an object.
You can find the solution here: How do I copy an object in Java?
The problem is that the clone() method of MClass is not visible in ImClass.
It will work when you add the following method to MClass:
#Override
public Object clone() {
try {
return super.clone();
} catch (Exception e) {
return null;
}
}
And change your constructor to clone the object there as well (as by Jon Skeet's comment):
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
My working code
public class ImmutabilityOfReferenceInstance {
public static void main(String[] args) {
MClass mc = new MClass();
mc.setId(1);
ImClass imc = new ImClass(mc);
System.out.println("imc = " + imc); // should print 1
mc.setId(2);
System.out.println("imc = " + imc); // should still print 1 if immutability works
imc.getmClass().setId(3);
System.out.println("imc = " + imc); // should still print 1 if immutability works
}
}
final class ImClass {
final private MClass mClass;
public ImClass(MClass mClass) {
this.mClass = (MClass)mClass.clone();
}
public MClass getmClass() {
return (MClass)mClass.clone();
}
#Override
public String toString() {
return String.valueOf(mClass.getId());
}
}
class MClass implements Cloneable{
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
MyMath's constructor is supposed to call Homework's constructor, but super(); returns an error 'cannot find symbol'. It should not have any arguments.
Also, I am confused about how to call the method createAssignment using an arraylist, but I have to use it. Any advice?
Homework
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
public Homework(int pages, String hw) {
// initialise instance variables
pagesToRead = 0;
typeHomework = "none";
}
public abstract void createAssignment(int p);
public int getPages() {
return pagesToRead;
}
public void setPagesToRead(int p) {
pagesToRead = p;
}
public String getTypeHomework() {
return typeHomework;
}
public void setTypeHomework(String hw) {
typeHomework = hw;
}
}
MyMath
public class MyMath extends Homework {
private int pagesRead;
private String typeHomework;
public MyMath() {
super();
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
public String toString() {
return typeHomework + " - " + pagesRead;
}
}
public class testHomework {
public static void main(String[] args) {
ArrayList<Homework> list = new ArrayList<Homework>();
list.add(new MyMath(1));
list.add(new MyJava(1));
for (Homework s : list) {
s.createAssignment();
}
}
}
Compiler error:
Regarding the compiler error, you have to change the MyMath constractor to somthing like:
public MyMath() {
super(someInt, someString);
}
Or, you can add a non-arg constructor to the Homework class:
public Homework() {
this(someInt,someString);
}
You can learn about the super() keyword in the Javadocs tutoriel:
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.
Code Suggestion:
As there is many other issues in your question, i modified all your classes like below:
Homework.java:
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
{
// initialise instance variables
pagesToRead = 0;
typeHomework = "none";
}
public Homework(int pages, String hw) {
this.pagesToRead = pages;
this.typeHomework = hw;
}
public abstract void createAssignment(int p);
public int getPages() {
return pagesToRead;
}
public void setPagesToRead(int p) {
pagesToRead = p;
}
public String getTypeHomework() {
return typeHomework;
}
public void setTypeHomework(String hw) {
typeHomework = hw;
}
}
MyMath.java
public class MyMath extends Homework {
private int pagesRead;
private String typeHomework;
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
public String toString() {
return typeHomework + " - " + pagesRead;
}
}
TestHomework.java:
class TestHomework {
public static void main(String[] args) {
ArrayList<Homework> list = new ArrayList<Homework>();
// will create a homework with type Math and one page to read
list.add(new MyMath(1,"Math"));
// Assuming MyJava is similar to MyMath
list.add(new MyJava(1,"Java"));
for (Homework s : list) {
if (s instanceof MyMath) {
// modify the number of pages to read for the Math homework
s.createAssignment(3);
} else if (s instanceof MyJava) {
// modify the number of pages to read for the Java homework
s.createAssignment(5);
} else {
s.createAssignment(7);
}
}
}
}
UPDATE: I got it! It turns out that the "GENERICS" comment from Boris the Spider was exactly the clue I needed.
Original question and broken code first, solution below that. My generic design for needer-needable below that.
Original question and non-working code
On and off for the past few years, I have been trying to make self-returning method-chains "sharable" with other classes. This is to avoid the big pain of having to duplicate every self-returning function in every sub-class. The basic idea is that you pass the "needer" class to the "needable" class to start configuration, and then pass the needer back when configuration is over. The "needed" object is set internally.
For example:
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().endCfg().
firstName("Kermit").lastName("Frog");
where
firstName("Kermit").lastName("Frog")
are part of the ConfigUser class, and
twentySeven().increment().timesTwo().endCfg()
comes from a separate "config the number" class. endCfg() returns the "needer" class (ConfigUser), at which point you should be able to continue the chain back in ConfigUser. But you can't. In the below code...and in every attempt I have made, I end up with the same error:
C:\java\ConfigUser.java:4: cannot find symbol
symbol : method firstName(java.lang.String)
location: interface NeedsFavNum
cfgFavNum().twentySeven().increment().timesTwo().endCfg().
^
If you comment out everything after endCfg() it reveals the problem:
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
//firstName("Kermit").lastName("Frog");
C:\java\ConfigUser.java:15: incompatible types
found : NeedsFavNum
required: ConfigUser
cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
^
It can't return ConfigUser, which is sub-class of NeedsFavNum, which is the interface for all classes "needing" the favorite-number-config.
Of course, you can duplicate all the functions so they ALL return ConfigUser-s, but that defeats the purpose of sharing chains. The purpose is to share these chains among ANY class, not just sub-classes.
Is there any way to achieve this, or to rethink the whole issue? I'm starting to think that it is simply not possible.
The details are in the below code. It works (...up to these compilation errors, anyway): copy it into a file named ConfigUser.java and give it a try.
Thank you for helping me.
public class ConfigUser implements NeedsFavNum {
public static final void main(String[] igno_red) {
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().endCfg().
firstName("Kermit").lastName("Frog");
cu = (new ConfigUser()). cfgFavNum().twentySeven().increment().timesTwo().endCfg();//.
// firstName("Kermit").lastName("Frog");
}
//init
public static final int iDEFAULT_FAV = 8;
int iFav = -1;
String sName1st = null;
String sNameLast = null;
//funcs
public ConfigUser() {
}
public ConfigUser firstName(String s_s) {
sName1st = s_s;
}
public ConfigUser lastName(String s_s) {
sNameLast = s_s;
}
public FavNumConfigurator cfgFavNum() {
return new FavNumConfigurator(this, iDEFAULT_FAV);
}
public ConfigUser setNumReturnNeeder(int i_favFullyConfigured) {
iFav = i_favFullyConfigured;
return this;
}
}
interface NeedsFavNum {
ConfigUser setNumReturnNeeder(int i_fav);
}
class FavNumConfigurator {
NeedsFavNum nfn = null;
int iFav = -1;
public FavNumConfigurator(NeedsFavNum nf_n, int i_defaultFav) {
nfn = nf_n;
iFav = i_defaultFav;
}
public FavNumConfigurator twentySeven() {
iFav = 27;
}
public FavNumConfigurator timesTwo() {
iFav = iFav * 2;
}
public FavNumConfigurator increment() {
iFav += 1;
}
public NeedsFavNum endCfg() {
return nfn.setNumReturnNeeder(iFav);
}
}
Solution with working code
It turns out that the "GENERICS" comment from Boris the Spider was exactly the clue I needed. Instead of the "needable" class being
FavNumConfigurator
now its
FavNumConfigurator<R extends FavNumNeeder>
where FavNumNeeder is the "needer" interface for any class needing the favorite-number configuration chain. Now the endCfg() function can return exactly the class I want.
Here's the fixed example (it works--copy and save it as ConfigUser.java):
/**
<P>The main class: the "needer".</P>
**/
public class ConfigUser implements NeedsFavNum {
public static final void main(String[] igno_red) {
ConfigUser cu = (new ConfigUser()).
cfgFavNum().twentySeven().increment().timesTwo().timesTwo().endCfg().
firstName("Kermit").lastName("Frog");
System.out.println("name: " + cu.sName1st + " " + cu.sNameLast);
System.out.println("favorite-num: " + cu.iFav);
//---OUTPUT:
//name: Kermit Frog
//favorite-num: 112
}
//init
public static final int iDEFAULT_FAV = 8;
int iFav = -1;
String sName1st = null;
String sNameLast = null;
//funcs
public ConfigUser() {
}
//Self-returning configurers...START
public ConfigUser firstName(String s_s) {
sName1st = s_s;
return this;
}
public ConfigUser lastName(String s_s) {
sNameLast = s_s;
return this;
}
//Self-returning configurers...END
//Start fav-num configuration. Returns the "needable"
public FavNumConfigurator<ConfigUser> cfgFavNum() {
return (new FavNumConfigurator<ConfigUser>(this, iDEFAULT_FAV));
}
//Called by the "needable" in endCfg()
public ConfigUser setNumReturnNeeder(int i_favFullyConfigured) {
iFav = i_favFullyConfigured;
return this;
}
}
//The "needer" interface, for all classes needing favorite-number
//configuration
interface NeedsFavNum {
ConfigUser setNumReturnNeeder(int i_fav);
}
//The "needable" class: A shareable function-chain for favorite-number
class FavNumConfigurator<R extends NeedsFavNum> {
R nfn = null;
int iFav = -1;
public FavNumConfigurator(R nf_n, int i_defaultFav) {
nfn = nf_n;
iFav = i_defaultFav;
}
//Self-returning configurers...START
public FavNumConfigurator<R> twentySeven() {
iFav = 27;
return this;
}
public FavNumConfigurator<R> timesTwo() {
iFav = iFav * 2;
return this;
}
public FavNumConfigurator<R> increment() {
iFav += 1;
return this;
}
//Self-returning configurers...END
public R endCfg() {
nfn.setNumReturnNeeder(iFav);
return nfn;
}
}
Generic needer-needable design
Here is my design of a generic needer-needable solution that implements the above fix. The hardest part was avoiding circular dependencies between ConfigNeedable and ConfigNeeder.
public interface Chainable {
Chainable chainID(Object o_id);
Object getChainID();
}
public interface ConfigNeedable<O,R extends ConfigNeeder> extends Chainable {
boolean isAvailableToNeeder();
ConfigNeedable<O,R> startConfigReturnNeedable(R c_n);
R getActiveNeeder();
boolean isNeededUsable();
R endCfg();
}
public interface ConfigNeeder {
void startConfig();
boolean isConfigActive();
<O> Class<O> getNeededType();
<O> void setNeeded(O o_fullyConfigured);
}
Here is the same (working) example that uses this design, but since it depends on implementations in my personal library (which is unreleased at the moment, because it's changing minute to minute as I'm working on it), it won't compile. Hopefully it will help someone to see.
import xbn.lang.chain.ChainableComposer;
import xbn.lang.chain.ConfigNeeder;
import xbn.lang.chain.SimpleConfigNeedable;
import xbn.lang.chain.SimpleConfigNeeder;
public class ConfigNeedableNeederXmpl {
public static final void main(String[] igno_red) {
UserSettings us = (new UserSettings()).
cfgFavInt().twentySeven().timesTwo().increment().endCfg().name("President Obama");
System.out.println("name=" + us.sName);
System.out.println("favorite number=" + us.iFav);
}
}
class UserSettings implements ConfigNeeder {
private SimpleConfigNeeder scn = new SimpleConfigNeeder(Integer.class);
public static final int iDEFAULT_FAV = 8;
public int iFav = -1;
public String sName = null;
public UserSettings name(String s_name) {
sName = s_name;
return this;
}
public FavNumConfigurator cfgFavInt() {
FavNumConfigurator fnc = new FavNumConfigurator();
fnc.startConfigReturnNeedable(this);
return fnc;
}
//ConfigNeeder: composition implementation...START
public <O> void setNeeded(O i_fullyConfigured) {
scn.setNeeded(i_fullyConfigured);
iFav = (Integer)scn.getElimNeeded();
}
public void startConfig() {
scn.startConfig();
}
public boolean isConfigActive() {
return scn.isConfigActive();
}
public <O> Class<O> getNeededType() {
return scn.getNeededType();
}
public void endConfig() {
iFav = (Integer)scn.getElimNeeded();
}
//ConfigNeeder: composition implementation...END
}
class FavNumConfigurator extends SimpleConfigNeedable<Integer,UserSettings> {
public FavNumConfigurator() {
super(33, true);
}
public FavNumConfigurator(Integer o_defaultNeeded, boolean b_defaultNeededUsable) {
super(o_defaultNeeded, b_defaultNeededUsable);
}
public FavNumConfigurator set(int i_i) {
try {
updateObject(i_i);
} catch(RuntimeException rtx) {
throw newRTXWChainID("set", rtx);
}
return this;
}
public FavNumConfigurator twentySeven() {
updateObject(27);
return this;
}
public FavNumConfigurator timesTwo() {
updateObject(getNeededInProcess() * 2);
return this;
}
public FavNumConfigurator increment() {
updateObject(getNeededInProcess() + 1);
return this;
}
}
What you're looking for is effectively the C++ Curiously recurring template pattern.
You can put all your "shared" self-returning bits in a base abstract class, then extend it.
For example:
public abstract class Base<T extends Base<T>>
{
protected abstract T self();
protected String name;
protected String address;
public T withtName(String name)
{
this.name = name;
return self();
}
public T withAddress(String address)
{
this.address = address;
return self();
}
}
class MyClass extends Base<MyClass>
{
private String someOtherThing;
public MyClass withSomeOtherThing(String thing)
{
this.someOtherThing = thing;
return self();
}
#Override
protected MyClass self()
{
return this;
}
}
Now you can do:
MyClass mc =
new MyClass()
.withAddress("111 elm")
.withtName("Bob")
.withSomeOtherThing("foo");
I have a class A, with a private member int myMember. And a class B with a private member of the class A, called myA;
That is:
public class A{
private int myMember;
...
}
public class B{
private A myA;
}
I would like to be able to access:
B.myA.myMember;
but it seems I can't because myMember is private in A. The thing is, I need A to be defined as private for the purpose of the exercise (that also includes it can't be protected). Is there a way around this?
Thanks.
public class A {
private int myMember;
public int getMyMember() {
return myMember;
}
public void setMyMember(int myMember) {
this.myMember = myMember;
}
}
public class B{
private A myA;
public B() {
myA = new A();
myA.setMyMember(0);
int a = myA.getMyMember();
}
}
Use getters :
public class A {
private int myMember;
public getMyNumber() {
return myNumber;
}
}
public class B {
private A myA;
public A getA() {
return myA;
}
}
So now you can code :
B b = new B();
b.getA().getMyMember();
Since you've stated you can't create more public methods, aka getters, you could use reflection...
public class A{
private int myMember;
...
}
public class B{
private A myA;
private int get(){
try {
Field field = myA.getClass().getDeclaredField("myMember");
field.setAccessible(true);
return (int) field.get(myA);
catch (Exception e){
//Something went wrong, the field doesn't exist or a security exception
return null; //or return some "error number" like -10
}
}
}
If you can declare the private field as static then something like this is possible :
public class A {
private int myMember;
}
public class B {
public static void main (String[] args) {
int myMember = new A() {
public int getPrivate() {
return myMember;
}
}.getPrivate();
System.out.print("\n\t Id : " + myMember);
}
}