Passing Class<?> cls as a method parameter? - java

I'm having trouble completing this method.
I am trying to write a method that will let my main pass two parameters: a Talker object instance and cls a Class object representing the type which the Listener should extend from in order to receive the message. I'm very new to Java and could use some help with this.
Here's the code for the method:
public void sMessage(Talker talker, Class<?> cls) {
for ( Listener l : mParticipants)
{
if (cls.isAssignableFrom(cls.getSuperclass())) {
l.onMessageReceived(talker.getMessage());
}
}
}
Not sure how I should complete this, or how to make a call from main:
singletonDemo.sMessage(demoTalker, Class?);
Not really following the examples I've seen so far. Any suggestions?

#BornToCode is correct about calling the method, but what you want to achieve with the method is still slightly wrong.
cls.isAssignableFrom(cls.getSuperclass())
will always return false. This is because you cannot take a parent class and assign it to the child class. I believe what you are looking for is a way to check if the listener extends the class specified. You can do this by getting the class of the listener.
cls.isAssignableFrom(l.getClass())
or more simply
cls.isInstance(l)

I do not understand what cls should represent. However, you should get something like:
singletonDemo.sMessage(demoTalker, SomeClass.class);
or:
singletonDemo.sMessage(demoTalker, someClassInstance.getClass());
For your information, cls.isAssignableFrom(cls.getSuperclass()) will always return false. The documentation of isAssignableFrom says:
Determines if the class or interface represented by this Class object is either the same
as, or is a superclass or superinterface of, the class or interface represented by the
specified Class parameter.

Related

When is the diamond operator, and when not?

Consider the following two lines of code:
final List<Path> paths = new ArrayList<>();
final FileVisitor<Path> fv = new SimpleFileVisitor<>();
To me, they look quite similar. However, the second line is refused by the Java compiler (1.8) with the message "Cannot infer type arguments for SimpleFileVisitor<>".
Can anyone please explain, what's the problem?
I don't see how you may get the error message Cannot infer type arguments because your syntax is correct, except for the fact that as many have said already, the class java.nio.file.SimpleFileVisitor has only one constructor which is protected:
protected SimpleFileVisitor() {
}
This means that only children of this class can initialize an instance of SimpleFileVisitor, and that's why your code doesn't compile.
I don't know this class, but by a quick look at the code I guess they simply expect you to extend it first (or use an already existing extension coming from somewhere else), and then use it the implementations of the FileVisitor interface.
If you don't have a concrete child class to use and want to create your own MySimpleFileVisitor:
public class MySimpleFileVisitor<T> extends SimpleFileVisitor<T> {
public MySimpleFileVisitor() {
super(); //<-- here you have the right to call the protected constructor of SimpleFileVisitor
}
}
... you will then be able to instantiate your class and use the already implemented methods like this:
FileVisitor<Path> fv = new MySimpleFileVisitor<>(); //<-- here you will be able to correctly infer parameter type as you do in your List example
fv.visitFile(file, attrs); //<-- here you enter the method implemented inside SimpleFileVisitor

Java - how can I loop methods with same name but different parameters

I have class named: ComplexValidator that extends absract class Validator which have two methods:
Validate(Part part);
getAnswer():
I also have validators, lets name them A, B, C and D.
So
AValidator extends Validator
BValidator extends Validator
CValidator extends Validator
DValidator extends Validator
I am not in front of my code right not so I will use pseudo-code.
CValidator takes different parameter than rest of it, A B and D uses part to get filename etc, but CValidator uses numberOfFiles (which are increased in loop (for part p: multipart) so after every time loop is repeated numberoffiles is increased so I can compare it with maxNumberOfFiles field).
Sadly I didnt know how to make abstract class that will take any parameter to method so all methods must take Part part. Cvalidator doesnt use it and I had to make field numberOfFiles static so I can get access to it.
Is there any way to make those validators takes no parameters but no using static?
Is there any way to make abstract class the way that child classes will be able to change arguments it take?
And if it takes other arguments HOW can I loop it all when I have:
List <Validator> validators = new ArrayList<>();
in my ComplexValidator.
and then I add all child validators to it and loop over them like that:
for (Validator v: validators){
validate(part);
}
The types of the parameters of an overriden method must be the same as the original method.
To face your problem I would create a custom class that wraps all the different parameters that you might want to pass to the validate function.
Something like that
class Wrapper{
Part param1;
File param2;
File param3;
}
class Validator{
void validate (Wrapper wrapper);
}
class ValidatorA extends Validate{
void validate (Wrapper wrapper){
//use wrapper.part...
}
}
class ValidatorC extends Validate{
void validate (Wrapper wrapper){
//use wrapper.file...
}
}
You may want to use java reflection. With a Class you can either getMethods and loop throught the methods and getParameterTypes of each method or if you know in advance the types of the method you wish you can getMethod (without s) and provide an array of type.
In your case I would go to the first method and depending on the presence of the second parameter (number of files), invoke the method the good way (with all the parameters needed).

How to execute a method from a subclass inside a "for" whose variable is the superclass?

I have a class named Agent:
abstract public class Agent {
// this class doesn't has the method "method_A"
}
And a class AgentHistoric:
public class AgentHistoric extends Agent{
public void method_A(){
code
}
}
I have also classes RandomAgent, AgentAlways0, etc, all extending the abstract class Agent, but only AgentHistoric has the method "method_A".
Suppose I created AgentHistoric's objetcs, RandomAgent's objetcs, etc, and I have added them to an ArrayList named agents.
In another class, I have the following code:
for (Agent ag: this.agents ){
ag.update(); // all Agent's subclasses have this method
if (ag.returntype() == AgentHistoric){ // I know there's a more elegant way, but OK
method_A() } // error!
}
How can I execute a exclusive method of AgentHistoric in this loop?
Use the instanceof operator to determine if ag is an AgentHistoric. If so, cast ag to an AgentHistoric, then call method_A.
Maybe try to use instanceof operator?
if (ag instanceof AgentHistoric){
...
}
Instead of using instanceof, a more "OO way" of doing it is just NOT override method_A in the classes that you want to run Agent.method_A() or if you want to do additional work, call super.method_A() while in the classes that you want to change the implementation - override the method.
The compiler only knows that the variable ag is of type Agent which, as you said yourself, has no method_A defined. In order to call method_A, you need to cast ag to an instance of AgentHistoric.
As others have said, you can use the instanceof operator to check that the current assignment of ag is in fact an AgentHistoric instance.

How do I typecast an object created through reflection to run a method?

I'm having trouble to find how to typecast the dynamically created class while using reflection.
String s;
...
Class unknownClass = Class.forName(s);
Constructor defaultConstructor = unknownClass.getConstructor(null);
Object retobj = defaultConstructor.newInstance(null);
retobj.Writeout(); // This won't work since;
The object class does not have a method called Writeout, but that is the name of the method which is shared by nine other possible classes that is dynamically created here (needless to say every Writeout method does a seperate thing). Any suggestions ? Thx in advance for your time.
Use reflection Luke...
Method writeOutMethod = unknownClass.getMethod("Writeout", new Class[]{});
writeOutMethod.invoke(retobj, new Object[]{});
Or, ensure that your objects implement a well known interface (the clean approach).
The 9 classes should all implement a single interface (let's call it Output) which declares the writeOut() method. The code would thus be:
Output retobj = (Output) defaultConstructor.newInstance(null);
retobj.writeOut();
Note that you could just use unknownClass.newInstance() to invoke the no-arg constructor.
Side note: please respect tha Java naming conventions: methods start with a lower-case letter.
Cast it:
((YourObjectWithThatMethod) retobj).Writeout();
EDIT (see the comment from Kevin Welker):
If all of your 9 classes implement the same interface, you can cast every class to that interface:
((YourInterface) retobj).Writeout();
If all nine classes share a super-class or an interface which declares/implements writeOut then you can cast retobj to that interface and then call it.
public interface Writable {
public void writeOut();
}
Then each class needs to have in the class declaration.
class MyClass implements Writable {
}
Then you can say
((Writable) retobj).writeOut();

Reflection issue of Android BluetoothService class

I want to call some methods like isEnabled(), getAddressFromObjectPath(), etc. of BluetoothService class, but this class is mark with #hide.
I know I have two possible ways to do what I want, one is remove the #hide, and the other is using reflection. I choose to use second one.
From the example of source code, I found that
Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder b = (IBinder) method.invoke(null, "bluetooth");
if (b == null) {
throw new RuntimeException("Bluetooth service not available");
}
IBluetooth mBluetoothService = IBluetooth.Stub.asInterface(b);
However, what it gets is the IBluetooth not BluetoothService although BluetoothService extends IBluetooth.Stub indeed.
So my questions are as follows:
(1) Could I get the BluetoothService class by reflection just like previous example code ?
(2) If my first question is negative, I call getAddressFromObjectPath() directly by reflection method like following
Method method = Class.forName("android.server.BluetoothService").getMethod("getAddressFromObjectPath", String.class);
String b = (String) method.invoke(???, PATH);
what the object dose I need to fill in the invoke() method, BluetoothService ???
Any suggestion would be greatly appreciated !!!
After surveying on the internet, I got the answer. If I want to invoke a non-static method, I need to get the class and constructor first. Use the constructor to construct the instance and then I could invoke the non-static method by this instance.
However, I could not do that on BluetoothService class because if I do the constructor again, it would cause a lot of problem !
I decide to modify the IBluetooth.aidl to add the methods I need because BluetoothService extends IBluetooth. If I could get the IBluetooth instance, I could call the methods I need. Maybe, this is not a good solution but I think it would work.
Thanks a lot.

Categories

Resources