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
Related
I am a newbie in Java.... It was all going smooth till I found that below scenario is possible in JAVA.
package newProject;
class A {
}
class B extends A {
}
public class C {
public static void main (String[] args) {
A obj = new B();
}
}
Can any one please explain me in detail about above scenario in terms of how is it possible and how it works on memory side
As said before, this is not possible. However, it is possible when B extends A. This would mean that B has the same properties, methods etc as A + what you add onto it.
you are allowed to do this
A obj = new B();
if one of the following conditions met:
Class B must extends class A
Class B implements the interface A
so, with the class definition you have is not possible!
now, suppose you have something like:
class A {
void move(){...}
}
class B extends A {
void start(){...}
void dispose(){...}
}
A obj = new B();
the only valid method you can call is:
obj.move();
but since the object is a new B you can call all declared B methods but you need to cast
((B)obj).start();
My code is similar to this:
class Base{
public void handleObject(A a){
//more code...
System.out.println("A");
}
}
class Sub extends Base{
public void handleObject(B b){
//more code specific to this instance and class B
System.out.println("B");
}
public void handleObject(C c){
//more code specific to this instance and class C
System.out.println("C");
}
}
Where B and C inherit from A.
I then want to call handleObject of Base from this code:
//...
Sub s = new Sub();
A[] obj = {new B(), new B(),new C(), new A()};
for(A o:obj){
s.handleObject(o);
}
//...
And I expect Sub.handleObject(B b) to be called for each object of type B, Sub.handleObject(C c) for type C, and Base.handleObject(A a) to be called for objects of type A.
The real result is it prints "A" three times.
Is it possible to make it work using java's overloading capabilities or must I type check every object myself? If not, what is the best practice to achieve the desired behavior?
This question is very similar to mine but the answers only show why his attempts did not work and did not offer a sufficient solution for me.
I have also tried making it work using Visitor Pattern, but in their example it seems like it is required for the Base class (or at least the interface) to know about Sub, which is something I prefer not to have my project.
I suggest you use polymorphism to your advantage. Instead of trying to figure out how to behave for different classes of objects, let each class provide its own behavior:
class A {
public void handleMyself() {
System.out.println("A");
}
}
class B extends A {
#Override
public void handleMyself() {
System.out.println("B");
}
}
class C extends A {
#Override
public void handleMyself() {
System.out.println("C");
}
}
class Base {
public void handleObject(A a) {
a.handleMyself();
}
}
class Sub extends Base {
public static void main(String... args) {
Sub s = new Sub();
A[] obj = {new B(), new B(), new C(), new A()};
for (A o : obj) {
s.handleObject(o);
}
}
}
Say I have Class A and Class B. Class B extends Class A. Class A has one method.
public class notimportant
{
public void one()
{
}
}
public class A extends notimportant
{
public void one()
{
//assume there is a super class making this call legal which doesnt do anything
super.one();
System.out.println("blah");
}
}
public class B extends A
{
}
A var1 = new B();
if I call 'var1.one();' will the output end up being:
"blah"
"blah"
because it creates a local copy of 'one()' in Class B and then reads that which calls 'super()' which leads it up to method 'one()' in Class A OR does it just print
"blah"
because it knows to look directly at Class A
EDIT: Hope that is a lot more clear now.
It will follow the way you have it currently written:
-> New object of class B
-> Call method One on this object
-> First line calls supermethod, proceed to execute it
-> Second line prints out after that
Your code doesn't compile at all though, you might want to clear that up. What's keeping you from testing this yourself?
Here's the new situation as you described it. Everything still works as expected, you just add a layer.
public class C {
public void test() {
System.out.println("Inside C");
}
}
public class B extends C {
public void test() {
super.test();
System.out.println("Inside B");
}
}
public class A extends B {
public static void main(String[] args) {
A obj = new A();
obj.test();
}
}
Output:
Inside C
Inside B
super means your superclass – it's resolved at compile-time.
It does not mean the immediate parent class of whatever the runtime type of this is.
I have the following classes:
public abstract class A implements C {
...
}
public abstract class B extends A {
method();
}
But when I try to do the following
A a = null;
A a = new A();
((B) a).method();
I receive a ClassCastException, does anyone have a solution?
B extends A, but A doesnt extend B.
everything A has B has, but A cant do the stuff declared in B
An instance of B is an instance of A, but an instance of A is not necessarily a B. Similar to saying "all circles are shapes, but not all shapes are circles".
You can't do what you are trying to do. That's why you get the exception.
I think what you want here is a constructor to take and A object and make a larger B object out of it which has the included method (which A does not have). But that doesn't make a whole lot of sense. Cant think for the life of me why you would want to do this in practice, and wouldn't just build the B object to start with.
public abstract class A implements C {
...
}
public abstract class B extends A {
public B(A child){
//Construct a B out of A here
}
public void method();
}
Then
A a = null;
A a = new A();
new B(a).method();
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())