I have a number of classes, please allow me to introduce them and then ask my question at the end:
I have a container class which contains two objects in a composite relationship:
public class Container{
A a;
B b;
public someMethod(){
a.getC().myMethod(b);
}
}
A and B are superclasses (or Interfaces), with subtypes that can also be the type held in the composite relationship.
A contains a member of (interface) type C:
public class A{
C c;
}
public interface C{
public void myMethod(B b);
}
public class D implements C{
public void myMethod(B b){
//This code will modify the state of object b, in class Container.
b.changeState();
}
}
public class E implements C{
public void myMethod(B b){
//This code will modify the state of object b, in class Container.
b.changeState();
}
}
My problem is that I wish to modify the state of object b from a method starting in the container class, which eventually calls code down the hierarchy, to classes D and E- calling myMethod() via dynamic binding. I want to do this because I am going to use polymorphism to run the correct myMethod() (depending on whether the type of object is D or E) and I wish to do this, rather than write IF statements.
So my problem is that it seems very bad continually passing the instance of object b down the class hierarchy to myMethod, so that I can run b-specific code to modify the state of b. Is there anything else I can do to modify b from d and e (collectively known as c)?
I can get this to work using just interfaces but without using generics- but when I added generics i had problems with types and that made me start to think if my whole design was flawed?
EDIT: I could probably do this easily just by using IF statements- but I wanted an elegant solution using polymorphism of classes D and E.
First of all, if I understood your question correctly, no instance of B is being "passed down" in your code. Dynamic dispatch will simply cause the myMethod() implementation in the actual type of a to be called with an instance of B as argument.
While it may be tedious to have to write the argument explicitly every time you implement myMethod(), there's nothing wrong with it.
The alternative is to give each subclass/implementation of A an attribute of type B. In this case, however, you would have to pass your B instance down the chain of constructors to the class that actually has your B attribute.
Your code would become:
public class A{
C c;
public A(C c) {
this.c = c;
}
public interface C{
public void myMethod(B b);
}
public abstract class CC {
protected B b;
public CC(B b) {
this.b = b;
public class D extends CC implements C {
public D(B b) {
super(b);
}
public void myMethod(){
b.changeState();
}
}
public class E extends CC implements C {
public E(B b) {
super(b);
}
public void myMethod(){
b.changeState();
}
}
And then somewhere, e.g. in Container's constructor:
b = new B();
a = new A(new E(b));
You could pass the instance of B to the constructor of E. (or use a setter). That poses issues in itself, but at least it avoids having to pass B down every time you call myMethod(), which now needs no arguments.
e.g.
somewhere inside B
E myE = new E(this);
and, inside E
final B myB;
public E(B myHigherLevelThing) {
this.myB = myHigherLevelThing;
}
public void myMethod() {
myB.changeState();
}
Use the most general interface for the declarations, I'm a little confused about your full hierarchy so there may be room for improvement there...
Related
I came across the following Java code that uses generics and inheritance. I truly do not understand what the following snippet does:
class A<B extends A<B>> {
...
}
What does this code do?
(I got this from DBMaker in MapDB)
It is almost clear and the question actually conists in two parts:
1) why B extends A?
2) why A inside B extends A<B> has generic type B?
Answers for these parts will be:
1) In particular example this class (A) is builder class (called DBMaker), so most of its methods return some type, which extends this builder's class type. This explains, why B should extend A class.
2) But, actualy, if we will hide for the second part ...extends A<B>, we will receive just class A<B>. So A has type variable of type B. That is why in ...extends A<B> A is marked as type A having type variable B.
This tells that A needs derived definitions to be able to do some work:
public abstract class A<T extends A<T>> {
protected T instance;
T getOne() {
return instance;
}
}
public class B extends A<B> {
public B() {
instance = this;
}
}
public static void test() {
B b = new B();
b.getOne();
}
This is most commonly used in interface definitions, where one wants to explicitly use instances of classes implementing an interface in return types or in arguments and not the interface itself:
public interface TimeSeries<T extends TimeSeries<T>> {
T join(T ts);
}
public class DoubleTimeSeries implements TimeSeries<DoubleTimeSeries> {
#Override
public DoubleTimeSeries join(DoubleTimeSeries ts) {
return null;
}
}
So I did some tests to figure this one out, and here is my test cases to see how one could use such a generic case:
public class A<B extends A<B>> {
int x = 10;
B test;
void printX() {
System.out.println(x);
}
void setB(B b) {
test = b;
}
void printB() {
System.out.println(test);
}
}
public class B extends A<B> {
}
public class Run {
public static void main(String[] args) {
A<B> test = new A<B>();
B myB = new B();
test.printX();
test.setB(myB);
test.printB();
myB.printB();
}
}
I hope the code might be self explanatory. If not leave a comment and I will try and explain what is going on. Look at the last line, myB.printB(), here we will get a null, because B has not yet been set for myB, but only for test. This demonstrates that we can have an infinite recursion into classes of B inside A (and inside B for that matter).
we can say:
myB.test.printB();
This will get an error (null pointer), but shows that we now have access to test in the A class from B, and we can go as deep as we want recursively with as many cases as we like. So the A class kind of functions as a wrapper of infinitely many B classes. Does this make sense?
This makes it easier when defining method return types such as this:
class A<B extends A<B>> {
public B getMe(){
return (B) this;
}
}
This tells Java compiler that you are in getMe() method returning a subclass of class A.
class C extends A<C> {
}
C c = new C();
c.getMe(); //returns C
I have a domain class which has a lot of children as shown below ( B is the interface type and B1 and B2 ) implementing the B interface.
As you can see in my main class it needs to cast the (B1 b1 = (B1) a.getB();) and we know it can be B1 or B2, so it should be alright for my knowledge.
Problem I have is the type can grow a lot, people who uses the A needs to put more conditions to check the instance of B and access the specific values of B1 or B2 … is there any ways that I can skip this casting so it can reduce a lot of conditions in the future
public class TestMain
{
public static void main(String[] args)
{
A a = new A();
//this can be B1 or B2
B1 b1 = (B1) a.getB();
}
}
public class A
{
private B b;
protected B getB()
{
return b;
}
protected void setB(B b)
{
this.b = b;
}
}
public interface B
{
void test();
}
public class B1 implements B
{
#Override
public void test()
{
// TODO Auto-generated method stub
}
}
public class B2 implements B
{
#Override
public void test()
{
// TODO Auto-generated method stub
}
}
Assuming you really need this feature (Eran's comment above raises a good point; polymorphism likely does much or all of what you need), the answer is generics. They're a slightly advanced topic, but they're central to Java (all of the collection classes in the JDK use them), so they're very important to learn.
Generics are a way to say "some type," and optionally "some type that's a subtype of some other type." The latter is what you want.
public class A<T extends B>
{
private T b;
protected T getB()
{
return b;
}
protected void setB(T b)
{
this.b = b;
}
}
The <T extends B> part declares a generic parameter of T, and says it must be a subclass of B. From then on, you can use T as if it's a type within the A class. For users of this class, they'll have to specify what kind of A it is, and the compiler will automatically do the downcasting for you:
A<B1> a = new A<B1>();
a.set(new B1());
B1 b = a.getB();
Note that in the second line, if you had done a.set(new B2()) it would be a compile-time error: the compiler would complain that a is parameterized to B1, and therefore you can't pass a B2 to it. At a very high level, you can imagine that the compiler is doing a search-and-replace, replacing T in the original class with B1. And if you had declared:
A<B2> a = new A<B2>();
then the search-and-replace would similarly turn T into B2.
In reality, it's not quite that simple due to something called erasure. You can read more at the Java trail on generics, and there are lots of other resources available as well. This PDF is a good intermediate-level description.
You can also do as below without casting.
B b1 = a.getB();
You need to explicitly add a cast when you perform down-casting. Up-casting is implicit and something which is always safe. Also, why do you need to explicitly cast it to B1 or B2. Instead you can use it base interface type as reference to the object (i.e B) which will not require you to add a cast.
Also it is safe to you base reference type as you need not worry about the actual object-type and thus prevent ClassCastException at runtime.
Using base type as reference to object has many advantages:
Avoid ClassCastException at runtime.
You need not worry about adding a cast
Also if you add more classes to the base class hierarchy, you still can access these classes with the base reference type. This makes your design more flexible.
public class Test {
public static void main(String[] args) {
B b = new B1();
if(B1.class.getName().equals(b.getClass().getName())){
// implement logic for B1 class
}else if(B1.class.getName().equals(b.getClass().getName())){
// implement logic for B2 class
}
}
}
interface B{
}
class B1 implements B{
}
class B2 implements B{
}
or
do method overriding and you can implement different logic for different class and you can call the methods using interface reference with out any casting
Let's say I have two classes, A and B, in turn have some methods, something() and nothing() and an instance of B is created in A, as
public class A {
public A() {
B b = new B();
b.nothing();
}
public void something() {
...
}
}
A calling b.nothing() is all standard stuff, but is there any means which by instance b can call a.something(), assuming the instance of A is called a. If not, why is this conceptually wrong?
I don't think there's anything conceptually wrong with this.
However, for the mechanics to work, b needs to know which instance of A to call something() on. For this, either B's constructor, or its nothing() method, needs to take an A reference as an argument.
example 1:
public class B {
public void nothing(A a) {
...
a.something();
...
}
}
example 2:
public class B {
private final A a;
public B(A a) {
this.a = a;
}
public void nothing() {
...
this.a.something();
...
}
}
example 3:
There is a third way, applicable in some circumstances. If B is an inner class of A, it has an implicit reference to its associated instance of A.
public class A {
public void something() { ... }
public class B {
public void nothing() {
...
something();
...
}
}
}
is there any means which by instance b can call a.something()
You can't get hold of the caller in a method so, no, there's no way to do that.
If not, why is this conceptually wrong?
Two issues come to my mind immediately:
What would the type of the caller be? Since anyone could call b.nothing(), you can't assume more than that it's an Object which would result in lots of ugly down casts.
The implementation of b.nothing() shouldn't care about who's calling him. What happens if you refactor A and move the call to b.nothing() to some other class? It would be quite surprising if b.nothing() all of a sudden stopped working.
The only way b.nothing() can call a.something() is if you tell the instance of B about the instance of A. For example:
b.nothing(this);
where B.nothing looks like:
public void nothing(A a)
{
// Do other stuff
a.something();
}
Alternatively, you could pass in this in the constructor to B, which would keep hold of the reference:
B b = new B(this);
b.nothing();
Note that letting this escape during a constructor call is generally a bad idea - you're letting B.nothing() call A.something() on an object which isn't fully initialized yet - its constructor hasn't finished executing. That can lead to undesirable and hard-to-diagnose behaviour sometimes.
To do this, b would require a reference to a. There are two ways to provide that:
Pass such a reference in the constructor of B or give B an appropriate setter.
If B is an inner class of A, then it has such a reference implicitly.
Lets say class C and D extend class B which extends class A
I have a methods in class E that I want to be able to use either an object C or object D in. I know that class A provides all the methods that I need. How can I go about writing a method that lets me pass either a object C or object D as a parameter?
Am I right in thinking I need to make a generic class? If so does anyone have specific examples that are closer to what I need that this which only seems to tell me how to use the existing collection class?
class A {
public String hello(){return "hello";}
}
class B extends A{}
class C extends B{}
class D extends B{}
The method hello is available in all subclasses B,C and D.
So in E, do something like:
private void test() {
System.out.println(hello(new A()));
System.out.println(hello(new B()));
System.out.println(hello(new C()));
System.out.println(hello(new D()));
}
public String hello(A a) {
return a.hello();
}
and you can pass instances of A,B,C or D
BTW - generics are not necessary in this scenario (as far as I understood it)
If C and D have A as their common ancestror and A provides all needed methods, then your method should simply take an instance of A as a parameter. You do not need a generic method, unless I misunderstood your question.
public void doSomething(A input) {
input.methodInA();
input.secondMethodInA();
...
}
Polymorphism will run an possible overridden code implement in C or D, you don't need to do anything other than call the method.
class A {
}
class B extends A {
}
class C extends B {
}
class D extends B {
}
class E {
public void test ( A a ) {
// c or d will work fine here
}
}
Why can't I cast a base class instance to a derived class?
For example, if I have a class B which extends a class C, why can't I do this?
B b=(B)(new C());
or this?
C c=new C();
B b=(B)c;
Alright let me be more specific as to what I'm trying to do. Here's what I have:
public class Base(){
protected BaseNode n;
public void foo(BaseNode x){
n.foo(x);
}
}
public class BaseNode(){
public void foo(BaseNode x){...}
}
Now I want to create a new set of classes which extend Base and Basenode, like this:
public class Derived extends Base(){
public void bar(DerivedNode x){
n.bar(x);//problem is here - n doesn't have bar
}
}
public class DerivedNode extends BaseNode(){
public void bar(BaseNode){
...
}
}
So essentially I want to add new functionality to Base and BaseNode by extending them both, and adding a function to both of them. Furthermore, Base and BaseNode should be able to be used on their own.
I'd really like to do this without generics if possible.
Alright so I ended up figuring it out, partly thanks to Maruice Perry's answer.
In my constructor for Base, n is instantiated as a BaseNode. All I had to do was re-instantiate n as a DerivedNode in my derived class in the constructor, and it works perfectly.
because if B extends C, it means B is a C and not C is a B.
rethink what you are trying to do.
The existing answers are fine in terms of an abstract argument, but I'd like to make a more concrete one. Suppose you could do that. Then this code would have to compile and run:
// Hypothetical code
Object object = new Object();
InputStream stream = (InputStream) object; // No exception allowed?
int firstByte = stream.read();
Where exactly would the implementation of the read method come from? It's abstract in InputStream. Where would it get the data from? It simply isn't appropriate to treat a bare java.lang.Object as an InputStream. It's much better for the cast to throw an exception.
In my experience it's tricky to get "parallel class hierarchies" like the one you're describing to work. You may find that generics help, but it can get hairy very quickly.
You need to use the instanceof keyword to check the type of object referenced by n and typecast the object and call the bar() method. Checkout Derived.bar() method bellow
public class Test{
public static void main(String[] args){
DerivedNode dn = new DerivedNode();
Derived d = new Derived(dn);
d.bar( dn );
}
}
class Base{
protected BaseNode n;
public Base(BaseNode _n){
this.n = _n;
}
public void foo(BaseNode x){
n.foo(x);
}
}
class BaseNode{
public void foo(BaseNode x){
System.out.println( "BaseNode foo" );
}
}
class Derived extends Base{
public Derived(BaseNode n){
super(n);
}
public void bar(DerivedNode x){
if( n instanceof DerivedNode ){
// Type cast to DerivedNode to access bar
((DerivedNode)n).bar(x);
}
else {
// Throw exception or what ever
throw new RuntimeException("Invalid Object Type");
}
}
}
class DerivedNode extends BaseNode{
public void bar(BaseNode b){
System.out.println( "DerivedNode bar" );
}
}
You can create a constructor for B that takes C as a parameter.
See this post for ideas to do what you're trying to do.
Base classes shouldn't know anything about classes derived from them, otherwise the problems highlighted above will arise. Downcasting is a 'code smell', and downcasting in the base class to a derived class is particularly 'smelly'. Such designs can lead to difficult to resolve circular dependencies too.
If you want a base class to make use of derived class implementations use the Template method pattern i.e add a virtual or abstract method in your base class and override and implement it in the derived class. You can then safely call this from the base class.
You can't do that because C does not necessarily implement the behaviours you created when you extended it in B.
So, say C has a method foo(). Then you know that you can call foo() on a B, as B extends C, so you can cast accordingly a treat a B as if it was a C with (C)(new B()).
However - if B has a method bar(), nothing in the subclass relationship says that you can call bar() on C too. Thus you cannot treat a C as if it were a B, and so you cannot cast.
In your exemple, you can cast n into a DerivedNode if you are certain that n is an instance of DerivedNode, or you can use generics:
public class Base<N extends BaseNode> {
protected N n;
public void foo(BaseNode x){
n.foo(x);
}
}
public class BaseNode {
public void foo(BaseNode x){...}
}
public class Derived extends Base<DerivedNode> {
public void bar(DerivedNode x){
n.bar(x); // no problem here - n DOES have bar
}
}
public class DerivedNode extends BaseNode {
public void bar(BaseNode){
...
}
}
Because if B extends C, then B might have stuff that isn't in C (like instance variables you initialize in the constructor that are not in new C())