I have class B which extends A. I declare object of A and initialise it as B. I want to call method which is not in super class.
Is there an easy way to do it?
or I need to cast every time?
Class A //don't have access to it.
Class B extends A {
methodNotInClassA();
}
I know this works:
Class C {
A obj;
method{
obj = new B();
((B)obj).methodNotInClassA();
}
}
But does something more simpler and nicer exists?
Sadly, you are required to cast every single time, or you have to make a variable that is actually type B. You can check if a variable that is type A is type B, then make a temporary variable something like so:
if(obj instanceof B) {
B tmp = (B) obj;
// Code using tmp instead of obj
}
But that is just about the prettiest you are going to get.
Related
I am new to Java generics. I have written one function like following:
public class C<T extends MyClass> implements MyInterface<T>{
public void f(T obj){
...
obj.getName()
}
}
Above function f is called for two types of objects MySubClass1 and MySubClass2. MySubClass1 and MySubClass2 are two concreter classes inherited from abstract class MyClass and name is an attribute of MySubClass2.
When f is called with object of MySubClass2 , I would like to access name like above. I cannot figure out how to do that.
...and name is an attribute of MySubClass2
Then your method can't rely on it being there, since obj can be anything deriving from MyClass.
This suggests your design should change such that either you have separate methods or you move name to MyClass.
You could do it with an instanceof check and a cast:
if (obj instanceof MySubClass2) {
String name = ((MySubClass2)obj).getName();
}
...but nine times out of ten, using instanceof should make you step back and reconsider your design.
In a generic method that takes T constrained to MyClass only methods of MyClass are available. Since getName is implemented only in MySubClass2, you cannot access getName without a cast to MySubClass2, which goes contrary to the point of making your f() method generic in the first place.
You can pass a Function object that pulls name from T to f(), like this:
public void f(T obj, Function<T,String> getName){
...
String name = getName.apply(obj);
}
The caller would invoke f() like this:
MySubClass2 s2 = new MySubClass2();
MyInterface<MySubClass2> c = new C<>();
c.f(s2, MySubClass2::getName);
Note that this technique lets you call f on MySubClass1 objects, as long as you provide some way of getting a name:
MySubClass1 s1 = new MySubClass1();
MyInterface<MySubClass1> c = new C<>();
c.f(s1, x -> "<no-name>");
I have different objects(Object A and object B). But some of the objects' fields are same. I can't change the object classes( i mean i cant write a implement/extends condition for them). I want to pass the objects to a method which uses the objects' fields They have same fields. I don't want to overloading. Which design is the most suitable for this?.
A obj1 = new A();
B obj2 = new B();
update(obj1);
update(obj2);
// my function
public <T extends myInterface> void update(T obj)
{
obj.field+=1;
}
public interface myInterface{
int field=0;
}
--------------
public class A{
int field;
.... // smt else
}
--------------
public class B{
int field;
.... // smt else
}
If you have two classes which do not implement a common interface or share a common base class, you can't really pass them to your function.
The fact that they have a common field doesn't matter.
You have 3 workarounds, none of which is really good:
Have your function accept Object type, and check its type (A or B) inside using instanceof. This is ugly and not recommended as any class can be passed inside, and also your code has to check it's type all the time.
Have your function accept Object type, Use reflection to access field with specific name, in this way:
Field field = obj.getClass().getDeclaredField('myfeild');
Object value = field.get(obj);
This is better in that your code doesn't have to check types, but more unsafe. Any class can be passed to your function, and there's some dark magic which relies on static field names. If field name changes, your code breaks.
Perhaps the best - Implement a wrapper for your objects. It will have two constructors, one for class A and one for class B. The wrapper will remember which kind of object resides inside. In its getField function if will have a single if statement. Have your function accept the wrapper type as the argument.
instanceof can be used indentify class of object. Like this:
public <T extends myInterface> void update(Object obj)
{
if ( obj instanceof A )
{
A a = (A)obj;
a.field+=1;
}
if( obj instanceof B )
{
B b = (B)obj;
b.field+=1;
}
}
class A {
int super_var = 1;
}
class B extends A {
int sub_var = 2;
}
public class Demo{
public static void main(String []args){
A a = new B();
System.out.print(a.sub_var); //compile error
}
}
why this will end with a compile error ? reference (a) referencing to an Object of B it has sub_var so why is it restricted ? why reference (a) can access only the fields in A ?
Let's say you have these classes:
public class Animal() {
// ...
}
public class Fish extends Animal() {
public void swim() {...}
}
If you declared an Animal:
Animal x = new Fish();
and you called the swim() method
x.swim();
Would you expect it to work? I don't think so, because not every animal can swim. That's why you have to explicitly specify that the animal x is a Fish:
((Fish) x).swim();
In your case, if you wanted to call that method, you should specify (technically, it's called cast) the type:
System.out.print(((B)a).sub_var);
Note:
This works similar for methods and variables. I used a method in the example since it's more illustrative.
Edit:
Let's see this example:
Animal x;
if (some_condition)
x = new Fish();
else
x = new Cat();
x.swim();
This restriction exists, because Java won't know if, at execution time, the object assigned to x will have the method swim(). So to avoid this, you have to cast to the respective type to call a method that doesn't exist in superclass.
At first it does sound like it should work. (And in some languages it probably does.) But think about this example:
public class Demo {
public static void main(String []args){
A a = new B();
print( a );
}
public static void print( A arg ) {
System.out.print(arg.sub_var); //compile error
}
}
This functionally does the same thing but the print is in another method. If your version worked, this one could be expected to work too.
But what if someone then does this?
Demo.print( new A() );
This should fail because A doesn't have a sub_var. It would have to throw some kind of runtime error instead.
So the design decision in Java was not to allow this and if you declare a local variable/field/method parameter as type A, then you can only access things that every object that is either A or a subclass is guaranteed to have.
If you want to access more, you need to cast it to the subclass, which will throw an exception if you try it on an object that doesn't fit.
A a = new A();
System.out.print(((B)a).sub_var); //ClassCastException is thrown here
You can not access B members with the reference of Parent object A.
Instead change your println statement like below to access,
System.out.print(((B)a).sub_var);
Is there a variable called sub_var in the parent class ? No. That is why you get the error -
sub_var cannot be resolved or is not a field
See this
System.out.print(a.super_var); //okay
System.out.print(a.sub_var); //compile error
you create an object of type B and assign it to a variable of type A. The type A does not declare sub_var. This field is declared only in type B. the compiler only sees what is declared in type A, although the variable is instantiated to an object of type B.
If you want to access sub_var you would have to cast a to B.
System.out.println( ((B)a).sub_var);
The sub_var is in class B, so you can only access through a reference of class B. To the compiler A a = new B(); means a is an instance of class A.
Is there a work around that will allow me to cast an object of the base class to an object of the derived class?
something like the following
B extends A
A a = new A();
B b = (B)a
Is there a trick that will achieve this?
No, absolutely not. What would you expect the values of any fields declared in B but not in A to be? For example, what would you expect this to do:
Object x = new Object();
String text = (String) x;
System.out.println(text);
An Object has no text data... so what would it mean to cast it as a string?
You can only cast a reference to a type which is appropriate for the actual type of the object.
The desire to do this usually indicates a design problem somewhere... or it might mean that you want something like:
public class A {
public A() {
// Whatever
}
public A(A a) {
// Use the existing values in "a" to initialize this object
}
}
public class B extends A {
/** Creates a new B from the values in an A, with suitable defaults. */
public B(A a) {
super(a);
// Now initialize any fields in B with appropriate values
}
}
Then:
A a = new A();
B b = new B(a);
That will create two objects, unlike a cast... but it would at least be valid.
How is that even possible? Think about it. It is like saying if you have a class FourWheeler, you can simply cast it into a Ferrari and make it a Ferrari!
No, this isn't possible. When B extends A it inherits the behavior of A, but on the same time, there is nothing stopping you from defining new behavior for B (where those new behaviors won't be part of A)
For example say A has a single method called 'methodA'. Now when B extends A it inherits 'methodA' but it also declares another method called 'methodB'. So under such circumstance you will get a runtime 'ClassCastException' when you try to call the 'methodB' over an instance of Object A.
I have several subclasses of a class "A", say B, C, and D. I store several of these in a generic
ArrayList<A> stuff;
B, C, and D have absolutely no different data members than A. The only way they differ is by different overridden methods. I would LIKE to be able to copy any instance of class A to another instance of class A (while retaining the true subclass)
Something like:
A obj1 = (A)new B(...)
A obj2 = (A)new C(...)
A obj3 = obj1.copy();
// (obj3 instanceof B) == true
Normally this would require B, C, and D to implement custom copy methods. However, this seems like a waste since the data members are exactly the same, and they would only exist so that the class is preserved.
Is there any way I could get away with only implementing copy in class A, and still preserving the underlying classes of the objects?
EDIT:
If I'm thinking correctly, the problem I would run into if just the superclass had a copy method:
class A {
int dataMember;
public A copy() {
A ret = new A(); // !!
ret.dataMember = dataMember;
return ret;
}
}
When calling "new" I couldn't generically determine what subclass of A the class is, and furthermore explicitly instantiate an instance of that. Or is there a way to do this?
You could give A a copy constructor:
class A {
public A(A other) {
//copy other's fields to this instance
}
}
Subclasses of A could also expose a constructor that took an A instance and passed it to the super constructor:
class B extends A {
public B(A other) {
super(other);
}
}
Are you familiar with clone? It will copy all your fields and mantain the derived class. Be careful that it won't do a clone of each field's object, but they will point to the same reference.
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {} // Will never happen if your object implements the Cloneable interface
}