Convert sub-type to super-type - java

I have a abstract super class A, and a subclass B that extends this class.
public abstract class A {
}
public class B extends A {
}
I have a method that returns type A, but object B
public A fetchType() {
A a = new B();
return a;
}
When I call the fetchType method, I want to actually get object A. In this case, I might have to cast B to A so I get A. How can I do that?

You cannot create an object if the type is abstract.
Here class A is abstract class, which means you will NEVER be able to create object A.
This is not allowed: A a = new A();

Related

How to get T type in parent class after extends?

How to get T type after extends?
The code below.
class A<T>{
void method(){
// how to get T type ?
}
}
class B extends A<String> {
}
class C extends B {
}
class D<T> extends A<List<T>>{
}
class E extends D<String>{
}
class Main{
public static void main(String[] args){
C c = new C();
c.method();// I want to get T type here is String.
E e = new E();
e.method();// I want to get T type here is List<String> but I can only get String.
}
}
If I create a B, I can use getGenericSupperclass to get T, but when I create a C, I can't.
You should either pass an object of the generic type with the constructor of your A or create an abstract method that returns an object.
Then, your method uses the object to get the class.
Passing an object with the constructor:
class A<T>{
private T dummy;
public A(T dummy){
this.dummy = dummy;
}
void method(){
System.out.println("Our type T is a " + dummy.getClass().getName());
}
}
Using an abstract method:
abstract class A<T>{
public abstract T getDummy();
void method(){
System.out.println("Our type T is a " + getDummy().getClass().getName());
}
}
Instead of an instance of T the various solutions could also pass the class of T.
For instance:
abstract class A<T>{
public abstract Class<T> getGenericClass();
void method(){
System.out.println("Our type T is a " + getGenericClass().getName());
}
}
Personally, I prefer this solution.
Of course, al derived classes should be adapted.
For instance:
class B extends A<String> {
#Override
public Class<String> getGenericClass(){
return String.class;
}
}
You can not.
This problem is caused by something called Type Erasure, which means that Java doesn't store any information about class' generics at runtime, and therefore there is no way to acquire them.
One possibility to work-around this is adding a constructor to A which takes a parameter of type Class and passing the class explicitly by the extending class:
class B extends A<String> {
public B() {
super(B.class)
}
}

Return data type the same as class name via superclass?

I have an abstract class which has one abstract method. I want this method to return the same data type as the class which is overriding the method without having to cast the result of create or having to make a new method declaration on each subclass. I want it to all be declared seemlessly from the parent class.
I want the method to return a object whose data type is the same as the class it was called on.
EDIT: I removed print as people are getting confused with what I am asking
abstract class A
{
public abstract ... create();
}
class B extends A
{
#override
public ... create()
{
return new B...;
}
}
class C extends A
{
#override
public ... create()
{
return new C...;
}
}
Such that
B x1 = new B();
B x2 = x1.create();
// Since create was called on a B object
// a B object is returned, NOT AN "A" object
C y1 = new C();
C y2 = y1.create();
// create makes a C object this time,
// because it's called on a C object
// Problem: create() returns A object, even when
// called from class B or C.
// I want create() to return a B object if called from a B object.
What would be a good way of going about this? Thanks.
I no longer think this is the right answer. It's an answer, but is over-complicated. See my other answer.
There is no notion of a "self" type in Java's generics. The best you can do is to use self-bounded generics:
abstract class A<T extends A<T>>
{
public abstract T create();
}
Then, in your subclasses:
class B extends A<B>
{
#override
public B create()
{
return new B...;
}
}
Actually, there is an easier way to do it than with my other answer: just use a covariant return type in the subclass:
abstract class A {
public abstract A create();
}
class B extends A {
#Override public B create() {
return new B...
}
}
This is more pleasant if you are dealing with instances of A, since you don't have to make it generic (or, shudder, raw).
It also gives just as much of a guarantee that it returns a "self" type, i.e. no guarantee at all.
this.getClass() to get the class object, or, this.getClass().getSimpleName() to get a string of class name.
I have to question the design approach.
I'd be going for
abstract class A {
abstract Supplier<? extends A> create();
}
with
class B extends A {
public Supplier<B> create() {
return B::new;
}
}
(and C accordingly).
Then, there is
A b = new B();
A anotherB = b.create().get(); // will create a B
A c = new C();
A anotherC = c.create().get(); // will create a C
You don't need to make your create method abstract. If all the subclasses have a no-argument constructor, then you can just write this (in class A)
public A create() {
try {
return getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}
This checks the class of the object that you called the method on; and creates a new object of the same class, using its no-argument constructor.
Update
OP's comment suggests that they don't want to have to cast the returned value. If this is a requirement, then the casting can be avoided by changing the method signature as follows.
public <T extends A> T create() {
try {
return getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}

Java generic types inheritance error

In Android Studio I have the following error:
java: incompatible types: java.lang.Object cannot be converted to
java.lang.String
I think b1 and b2 should be behaving the same, but they are not.
Is there a way to make them behave the same (without changing their type of course)?
Here is the code typed:
public class Test
{
class A<T>
{
T t;
T getT()
{
return t;
}
}
class AS extends A<String>
{
}
class B<T> extends AS
{
}
B<Object> b1;
B b2;
public void test()
{
String t3 = b1.getT();
String t4 = b2.getT();
}
}
The problem is that B is a parameterized type, but b2 is declared to have raw B as its type.
You demonstrate with b1 that B's type parameter is distinct from A's, even though they have the same name, so that B's type parameter has nothing to do with the return type of the getT() method inherited from A<String>. When you use a raw type, however, you get the full erasure of that type, including of its supertypes.
Since's A's type parameter is unbounded, its erasure produces type Object, and therefore this is the type of b2.getT(). Of course, Object is not assignable to String.
You can resolve this in at least two ways:
Don't use a raw type for b2. If you don't care about its type parameter then use B<?>. Or,
Remove class B's type parameter. It's not used for anything in your example, so that would be the cleanest thing to do. Just because its superclass is generic does not mean that B has to be.
I think that B without the template object is an incomplete class as opposed to B<Object>. This is why when you are calling it getT() you are actually calling A.getT().
This why in the code below, only String t3 = b2.getT(); fails to compile.
static class A<T>
{
T t;
T getT()
{
return t;
}
}
static class AS extends A<String> {}
static class B<T> extends AS {}
static class C extends B<Object> {}
static A a;
static B<Object> b1 = null;
static B b2 = new B();
static C c = new C();
static void test()
{
Object tt = a.getT();
String t2 = b1.getT();
String t3 = b2.getT();
String t4 = c.getT();
}
The issue here is that getT() returns the object. What you need to do is implement a method toString() that gives the value of the T Object in terms of a String (or just change the types for t3 and t4 to T so the declaration comes out to T t3 = b1.getT(); and T t4 = b2.getT();).
In addition, you should do the following instead of the code you have for B.
B<T> b1;
B<T> b2;
Note that you need to initialize B to something before you can call b1.anyMethod() or else you'll get a NullPointer Exception.

Difference between assigning instantiation to parent class and derived class

If I declare these 2 classes:
public class A {
// attributes
}
public class B extends A {
// attributes
}
A obj1 = new B();
B obj2 = new B();
What is the difference between these two instantiations?
The instantiations are the same. In both cases you are creating a new B().
The assignments are different. Because B is a A, you can assign any expression of type B to a variable of type A. This can happen without you needing to do explicit casts due to assignment contexts (JLS 8 § 5.2) which:
allow the value of an expression to be assigned to a variable; the type of the expression must be converted to the type of the variable.
In your example, a widening reference conversion (JLS 8 § 5.1.5) is performed which allows a reference type S to be converted to a reference type T, provided S is a subtype of T. The compiler does this automatically for you as it is a widening conversion: i.e. it will always succeed without a ClassCastException.
Java needs to allow for this in order to be able to do Polymorphism, which allows you to treat a type S as any of it's supertypes T (e.g. to treat a Cat or a Dog as an Animal); this in turn allows you to put common behaviour (or common contracts - see below for comments about interfaces) into a supertype.
At runtime the actual type is known, and the actual type's methods are called instead of the supertypes methods. So, for Animal a = new Cat();, the runtime knows a is a Cat and calls the implementation of sleep on Cat, not on Animal.
public class Animal { public void sleep() { /* close eyes */ } }
public class Cat extends Animal { public void sleep() { /* curlUpAndSleep */ } }
public class Dog extends Animal { public void sleep() { /* stretchOutAndSleep */ } }
...
public void putToBed(Animal a) { a.sleep(); }
...
Animal a1 = new Cat(); // curls up and sleeps
Animal a2 = new Dog(); // stretches out and sleeps - my dog obviously thinks he's a cat
putToBed(a1); putToBed(a2);
This whole concept also applies to interfaces which allow you to apply common contracts to objects that don't share a supertype relation:
public interface Sleepable { public void sleep(); }
public class Cat implements Sleepable { public void sleep() { /* curlUpAndSleep */ } }
public class Dog implements Sleepable { public void sleep() { /* stretchOutAndSleep */ } }
...
public void putToBed(Sleepable a) { a.sleep(); }
There is no difference in the instantiation. In both cases you are allocating space on the Heap for a B object.
The difference is in the assignment and the type of the reference variables.
A obj = new B();
In this case, the reference variable obj is of type A (parent). So when calling behaviours on obj you can only call methods that exist in A.
B obj = new B();
In this case, the reference variable obj is of type B (child). So when calling behaviours on obj, you can call methods that have been inherited by the child B from its parent A, and also methods that only exist in B.
In case
A a = new B()
Instace of type B is created but refference is in parent type. Using it you are not able to access fields or call methods specific for B type.
Let me add some code in your Question...
public class A{
void base(){
print("base method");
}
}
public class B extends A{
void child(){
print("child method");
}
}
.......
A obj1 = new B();
B obj2 = new B();
Now Call both method by object
obj1.base(); //base method
obj1.child(); //create compile time error
because obj1 is an object of B class but the reference is of A class....
obj1 only can call methods which is in Class A
//but obj2 can call both methods as it inherits Class A and also having reference of its own.
obj2.base(); //base method
obj2.child(); // child method

Classcast exception for inherited classes

I have a class structure like this:
Interface A extends X
Class A_Impl implements A
Interface B extends A
Class B_Impl extends A_Impl implements B
My webservice client returns object of A and I need some parameters from B. So I do is this:
A myA = (A) webservice.getA();
B myB = (B) myA;
But this always throws the ClassCast exception:
java.lang.ClassCastException: A_Impl cannot be cast to B
Am I doing something wrong here ? How can I get some params from B class.
If you have a reference to an object that doesn't implement B, there is no way to cast it to a B. Full stop.
Imagine if it was possible. Then what would this print?
interface A {
int getNumberOfLives();
}
interface B extends A {
boolean isOrange();
}
class A_Impl implements A {
int getNumberOfLives() {return 9;}
}
public class Main {
public static void main(String[] args) {
A a = getA();
B b = (B)a;
System.out.println(b.isOrange() ? "Is orange" : "Is not orange");
}
static A getA() {return new A_Impl();}
}
You cannot get any properties of B when you have an instance of B's supertype A, or any subtype of that other than B. For example, if you wanted to get the value of a field x that is a member of B, but your object is only an A, the field is not even present in the object. So what would the value of it be? That is the reason you can't cast in this direction. If you wan't to access the object like an instance of B, you have to change your webservice.getA() to something that actually returns a B (or a B_Impl)

Categories