How to find out the subclass from the base class instance? - java

Is there a way to find out the name of derived class from a base class instance?
e.g.:
class A{
....
}
class B extends A{
...
}
class c extends A{
...
}
now if a method returns an object of A, can I find out if it is of type B or C?

using either instanceof or Class#getClass()
A returned = getA();
if (returned instanceof B) { .. }
else if (returned instanceof C) { .. }
getClass() would return either of: A.class, B.class, C.class
Inside the if-clause you'd need to downcast - i.e.
((B) returned).doSomethingSpecificToB();
That said, sometimes it is considered that using instanceof or getClass() is a bad practice. You should use polymorphism to try to avoid the need to check for the concrete subclass, but I can't tell you more with the information given.

Have you tried using instanceof
e.g.
Class A aDerived= something.getSomethingDerivedFromClassA();
if (aDerived instanceof B) {
} else if (aDerived instanceof C) {
}
//Use type-casting where necessary in the if-then statement.

Short answer to your question
Is there a way to find out the derived class's name from a base class object?
no, the super-class has no way of telling the name/type of a sub-class.
You have to interrogate the object (which is an instance of a sub-class) and ask if it is an: instanceof a particular sub-class, or call it's getClass() method.

You can do it in the subclass' constructor
class A {
protected String classname;
public A() { this.classname = "A"; }
public String getClassname() { return this.classname; }
}
class B extends A {
public B() {
super();
this.classname = "B";
}
}
So
A a = new A();
a.getClassname(); // returns "A"
B b = new B();
b.getClassname(); // returns "B"
((A)b).getClassname(); // Also returns "B"
Because it is casted into an "A" object, it will call the "A" getClassname() function but will return a value set by the constructor that was the "B" constructor.
Note: Call super(); before setting it

There are 2 ways I can think of
1) One with Using the Java reflection API
2) Other one would be with the instanceOf
Other method can be a Comparing objects to objects, I dont know how it might be, you can try this

Is there a way to find out the name of derived class from a base class instance?
As answered here, you can use this extremely simple approach.
abstract class A {
public final String getName() {
return this.getClass().getName();
}
}
class B extends A { }
class C extends A { }
then simply print the current class name:
B b = new B();
C c = new C();
System.out.println(b.getName());
System.out.println(c.getName());
Output:
com.test.B
com.test.C
There is no need to store additional Strings, check instanceof or override the method in any subclass.

A more modern approach (Java 16+) would be using pattern matching for the instanceof operator. The syntax is pretty simple:
if(x instanceof X xChild){
// use xChild
}
It is both shorter and less error-prone as it combines all the steps of testing the runtime type of the variable(x in the example above), casting it down, and assigning it to a new variable(`xChild in the example above). Read more.
Another example:
public void addUIControl(UIControl control) {
if(control instanceof SelectList sl){
selectList = sl;
}
else if(control instanceof TextBox tb){
textBox = tb;
}
else if(control instanceof Button btn){
button = btn;
}
else {
throw new IllegalArgumentException("Uknown UIControl object has been passed to the SendFormMediator");
}
}

Related

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 - Pass Class as Parameter for Comparison

Essentially what I want to do is pass a class as a parameter so that I can preform an instanceof comparison.
public class MyClass
{
Object o = something;
public void myMethod(Class c)
{
if(o instanceof c)
{
do something
}
}
}
Where the parameter Class c is any class that I choose to pass in from else where. Essentially I want to be able to pass in any class and make a comparison.
Any help would be appreciated.
Thanks
You can call Class#isInstance(Object obj):
if(c.isInstance(o)) {
Determines if the specified Object is assignment-compatible with the object represented by this Class. This method is the dynamic equivalent of the Java language instanceof operator.
Just let the method accept Object. In Java all classes extend from Object.
public class MyClass
{
Object o = something;
public void myMethod(Object c)
{
if(o.isInstance(c))
{
do something
}
}
}

Overriding a chained method

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<>();

Is there any way to know the type of an Object?

The scenario is that I am passing an object as a parameter in a method and I want to perform operations based on the type of that object within the method.
Sample code is:
method(Object object){
//if object== String type print string
}
Use instanceof keyword. The keyword instanceOf in java programming language is a boolean operator that is used to test whether an object is of an specified type or not and returns the value accordingly.
if(object instanceof String) {
}
Try
if (object.getClass().getName().equals("Class1Name"))
//do something.
The advantage of getClass instead of instanceof is that you do not need to know the class type at compile time.
You can use the instanceof operator in java.
Please check the bellow link
Click here for an example
If you want method to react differently according to the parameter you should overload it
public void method(String s) {
}
public void method(Integer i) {
}
public void method(SomeClass o) {
}
Use instanceof operator to check the type and cast appropriately
You can use the instanceof keyword. Be forewarned, though; this is not normally a good practice unless you're absolutely unsure of what kind of Object you'll be passing through.
The good practice is using polymorphism ..
Where you have a parent class that has a property that represent which childType is this,
class Parent { string type; public string getType() { return type; } }
class ChildA extends Parent { ChildA() { type = "ChildA"; }
class ChildB extends Parent { ChildB() { type = "ChildB"; }
public void function (Parent p)
{
if (p.getType() == "ChildA")
{
// A
}
else if (p.getType == "ChildB")
{
// B
}
}
If you plan just to print something, you can use toString() method that will be override on each different type of object ;)
just use something like the code bellow and let each class have a different toString() method:
method(Object object){
// ... object.toString();
}
I think you can use getclass() method instead.

using instanceof operator in Java

I have a base class called class Base and two children classes
class A extends Base
and
class B extends Base
I have a method foo in Base.
Rather than putting the implementation of foo in class A and class B, so that I can do
void foo (Object o)
{
// A's implementation
assert o instanceof A;
}
void foo (Object o)
{
// B's implementation
assert o instanceof B;
}
Is there anyway to put foo in Base, and still still be able to check for the runtime class? I've thought of something like this:
void foo (Object o)
{
// Check that o is instanceof a runtime class
assert o instanceof this.getClass(); // ????
}
Thanks.
You can implement your method like this:
public void foo() {
if (this instanceof A) {
// implementation for A
}
else if (this instanceof B) {
// implementation for B
}
}
But the point of polymorphism is to put the A implementation in A, so that this implementation can use A's private fields to implement the method (same for B, or course).
getClass().isInstance(o)
That said, perhaps you want to constrain the type in a way the compiler can check? Generics can do that:
class Base<T extends Base<B>> {
void foo(T o) { ... }
}
class A extends Base<A> {
#Override void foo(A o) { ... }
}
Then,
new B().foo(new A());
will not compile.
There is class method isAssignableFrom()
getClass().isAssignableFrom(o.getClass())
instanceof will not work since the parameter can not be 'dynamic'.
You could use the isInstance method of Class
void foo (Object o)
{
// Check that o is instanceof a runtime class
assert getClass().isInstance(o);
}
but this has at least one possible problem:
it will result in an AssertionException if this is an instance of a subclass of A and the object is just a direct instance of A!
In Java, you can check the class of an object using the instanceof operator:
object instanceof M
When you have a Class object, it would make sense to write:
object.getClass().isAssignableTo(MyClass.class)
http://www.ralfebert.de/blog/java/isassignablefrom/

Categories