Java Reflection, java.lang.IllegalAccessException Error
My goal is:
Third class will read the name of the class as String from console.Upon reading the name of the class, it will automatically and dynamically (!) generate that class and call its writeout method. If that class is not read from input, it will not be initialized.
And I am taking java.lang.IllegalAccessException: Class deneme.class3 can not access a member of class java.lang.Object with modifiers "protected"
error. And ı don't know how ı can fix it..
Can anyone help me?
import java.io.*;
import java.lang.reflect.*;
class class3
{
public void run()
{
try
{ 开发者_如何学编程
BufferedReader reader= new BufferedReader(new InputStreamReader(System.in));
String line=reader.readLine();
Class c1 = Class.forName("java.lang.String");
Object obj = new Object();
Class c2 = obj.getClass();
Method writeout = null;
for( Method mth : c2.getDeclaredMethods() ) {
writeout = mth;
break;
}
Object o = c2.newInstance();
writeout.invoke( o );
}
catch(Exception ee)
{
System.out.println("ERROR! "+ee);
}
}
public void writeout3()
{
System.out.println("class3");
}
}
class class4
{
public void writeout4()
{
System.out.println("class4");
}
}
class ornek {
public static void main(String[] args) {
System.out.println("Please Enter Name of Class : ");
class3 example = new class3();
example.run();
}
}
what function are you trying to execute exactly? looks to me like you are just picking the first method without actually checking what it is. try to pick a specific method which is public.
It's not clear what you are doing in your code.
It seems like, first you declare c1
that is java.lang.String
without using it.. then you load a new java.lang.Object
, go through its declared methods and you choose the first one found as writeout
and you try to invoke it without ever knowing what you are calling.
To do what you tried to explain I suggest you to:
Define an interface like Invokable
with a method that you want to call dynamically, for example
interface Invokable {
public void invokeMe();
}
Then whenever you generate a new class by loading the name you can cast it to your interface and call that method without going crazy:
Class<?> class = Class.forName("your.YourClass");
Object target = class.newInstance();
if (target instanceof Invokable)
((Invokable)target).invokeMe();
(of course YourClass
will have to implement the Invokable
interface)
This approach clearly defines what the program will be able to instantiate dynamically and what you are supposed to be allowed to do with these objects without worrying about searching for methods or allow strange things to happen..
This is the most glaring problem with your code:
Method writeout = null;
for( Method mth : c2.getDeclaredMethods() ) {
writeout = mth;
break;
}
You're just grabbing the first declared method of c2
, which is Object.class
. Who knows what the method is? (in my case it's protected void java.lang.Object.finalize() throws java.lang.Throwable
, by the way).
Another problem is earlier:
String line=reader.readLine();
// presumably you're reading the name of the class to find here...
Class c1 = Class.forName("java.lang.String");
// why do you need String.class? what is c1 used for?
Object obj = new Object();
Class c2 = obj.getClass();
// so now c2 is Object.class? what are you trying to accomplish?
Presumably you may want to do this instead:
- Read the name of the class to find
- Find that class using
Class.forName
- Reflect on that class to find the
writeout*
method
That means something like this:
String line = reader.readLine();
Class<?> writeoutClass = Class.forName(line);
Method writeout = null;
for (Method mth : writeoutClass.getDeclaredMethods()) {
if (mth.getName().startsWith("writeout")) {
writeout = mth;
break;
}
}
Object o = writeoutClass.newInstance();
writeout.invoke(o);
This will print "class3"
and "class4"
depending on the class name you type in. You'd need to make it more robust, but it illustrates the idea.
It should be mentioned that if possible, you should make these dynamically created type implements SomeInterface
(see Jack's answer). Also read Effective Java 2nd Edition, Item 53: Prefer interfaces to reflection.
Looks like it will it will try to call the first method of Object
. Seems to have picked up clone
. That will require setAccessible(true)
. There are probably other problems with your code.
The above seems very confused to me. In no order:
- you're not using the name of the class entered on standard input
- you're loading a class via
forName()
, but it's not the one you specify in 1. above - you should find the
writeout()
method of that class usinggetDeclaredMethods()
or similar.
In short, I think you have all the required methods/APIs you need to load a class that someone specifies on the command line, instantiate an instance, and then call a method. It's just that at the moment your class loading/method location isn't doing the above.
精彩评论