Keep out of reach of Children: Removing protected fields from inheritance - java

In the spirit of well designed OO, a certain class I am extending has marked one of its fields protected. This class has also generously provided a public setter, yet no getter.
I am extending this class with a base class that is in turn extended by several children. How can I restrict access to the protected variable from my children while still being able to manipulate it privately and set it publicly?
See example below:
public abstract class ThirdPartyClass {
protected Map propertyMap;
public void setPropertyMap(Map propertyMap){
this.propertyMap= propertyMap;
}
// Other methods that use propertyMap.
}
public abstract class MyBaseClass extends ThirdPartyClass{
// Accessor methods for entries in propertyMap.
public getFoo(){
propertyMap.get("Foo");
}
public getBar(){
propertyMap.get("Bar");
}
// etc...
}
public class OneOfManyChildren extends MyBaseClass {
// Should only access propertyMap via methods in MyBaseClass.
}
I have already found that I can revoke access by making the field private final in MyBaseClass. However that also hinders using the setter provided by the super class.
I am able to circumvent that limitation with the "cleverness" below yet it also results in maintaining two copies of the same map as well as an O(n) operation to copy over every element.
public abstract class MyBaseClass extends ThirdPartyClass{
private final Map propertyMap = new HashMap(); // Revokes access for children.
/** Sets parent & grandparent maps. */
#Override
public final void setPropertyMap(Map propertyMap){
super.setPropertyMap(propertyMap);
this.propertyMap.clear();
this.propertyMap.putAll(propertyMap);
}
}
Are there any better ways of accomplishing this?
Note: This is only one example of the real question: How to restrict access to protected fields without maintaining multiple copies?
Note: I also know that if the field were made private in the first place with a protected accessor, this would be a non-issue. Sadly I have no control over that.
Note: IS-A relatonship (inheritance) required.
Note: This could easily apply to any Collection, DTO, or complex object.
Metaphor for those misunderstanding the question:
This is akin to a grandparent having a cookie jar that they leave accessible to all family members and anyone else in their house (protected). A parent, with young children, enters the house and, for reasons of their own, wishes to prevent their children from digging into the cookie jar ad nauseam. Instead, the child should ask the parent for a chocolate chip cookie and see it magically appear; likewise for a sugar cookie or Oreo. They need never know that the cookies are all stored in the same jar or if there even is a jar (black box). This could be easily accomplished if the jar belonged to the parent, if the grandparent could be convinced to put away the cookies, or if the grandparents themselves did not need access. Short of creating and maintaining two identical jars, how can access be restricted for children yet unimpeded for the parent & grandparent?

This might not be possible for you, but if you could derive an interface from ThirdPartyClass and make ThirdPartyClass implement it ?
Then have MyBaseClass act as a decorator by implementing the interface by delegating to a private member ThirdPartyClassImpl.
I.e.
public interface ThirdParty ...
public class ThirdPartyClass implements ThirdParty
public class MyBaseClass implements ThirdParty {
private ThirdParty decorated = new ThirdPartyClass();
public class SubclassOne extends MyBaseClass....
etc

Ok, cheating mode on:
How about you overwrite de public setter and change the map implementation to a inner class of MyBaseClass. This implementation could throw a exception on all methods of map you dont want your children to access and your MyBaseClass could expose the methods they should use by using an internal method your map implementation...
Still has to solve how the ThirdPartyMethod will access those properties, but you could force your code to call a finalizationMethod on your MyBaseClass before use it... I'm just divagating here
EDIT
Like This:
public abstract class MyBaseClass extends ThirdPartyClass{
private class InnerMapImpl implements Map{
... Throw exception for all Map methods you dont want children to use
private Object internalGet(K key){
return delegate.get(key);
}
}
public void setPropertyMap(Map propertyMap){
this.propertyMap= new InnerMapImpl(propertyMap);
}
public Object getFoo(){
return ((InnerMapImpl) propertyMap).internalGet("Foo");
}
}

Sadly, there's nothing you can do. If this field is protected, it is either a conscious design decision (a bad one IMO), or a mistake. Either way, there's nothing you can do now about it, as you cannot reduce the accessibility of a field.
I have already found that I can revoke access by making the field private final in MyBaseClass.
This isn't exactly true. What you are doing is called variable hiding. Since you are using the same variable name in your subclass, references to the propertyMap variable now point to your private variable in MyBaseClass. However, you can get around this variable hiding very easily, as shown in the code below:
public class A
{
protected String value = "A";
public String getValue ()
{
return value;
}
}
public class B extends A
{
private String value = "B";
}
public class C extends B
{
public C ()
{
// super.value = "C"; --> This isn't allowed, as B.value is private; however the next line works
((A)this).value = "C";
}
}
public class TestClass
{
public static void main (String[] args)
{
A a = new A ();
B b = new B ();
C c = new C ();
System.out.println (new A ().getValue ()); // Prints "A"
System.out.println (new B ().getValue ()); // Prints "A"
System.out.println (new C ().getValue ()); // Prints "C"
}
}
So, there's no way you can "revoke" access to the protected class member in the super class ThirdPartyClass. There aren't a lot of options left to you:
If your child class do not need to know about the class hierarchy above MyBaseClass (i.e. they won't refer to ThirdPartyClass at all), and if you don't need them to be subclasses of ThirdPartyClass then you could make MyBaseClass a class which does not extend from ThirdPartyClass. Instead, MyBaseClass would hold an instance of ThirdPartyClass, and delegate all calls to this object. This way you can control which part of ThirdPartyClass's API you really expose to your subclasses.
public class MyBaseClass
{
private ThirdPartyClass myclass = new ThirdPartyClass ();
public void setPropertyMap (Map<?,?> propertyMap)
{
myclass.setPropertyMap (propertyMap);
}
}
If you need a direct access to the propertyMap member of ThirdPartyClass from MyBaseClass, then you could define a private inner class and use it to access the member:
public class MyBaseClass
{
private MyClass myclass = new MyClass ();
public void setPropertyMap (Map<?,?> propertyMap)
{
myclass.setPropertyMap (propertyMap);
}
private static class MyClass extends ThirdPartyClass
{
private Map<?,?> getPropertyMap ()
{
return propertyMap;
}
}
}
If the first solution doesn't apply to your case, then you should document exactly what subclasses of MyBaseClass can do, and what they shouldn't do, and hope they respect the contract described in your documentation.

I am able to circumvent that limitation with the "cleverness" below yet it also results in maintaining two copies of the same map as well as an O(n) operation to copy over every element.
Laf already pointed out, that this solution can easily be circumvented by casting the child classes into the third party class. But if this is ok for you and you just want to hide the protected parent map from your child classes without maintaining two copies of the map, you could try this:
public abstract class MyBaseClass extends ThirdPartyClass{
private Map privateMap;
public Object getFoo(){
return privateMap.get("Foo");
}
public Object getBar(){
return privateMap.get("Bar");
}
#Override
public final void setPropertyMap(Map propertyMap) {
super.setPropertyMap(this.privateMap =propertyMap);
}
}
Note also, that it doesn't really matter, if the parents map is protected or not. If one really wants to access this field through a child class, one could always use reflection to access the field:
public class OneOfManyChildren extends MyBaseClass {
public void clearThePrivateMap() {
Map propertyMap;
try {
Field field =ThirdPartyClass.class.getDeclaredField("privateMap");
field.setAccessible(true);
propertyMap = (Map) field.get(this);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
return;
}
propertyMap.clear();
}
}
So it actually comes down to the question, why you want the field not to be accessible by the child classes:
1) Is it just for convenience, so it is immediately clear how your api should be used? - then it is perhaps fine to simply hide the field from the sub classes.
2) Is it because of security reasons? Then you should definitely search for another solution and use a special SecurityManager that also prohibits accessing private fields through reflection...
That said there is perhaps another design you could try: Instead of extending the third party class, keep a final inner instance of this class and provide public access to the inner class like this:
public abstract class MyBaseClass {
private Map privateMap;
private final ThirdPartyClass thirdPartyClass = new ThirdPartyClass(){
public void setPropertyMap(Map propertyMap) {
super.setPropertyMap(MyBaseClass.this.privateMap = propertyMap);
};
};
public Object getFoo(){
return privateMap.get("Foo");
}
public Object getBar(){
return privateMap.get("Bar");
}
public void setPropertyMap(Map propertyMap) {
thirdPartyClass.setPropertyMap(propertyMap);
}
public final ThirdPartyClass asThirdPartyClass(){
return this.thirdPartyClass;
}
}
Then, whenever you need to access the third party library with an instance of the third party class, you do something like this:
OneOfManyChildren child;
thirdpartyLibrary.methodThatRequiresThirdPartyClass(child.asThirdPartyClass());

What about creating another protected variable called propertyMap ? That should over shadow if for your child classes. You can also implement it such that calling any method on it will cause an exception.
However, as accessor methods are defined in the base class, they will not see your second shadowed version and still set it appropriately.

How can I restrict access to the protected variable from my children while still being able to manipulate it privately and set it publicly?
So you want the public to have more rights than you do? You can't do that since they could always just call the public method... it's public.

Visibility on variables is just like visibility on methods, you are not going to be able to reduce that visibility. Remember that protected variables are visible outside the direct subclass. It can be accessed from the parent by other members of the package See this Answer for Details
The ideal solution would be to mess with the parent level class. You have mentioned that making the object private is a non-starter, but if you have access to the class but just cannot downscope (perhaps due to existing dependencies), you can jiggle your class structure by abstracting out a common interface with the methods, and having both the ThirdPartyClass and your BaseClass use this interface. Or you can have your grandparent class have two maps, inner and outer, which point to the same map but the grandparent always uses the inner. This will allow the parent to override the outer without breaking the grandparent.
However, given that you call it a 3rd party class, I will assume you have no access at all to the base class.
If you are willing to break some functionality on the master interface, you can get around this with runtime exceptions (mentioned above). Basically, you can override the public variable to throw errors when they do something you do not like. This answer is mentioned above, but I would do it at the variable (Map) level instead of your interface level.
If you want to allow READ ONLY access top the map:
protected Map innerPropertyMap = propertyMap;
propertyMap = Collections.unmodifiableMap(innerPropertyMap)
You can obviously replace propertyMap with a custom implementation of map instead. However, this only really works if you want to disable for all callers on the map, disabling for only some callers would be a pain. (I am sure there is a way to do if(caller is parent) then return; else error; but it would be very very very messy). This means the parents use of the class will fail.
Remember, even if you want to hide it from children, if they add themselves to the same package, they can get around ANY restrictions you put with the following:
ThirdPartyClass grandparent = this;
// Even if it was hidden, by the inheritance properties you can now access this
// Assuming Same Package
grandparent.propertyMap.get("Parent-Blocked Chocolate Cookie")
Thus you have two options:
Modify the Parent Object. If you can modify this object (even if you can't make the field private), you have a few structural solutions you can pursue.
Change property to fail in certain use-cases. This will include access by the grandparent and the child, as the child can always get around the parent restrictions
Again, its easiest to think about it like a method: If someone can call it on a grandparent, they can call it on a grandchild.

Use a wrapper. A anti decorator pattern, that instead of adding new methods removes them by not providing a method to call it.

Related

How to access a Child class function in java [duplicate]

I have the following classes
class Person {
private String name;
void getName(){...}}
class Student extends Person{
String class;
void getClass(){...}
}
class Teacher extends Person{
String experience;
void getExperience(){...}
}
This is just a simplified version of my actual schema. Initially I don't know the type of person that needs to be created, so the function that handles the creation of these objects takes the general Person object as a parameter.
void calculate(Person p){...}
Now I want to access the methods of the child classes using this parent class object. I also need to access parent class methods from time to time so I CANNOT MAKE IT ABSTRACT.
I guess I simplified too much in the above example, so here goes , this is the actual structure.
class Question {
// private attributes
:
private QuestionOption option;
// getters and setters for private attributes
:
public QuestionOption getOption(){...}
}
class QuestionOption{
....
}
class ChoiceQuestionOption extends QuestionOption{
private boolean allowMultiple;
public boolean getMultiple(){...}
}
class Survey{
void renderSurvey(Question q) {
/*
Depending on the type of question (choice, dropdwn or other, I have to render
the question on the UI. The class that calls this doesnt have compile time
knowledge of the type of question that is going to be rendered. Each question
type has its own rendering function. If this is for choice , I need to access
its functions using q.
*/
if(q.getOption().getMultiple())
{...}
}
}
The if statement says "cannot find getMultiple for QuestionOption." OuestionOption has many more child classes that have different types of methods that are not common among the children (getMultiple is not common among the children)
NOTE: Though this is possible, it is not at all recommended as it kind of destroys the reason for inheritance. The best way would be to restructure your application design so that there are NO parent to child dependencies. A parent should not ever need to know its children or their capabilities.
However.. you should be able to do it like:
void calculate(Person p) {
((Student)p).method();
}
a safe way would be:
void calculate(Person p) {
if(p instanceof Student) ((Student)p).method();
}
A parent class should not have knowledge of child classes. You can implement a method calculate() and override it in every subclass:
class Person {
String name;
void getName(){...}
void calculate();
}
and then
class Student extends Person{
String class;
void getClass(){...}
#Override
void calculate() {
// do something with a Student
}
}
and
class Teacher extends Person{
String experience;
void getExperience(){...}
#Override
void calculate() {
// do something with a Teacher
}
}
By the way. Your statement about abstract classes is confusing. You can call methods defined in an abstract class, but of course only of instances of subclasses.
In your example you can make Person abstract and the use getName() on instanced of Student and Teacher.
Many of the answers here are suggesting implementing variant types using "Classical Object-Oriented Decomposition". That is, anything which might be needed on one of the variants has to be declared at the base of the hierarchy. I submit that this is a type-safe, but often very bad, approach. You either end up exposing all internal properties of all the different variants (most of which are "invalid" for each particular variant) or you end up cluttering the API of the hierarchy with tons of procedural methods (which means you have to recompile every time a new procedure is dreamed up).
I hesitate to do this, but here is a shameless plug for a blog post I wrote that outlines about 8 ways to do variant types in Java. They all suck, because Java sucks at variant types. So far the only JVM language that gets it right is Scala.
http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html
The Scala creators actually wrote a paper about three of the eight ways. If I can track it down, I'll update this answer with a link.
UPDATE: found it here.
Why don't you just write an empty method in Person and override it in the children classes? And call it, when it needs to be:
void caluculate(Person p){
p.dotheCalculate();
}
This would mean you have to have the same method in both children classes, but i don't see why this would be a problem at all.
I had the same situation and I found a way around with a bit of engineering as follows - -
You have to have your method in parent class without any parameter and use - -
Class<? extends Person> cl = this.getClass(); // inside parent class
Now, with 'cl' you can access all child class fields with their name and initialized values by using - -
cl.getDeclaredFields(); cl.getField("myfield"); // and many more
In this situation your 'this' pointer will reference your child class object if you are calling parent method through your child class object.
Another thing you might need to use is Object obj = cl.newInstance();
Let me know if still you got stucked somewhere.
class Car extends Vehicle {
protected int numberOfSeats = 1;
public int getNumberOfSeats() {
return this.numberOfSeats;
}
public void printNumberOfSeats() {
// return this.numberOfSeats;
System.out.println(numberOfSeats);
}
}
//Parent class
class Vehicle {
protected String licensePlate = null;
public void setLicensePlate(String license) {
this.licensePlate = license;
System.out.println(licensePlate);
}
public static void main(String []args) {
Vehicle c = new Vehicle();
c.setLicensePlate("LASKF12341");
//Used downcasting to call the child method from the parent class.
//Downcasting = It’s the casting from a superclass to a subclass.
Vehicle d = new Car();
((Car) d).printNumberOfSeats();
}
}
One possible solution can be
class Survey{
void renderSurvey(Question q) {
/*
Depending on the type of question (choice, dropdwn or other, I have to render
the question on the UI. The class that calls this doesnt have compile time
knowledge of the type of question that is going to be rendered. Each question
type has its own rendering function. If this is for choice , I need to access
its functions using q.
*/
if(q.getOption() instanceof ChoiceQuestionOption)
{
ChoiceQuestionOption choiceQuestion = (ChoiceQuestionOption)q.getOption();
boolean result = choiceQuestion.getMultiple();
//do something with result......
}
}
}

Why can the level access of a field or method be more accessible in a java subclass

So as far as I understand the Substitution principle doesn't allow a subclass to have fields which have a weaker access privilege because otherwise it could potentially violate information hiding and also because a subclass should always offer at least the same behavior of its parent one. That makes sense to me.
but at the same time I don't understand how it could make sense to extend a field or method access level? I have a private field in the parent class while public in the child class. Could you give me an example of why this makes sense? Or is it just because of a design choice?
it is not true as you mentioned for private field. you can't extend a private field from super class to subclass. if you declare a field with that same name, you define a new field for that subclass.
However, you can change package access and protected access to something more like public and this doesn't make any problem because super class doesn't provide that for it's subclass but subclass maybe change its behavior depend on its state and wants to provide that for other users.
For example when it protected you can only access that in that package and in subclass. however maybe you do some works in it that doesn't good for public implementation. (if you make something public, you must support it for future release) however in subclass you might want to override it and add some new feature to it and provide a result that is usable by other people.
A good example (always java provide best example):
If you see, java declared this in Object class:
class Object {
protected native Object clone() throws CloneNotSupportedException;
}
so no one can call clone() on it. it is good because maybe I don't want to provide clone() for my class. however if I want it, it is easy to override that and make it public for other people and also call super.clone() in it for use feature which is implemented before for create a new copy of my class. Isn't great?!
https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
The parent and child have 2 separate instances of test. As you can see in this example.
public class Main {
public class Parent{
private String test = "parent test";
String getTest() {
return test;
}
}
public class Child extends Parent {
public String test = "child test"; // defining it here hides the parent field
#Override
String getTest() {
return test;
}
}
public static void main(String[] args) {
Main main = new Main();
Parent parent = main.new Parent();
System.out.println(parent.getTest());
Child child = main.new Child();
System.out.println(child.getTest());
}
}
Output:
parent test
child test
it could potentially violate information hiding
Information hiding, while a good practice, has little to do with the Liskov substitution principle.
(A) subclass should always offer at least the same behavior of its parent (class).
This is true, but is achieved by disallowing a stricter access modifier on an inherited member. A weaker access modifier surfaces additional behavior.
class A {
private int lastInput;
protected int getLastInput() {
return lastInput;
}
public int getSquareValue(int input) {
lastInput = input;
return getLastInput()*getLastInput();
}
}
class B extends A {
public int getLastInput() {
return super.getLastInput();
}
}
A aa = new A();
B bb = new B();
A ab = bb;
// All behaviors of A exist in B as well.
// B can be substituted for A.
System.out.println(aa.getSquareValue(5)); // 25
System.out.println(ab.getSquareValue(5)); // 25
// B also has new behaviors that A did not surface.
// This does not prevent B from substituting for A.
System.out.println(bb.getLastInput()); // 5

How to prevent sublasses from default implementing a method of super class?

I have a method which adds Objects to an static list like this:
#PostConstruct
protected void registerToTransactionList() {
TransactionValidator.registerTransactionList(this);
}
registerTransactionList method just adds "this" to the static list, this method is in BalanceTransactionValidator class which extends TransactionValidator (owner of static list),the problem is all subclasses of BalanceTransactionValidator class are added to static list either,and if I override registerToTransactionList method in them like this:
#Override
#PostConstruct
protected void registerToTransactionList() {
}
It doesn't add subclasses but doesn't add BalanceTransactionValidator either. Can anybody help me on this? Please notice sublasses are overriding this method by default.
make the method private to block the visibility
private void registerToTransactionList() {
}
or make the method final to block it from been override
protected final void registerToTransactionList() {
}
There are two ways of achieving that:
Keep your method as it is; but then you have to actively check for the type of your objects before externally calling that method
Change your whole logic and make that method private
It won't help to make the method final as suggested in one of the comments - your problem is not that subclasses are overwriting that method; in essence, you have a design problem: you wish that subclasses should not invoke that method at all.
So, the only real option that makes sense here is "2.". You see, by having public method on a class that you want to be extended you are implicitly saying: it is perfectly fine to call that method; on any object that is instance of the base class (or child class!).
And in your case, that is not true: you actually do not want that the code behind this method runs for child classes. Then you shouldn't put that method in the list of public/protected methods of your base class!
Finally: you might want to step back and do some reading about good OO design. Class hierarchies do not fall from the sky: you willfully design them for a certain purpose. In other words: there is more to inheritance than just putting some "A extends B" on your class declaration. You have to understand each and every method on your B class; and how your child classes should deal with them!
EDIT: after some more thinking, I guess you are doing things "the wrong way", like:
class BaseClass {
public final void doRegistration() {
BaseClass toRegister = getObjectForRegistration();
if (toRegister != null) { ... register toRegister ...
}
protected BaseClass getObjectForRegistration() {
return null;
}
With that code, you could then put
protected BaseClass getObjectForRegistration() {
if (this instanceof ClassThatShouldBeRegistered) {
return this;
}
return null;
}
into that one class that wants to be registered. Probably there could be even nicer ways of doing so; but after some thinking I don't see how we could avoid the instanceof. But the above code should work; and it only requires specific code only in your base class and in that one class that wants to register something.

How can I have two classes share the same variable definitions

What I really need is to be able to declare regular variables in an interface and implement that interface in two classes that I would not have to have to re-declare these in each class (ie class.data.variables instead of class.variables). Is there any way that I could achieve the same goal differently?
To give more detail. Essentially, I have created a small drawing program that drops JLabels on a JPanel that is on a JScrollPane. Because I have a specific design for these JLabels (ie they are not just for drawing they represent airline objects for this application), I have a class that extends JLabel and adds my application specific variables to it. Ultimately, I read and write an XML file with these variables so they can load and save their designs. Since I can not use this extended class for my XML definitions because it screams about the parent class even though I told it to have NONE as the accessor (I read there is a bug), I have to create an identical class and copy values back and forth for saving and loading. Not too much of a problem except when I add a variable to the JLabel extended class and forget to add it to the XML mimic class and subsequent copy routines.
So, it would be great if I could make one class (say CellDataRecord.java) that held the extra data declarations and have that class be used in both places (the JLabel extension and the XML data) without having to have something like XML.data.CellDataRecordXXX.
You can do that with inheritance or using an interface, where the variable is set as a constant in the parent class. Since you are extending a JLabel, you should implement the interface on both classes:
public interface MyInterface {
int someint = 9;
}
public class MyClass1 extends JLabel implements MyInterface {
//this class has access to `someint`
}
public class MyClass2 extends JLabel implements MyInterface {
// also has access to `someint`
}
Edit
Since you want to be able to change the same variable from different classes, you have to ensure you aren't changing copies and are changing the same variable, so you should use a volatile keyword on the variable to indicate to java that all threads should check the value before it updates it.
Now you'll need to have a separate class so that instances can be made from other classes to get the value. You have to use the static keyword to ensure that one copy is kept for all class instances.
public class MyVariableWrapper {
public static volatile int some_var = 9;
public void updateSomeVar(int newvar) {
some_var = newvar;
}
public int getSomeVar() { return some_var; }
}
Now the other two classes just do this:
public class MyClass1 extends JLabel {
MyVariableWrapper myVariableWrapper;
MyClass1() {
super();
myVariableWrapper = new MyVariableWrapper();
// now I have access to `some_var`
}
}
public class MyClass2 extends JLabel {
MyVariableWrapper myVariableWrapper;
MyClass2() {
super();
myVariableWrapper = new MyVariableWrapper();
// now I have access to the same `some_var` as MyClass1
}
// this is a wrapper method for your convenience
// since you don't like the excess code when accessing the variable
public int getSomeVar() {
return myVariableWrapper.some_var;
// or myVariableWrapper.getSomeVar();
}
public void setSomeVar(int newvar) {
myVariableWrapper.some_var = newvar;
// or myVariableWrapper.setSomeVar(newvar);
}
}
Now you can do this:
MyClass2 myClass2 = new MyClass2();
System.out.println(""+myClass2.getSomeVar());
I'm not sure I 100% grasp your problem but from the first few lines of your description, instead of implementing an interface, you could define an abstract class and have your classes extend it. That way, you'll be able to define attributes in the abstract class and these will be common to all subclasses.

How do I extend a java class that is instantiated by another class?

Given two java classes, A and B, where A is usually instantiated via B, such as:
A myA = B.createA();
Can I create a subclass of A (let's call it SubA) and somehow have it be instantiated by the B.createA() method?
(Note that I cannot modify A and B....)
I know that not all instances of A are instances of SubA, thus I cannot do this:
SubA mySubA = B.createA();
Similarly, I cannot cast it like this either:
SubA mySubA = (SubA) (B.createA());
for the same reason -- it will get a ClassCastException.
Am I being dense and forgetting something fundamental, or is there no way to do this?
(Late addition: I'm so sorry, I should have mentioned that A and B have roughly 50 methods each, and all I want to do is add a single property to SubA, along with a getter and a setter. I'd really rather not implement all 50 of A's methods to invoke the corresponding method in the superclass's object.)
It sounds like like what you'd really like is to modify the behavior of both the original A and B. In that case, you could try extending both classes (where the extension of B is purely to specify a slightly different factory method for creating SubAs).
class SubA extends A {
/** This is the one special aspect of SubA justifying a sub-class.
Using double purely as an example. */
private double specialProperty;
public double getSpecialProperty() { return specialProperty; }
public void setSpecialProperty(double newSP) { specialProperty = newSP; }
public SubA() {
super();
// Important differences between SubAs and As go here....
// If there aren't any others, you don't need this constructor.
}
// NOTE: you don't have to do anything else with the other methods of
// A. You just inherit those.
}
class SubB extends B {
// Purely for the purposes of a slightly different factory method
public A createA() {
return new SubA();
}
// Or if you need a static method
// (this is usually instead of the first choice)
public static A createA() {
return new SubA();
}
}
Note that at this point, you could create one of your SubB factory objects and make it look like the original B like so:
B myNewB = new SubB();
A myA = myNewB.createA();
Or, if you're using the static factory instead, it isn't quite as close a match (but it's close).
A myA = SubB.createA();
Now, if you really need to do something with the sub-property, you'll have access to it via the child interface. I.e., if you create the object like so:
SubA mySubA = SubB.createA();
mySubA.setSpecialProperty(3.14);
double special = mySubA.getSpecialProperty();
Edit to discuss "Late addition":
At this point, your SubA object should be exactly what you want. It will inherit the 50 methods from the parent (A) and you can add your additional property to the child, plus the getter and setter. I changed the code above to illustrate what I mean.
This is usually done via a proxy:
class SubA extends A {
private A proxiedClass;
public SubA(A a) {
proxiedClass = a;
}
public int anyMethodInA() {
return proxiedClass.anyMethodInA();
}
}
...
SubA mySubA = new SubA(B.createA());
Doing this manually is rather verbose, so most people use some kind of a AOP library (like AspectJ) to only intercept method calls they are interested in.
You could create a wrapper around it, with SubA having a constructor that takes A as the parameter.
Like this:
SubA mySubA = new SubA(B.createA());
Since all instances of SubA are instances of A, you could then assign it to your existing A variable and override any necessary methods.
A myA = new SubA(B.createA());
I can't think of any other clean way of doing it.
If you are just wanting to add a field to A without object oriented such as changing behaviour, you could add it as an "external field". Use a WeakHashMap to map from instance of A onto the field value (just so long as the field value doesn't directly or indirectly reference A or you'll have an object life time contention issue):
private static final Map<A,FieldType> map =
new java.util.WeakHashMap<A,FieldType>(); // thread-safe from 1.6, IIRC
public static FieldType getField(A a) {
return map.get(a);
}
public static void setField(A a, FieldType value) {
map.set(a, value);
}
Really we should be using WeakIdentityHashMap, but it doesn't exist in the Java library!

Categories