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.
Related
I have found following code:
public class Ex7 {
static class Translator<T1, T2 extends String> {
T2 translate(T1 what) {
return what + " ";
}
}
public static void main(String[] args) {
System.out.println(
new Translator<Integer, String>().translate(1)
);
}
}
I don't understand why this code doesn't compile, since T2 is String and i want to return
String from the method "translate", compiler says that it expects T2 instead of String, but i understand that T2 is string as is is stated here:
new Translator<Integer, String>().translate(1)
Can someone please, explain this to me?
T2 extends String is legal, but nonsensical. Nothing extends String, because it's a final class. However, the compiler doesn't stop you writing this because it doesn't consider final-ness of the bounding class.
Put String aside for a second, and consider these classes:
class A {}
class B extends A {}
If you declare a class like this:
static class Translator<T1, T2 extends A> {
T2 translate(T1 what) {
return new A();
}
}
you can hopefully see why this would be illegal:
Translator<String, B> t = new Translator<>();
B result = t.translate("");
Here, result is expected to be an instance of B; but the implementation of the method means that it's returning an A. This is guaranteed to fail, so it's forbidden.
The compiler doesn't consider String any differently from A in this regard: there might be a subclass, so it bans you from returning a String where a subclass might be expected to be returned.
since T2 is String
This is the essential part. A generic class is a template for instances that can use various types. If the method signature defines T2 it remains generic even if it has a constraint like extends String. T2 is never String, it is some unknown type that should extend String.
If the generic class does not consider that and returns a String it violates the method definition of returning T2.
Without irrelevant pieces, I have:
public interface A {
// contents
}
public class B implements A {
// contents
}
I'd like to follow the dependency interjection pattern by instantiating the object of class B in my main method then passing it into class C's constructor, instead of instantiating it in C's constructor.
public class C {
private final B object;
private int D;
}
public C(A object) {
B = object;
D = object.method();
}
public static void main(String[] args){
C finalobject = new C(new B);
}
Essentially, I want to do something similar to what this question is based on.
I get the error:
C.java:137: error: incompatible types: B cannot be converted to A
C finalobject = new C(new B());
How do I pass B into C's constructor with the interface as the parameter?
I've tried casting it, and I can't instantiate it as the interface in the first place for obvious reasons. I can't pass it in as the object's class type not only because it doesn't fit the specifications I have for how this program has to behave, but I'd like to learn how to do what I've been trying to do.
You're forgetting that there could also be a D, E, F, and G classes that implement A interface. Meaning what you're doing is wrong conceptually. Of course you know what you're passing inside and you know it is an instance of class B, however Liskov's Substitution Principle would suggest that you either deal entirely with B or deal entirely with A depending on what fits the role better. You shouldn't ever need to cast to a derived class.
So that said, your solution is simply the following:
public class C {
private final A object;
private int D;
}
Any methods you need to call in B should be added accordingly to A, and if you don't think that A is suited to have certain methods, then you should ask yourself if you should be passing an A instance to C to begin with.
Hope that helps!
The definition of class C should be:
public class C {
private final A object;
private int D;
}
If you really need a B in C class, you have to change the C constructor to:
public C(B object) {
B = object;
D = object.method();
}
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();
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)
Let's have class A with a method useful for chaining:
class A {
A foo() {
// do stuff
return this;
}
}
You could now do a.foo().foo().foo() (think: builder pattern). Let class B extend it:
class B extends A {
}
B b;
Now invoking b.foo() returns actual type B, but declared A. Therefore I cannot write:
B other = b.foo();
I would have to write either:
B other = (B) b.foo();
Or override foo() in B:
class B extends A {
#Override
B foo() {
super.foo();
return this;
}
}
Is there a nice way to do this?
Did this by implementing an additional generic method as(type) to the superclass. This helps to have a nicer cast for fluent interfaces.
class A {
public A foo() {
return this;
}
#SuppressWarnings("unchecked")
public <T extends A> T as(Class<T> clazz) {
return (T) this;
}
}
class B extends A {}
So you can write a.foo().as(B.class).methodOfB(..). And you do not need to reimplement foo() in all subclasses.
Sorry, but no you already listed the nicest way:
B other = (B) b.foo();
That would be the solution for any developer, who uses classes A and B.
Overwriting is for you, so that other developers could simply write B other = b.foo();
But there is actually no other way for the compiler to know, that
B is sort of an A
B is compatible, so that you won't use any information when instantiating an A but putting it in a B
The last one is the reason why you have to cast explicitly. Example:
int myInt = 2;
short myShort = (short) myInt; // correct
although this works, the compiler needs you to be explicit, because in many cases (when myInt is big) you will loose precision / information when casting to short.
If this one would work:
short myShort = myInt; // wrong
Then the compiler would make an assumption on its own. But only the developer can know, if myInt will ever have a value that is bigger than a short can hold.
You can declare class A to have a generic type parameter of its implementing class and foo() could return this dynamic type:
class A<T extends A<T>> {
#SuppressWarnings("unchecked")
T foo() {
// do stuff
return (T) this;
}
}
class B extends A<B> {
B bar() {
// do other stuff
return this;
}
}
After this, the following is valid:
B b = new B();
b.foo().bar();
I think the nice way to do this is to keep the reference as type A, since this is the least specific class that has the functionality that you require:
A other = b.foo();
You should only cast to type B if B contains some required functionality:
B another = (B)A;
another.somethingElse();
This is the same logic that makes:
List<String> myList = new ArrayList<>();
more desirable than:
ArrayList<String> myList = new ArrayList<>();