Cast class to unknown subclass by name? - java

First off, sorry for the confusing title. It even confuses me so I don't wat to think about a better title any more.
Though, let's get to my problem. I have a class Classss. That class has some variables and a doSomething() void.
Now, that class has lots of classes extending that class, with different values of the variables and a different doSomething void. Now, I have the name of a class, something like "com.cool.cool.Cool".
So, I know that that class is a subclass of Classss and I have the name. Is there any way I can load that class by its name and be able to treat it as a Classss?
Thanks in advance.

It seems to me like this the classic case of polymorphism. Where you want to treat all subclasses the same way as the top class.
Basically, you can do this:
Classs c1 = new Cool(); // This works
Classs c2 = new SubClass(); // This works
c1.doSomething(); // Will call the Cool.doSomething() method;
c2.doSomething(); // Will call the SubClass.doSomething method;
You can also use List<Classs> and put subClass object in it...

Maybe something along the lines of:
static Bar getSubclass(String name) throws Exception{
Class<?> c = Class.forName(name);
Constructor<?> con = c.getConstructor();
return (Bar)con.newInstance();
}
This should work, provided name is the fully qualified name of a class that extends Bar and has a no-arg constructor.
class Bar{}
class Foo extends Bar{ public Foo(){} }
This is pretty prone to breaking.

Since your question mentions “load that class by its name” I assume you are using the Class.forName method.
java.lang.Class has an asSubclass method which I believe will do what you want:
Class<?> loadedClass = Class.forName(name);
Class<? extends Classss> type = loadedClass.asSubclass(Classss.class);
Your example name of “Classss” makes the above rather confusing, so I’ll repeat it using the name ExampleService:
Class<?> loadedClass = Class.forName(name);
Class<? extends ExampleService> type = loadedClass.asSubclass(ExampleService.class);
Alternatively, you may want to make use of the service provider facility, which is designed to dynamically search for “plugins,” that is, foreign implementations of an interface or abstract class:
for (ExampleService service : ServiceLoader.load(ExampleService.class)) {
System.out.println("Found subclass: " + service.getClass());
}

Related

return a class implementing an interface using reflections

I'm using reflections to find all classes implementing IAnimal Interface.
but how do I return a class instance using the animals set in the below code:
Reflections reflections = new Reflections(IAnimal.class);
Set<Class<? extends IAnimal>> animals= reflections.getSubTypesOf(IAnimal.class);
I have 3 classes implementing IAnimal interface Dog, Cat, Duck. and I want to apply this logic but I don't know how to do it.
method findAnimal(String animalName){
for (Iterator<Class<? extends Operations>> it = animals.iterator(); it.hasNext(); ) {
String classname=it.Name;
if (classname.eqauls(animalName)){
System.out.println("found");
return new class(); }
}}
I want the findAnimal method to return a class instance if matched with the passed string. i.e., if I passed a "Dog" string as a parameter, the method will return a dog class.
is it possible to do that, any ideas on how to implement the logic in the box above?
So this basically boils down to how to create an instance having the java.lang.Class that represents that type?
You can create an instance by using the following code:
Class<?> cl = it.next();
... if condition, you decide to create the instance of cl
IDog object= cl.getDeclaredConstructor().newInstance(); // will actuall be a Dog, Cat or whatever you've decided to create
Note, you've assumed that the default constructor exists (the constructor without arguments). This kind of assumption is necessary, because you have to know how to create the object of the class of your interest.
If you know, that you have constructor that takes some specific parameters (of specific types) you can pass the parameter types to the getDeclaredConstructor method. For example, for class Integer that has a constructor with one int argument the following will print "5":
Integer i = Integer.class.getDeclaredConstructor(int.class).newInstance(5);
System.out.println(i);

Need assistance with inheritance logic

If I have a subclass called AmericanFender which extends Fender, while Fender extends the superclass BassGuitars, why would something like
AmericanFender amFen = new AmericanFender();
System.out.println(amFen.brand);
not work out to amFen.brand equaling "Fender" when
Fender fen = new Fender()
fen.brand = Fender;
Instead amFen.brand is coming out to be null. I thought since AmericanFender extends Fender, it inherits the instance variables of Fender(which those are inherited from BassGuitars) as long as they are public? I'm obviously thinking about inheritance incorrectly, so could someone steer me in the right direction? Much appreciated!
In inheritance, AmericanFender DOES inherit the instance variables of Fender. This means it will have the same fields as Fender. This does NOT mean it will have the same values in these fields. It will have an empty field called brand, which is what you are seeing.
If you want it to inherit the value, you could make a method inside your Fender class:
public String getBrand() {
return "Fender";
}
And then you can call:
AmericanFender f = new AmericanFender();
System.out.println(f.getBrand());
If you could post a whole part of your code maybe the question would be more specific, however what you might have misunderstood about inheritance is that if a class inherits another class, then the subclass inherits the same fields from the super class but not the value inside the field. For example:
class kid extends parent {
if you have a field named haircolor in the parent class and
parent.haircolor = brown;
then the kid also has a haircolor characteristic but it doesn't equal brown. It equals null until you initialize it.

Detecting Class object equivalence for classes loaded by different ClassLoaders

My Task is to write a unit test for a method findSubClassImplementation that returns an instance for a given Class object. The method signature looks like this:
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception
Internally the method checks wether the supplied Class object belongs to a set of known classes and then returns an instance of that class:
if (Subclass.class.equals(cls))
return (T) new Subclass(args);
If the class is not known, an Exception is thrown. This code is given
I tried to load all Classes inheriting from SuperClass via Reflection and then pass them as argument to findSubClassImplementation:
Set<Class<? extends SuperClass>> subTypesOf = reflections.getSubTypesOf(SuperClass.class);
Class<? extends SuperClass> clazz = subTypesOf.iterator().next();
SuperClass instance = findSubClassImplementation(clazz);
I then use a Debugger to step into the method, and I can see the line of code where
if (Subclass.class.equals(cls))
returns false, although cls = Subclass.class
I assume what happens is this: Class does not implement equals, thus equals of Object is used, that compares with "==". As reflection uses a different ClassLoader than is used in findSubClassImplementation the two class Objects are different. Is this assumption correct?
Is it possible to get the other Class object for a class that I have loaded with Reflection? Do you have another idea how to deal with this problem?
ANSWER:
Turns out I am not very good at reading: The hirarchy is in 3 levels: SuperClass --> IntermediateAbstractClass--> Subclass. The comparison is always to the intermediate abstract class:
if (IntermediateAbstractClass.class.equals(cls)) return (T) new Subclass(args);
Thus my question wasn't very accurate or precise - I am sorry if you feel like I wasted your time. I'll mark Michael Wiles answer as the correct one, because his advice pushed my to discover my missunderstanding. Thank you!
There must be something that is different about the classes...
You say that Subclass.equals(otherSubclass) returns false we need to ascertain why this is the case.
Check the name of each class for equality and then check the classloader of each class for equality.
Based on your provided code to do the reflection there is nothing here to sugggest that these classes loaded by "Reflection" are in fact loaded from different classloaders.
Furthermore try all sorts of classes, maybe there is something unique about that particular class that causes the behaviour.
One suggestion to try would be to add Integer to the subclass set and then pass in Number to the method...
Maybe you don't need to check what class is cls, since cls already contains all the information you need. Try simply with
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
// ... retrieve args
final Class<?>[] constructorParamTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
constructorParamTypes[i] = args[i].getClass();
}
return cls.getConstructor(constructorParamTypes).newInstance(args);
}
Or in the Java 8 way:
public <T extends SuperClass> T findSubClassImplementation(Class<T> cls) throws Exception {
// ... retrieve args
final Class<?>[] constructorParamTypes = Arrays.stream(args).map(Object::getClass)
.toArray(size -> new Class<?>[size]);
return cls.getConstructor(constructorParamTypes).newInstance(args);
}

Java Inheritance Query

Say I have two classes where SubClass inherits from (extends) SuperClass.
What is the difference between:
SuperClass obj1 = new SubClass();
and:
SubClass obj2 = new SubClass();
Both will look to the constructor of the Superclass and initialise it (the correct one, obviously). Both have access to the superclass implementations. But one is (as far as I am aware) a subclass wrapped in a superclass (the first example) and the other is a subclass object (the second example).
How will this effect the way code is run and interpreted?
What are the real world issues that a developer needs to be aware of regarding how these two objects differ?
Thanks in advance for any help!
The only difference with initializing it as a superclass is that if the subclass implementation has methods which the superclass does not, they will not be accessible via this object reference.
But "internally", this is still an instance of the subclass; so, if you call a method defined in the superclass but the subclass has overriden it, it is the subclass' method which is called: the JVM looks up methods from the more specific to the more general.
As a convoluted example, let us take Object and String:
final Object o = "Hello!"; // in fact this calls new String("Hello!")
o.toString(); // <-- uses String's .toString(), not Object's
// Can't do that: String defines .subString() but Object does not
o.subString(1);
It may help to think what the compiler knows about and what the runtime knows and a simple example:
public class Product {
public double getPrice() {...}
}
public class Book extends Product() {
public int getPageCount() {...}
}
and a simple program:
Product p = new Product();
p.getPrice(); // OK
p.getPageCount(); // compiler error
Book b = new Book();
b.getPrice(); // OK
b.getPageCount(); // OK
Product pb = new Book();
pb.getPrice(); // OK
pb.getPageCount(); // compiler error
// but we can still use the getPageCount() of pb;
((Book)pb).getPageCount(); // compiles
// however if pb was not a Book then you would get a runtime error (ClassCastException)
You can test for the actual class by:
if (pb instanceof Book) {
((Book)pb).getPageCount();
}
This is often necessary when developing classes, but if your code has a lot of instanceof it probably needs rethinking.
SuperClass obj1 = new SubClass();
What you're seeing here is a type of substitutability. What this means is, let's say you make another sub class of SuperClass, SiblingClass. Without using the superclass reference type, we would have to change more code, getters and setters, collections that might want to use it. By referencing them as the supertype, all you need to do is pass in the new SiblingClass object on construction.

Java: How to convert a String into an subclass data type?

I want to convert a String to an subclass data type, how can it be done? or it is possible?
I have a abstract class Acct
A public abstract class SinAcct extends Acct
A public class SavAcct extends SinAcct
In SavAcct, there is a constructor
public SavAcct(String acctNo, String name, ConsolidateAccount ownerAcct, double lastMonthBal){
super(acctNo,name,ownerAcct,lastMonthBal);
}
An abstract class ConsolidateAccount extends Account
I want to new a SavAcct,
new SavAcct(array[1],array[2],array[3],Double.parseDouble(array[4])
but it is error The constructor SavAcct(String, String, String, double) is undefined
anyone can help me? pls
Just to be sure you're not going on a wrong path, instead of adding a new constructor which will essentially need to call super(acctNo,name,ownerAcct,lastMonthBal); like this existing constructor, why don't you otherwise try and create or look up ConsolidateAccount instance using your array[3] key?
E.g.
ConsolidateAccount consolidateAccount = new ConcreteConsolidateAccount(array[3]);
new SavAcct(array[1],array[2],consolidateAccount,Double.parseDouble(array[4]);
Where ConcreteConsolidateAccount is a concrete class extending ConsolidateAccount.
Looks like a more sensible thing to do.
Of course I don't know about logic around ConsolidateAccount, or even if it has a constructor that takes a String, but this is just to give you an idea, because it would appear that you need to call the constructor of the class that SavAcct is extending (this is indicated by the super call).
You should be having a concrete class(non abstract class) extending ConsolidateAccount lets say it being
public class ConcreteAccount extends ConsolidateAccount
Then you can use something like this.
ConsolidateAccount ownerAcct = new ConcreteAccount(array[3]);
new SavAcct(array[1],array[2],ownerAcct,Double.parseDouble(array[4]);
and create a constructor public ConcreteAccount(String str) in your ConcreteAccount class
You can't do that because String class is final. Can you make composition instead of inheritance? http://www.artima.com/designtechniques/compoinh.html
If you really want to convert a String to an object of some other class. You can have three possible solutions :-
Create a Constructor which takes String as an argument and does the appropriate conversion to create the Object.
Have a factory method i.e getInstance() which takes String parameter and returns an Object.
You can have a method which can be used for the same purpose as above.
EDIT
Just forgot to mention that String is a final class which can't be modified or inherited in your application.
public Static SubClass getInstance(String str){
SubClass obj = new SubClass();
// ***the choice of constructor depends upon how u have created ur class
//use str to form the SubClass object in following lines
return obj;
}
than you can use it as
SubClass newObj = SubClass.getInstance("String value here");
Not possible, String is final.
The java.lang.String class is final, so there's no way you can extend it. You could at most wrap it.
See Can I add new methods to the String class in Java?
You have an array of Strings and the constructor you are calling needs ConsolidateAccount at the third position. You need to instantiate a subtype of ConsolidateAccount based on that third String. There are no details to help you how to do that. Also, you are indexing the array starting from 1. Arrays are zero-based.

Categories

Resources