0x01 前言
学习了本章,那么如何获取类的名称与类的方法,就都可以大概了解,也可以为后面学习之路,扫除一些困难。
0x01.1 目录结构
# 目录结构
├── 反射
│ └── java动态加载类3
│ ├── Test.java (用来做测试的方法)
│ ├── Word.java
0x01.2 例子-Word类(用于理解的)
// 该类具体路径: 反射.java获取类信息3.Word
package 反射.java获取类信息3;
public class Word {
public void start() {
System.out.println("start() 公共方法被成功访问");
}
public void end() {
System.out.println("end() 公共方法被成功访问");
}
public String save(int id, String title, String content) {
return "id: " + id + "; " + "title: " + title + "; " + "content: " + content;
}
public String add(String title, String content) {
return "title: " + title + "; " + "content: " + content;
}
private String upload(String[] files) {
return "upload() 私有方法被成功访问";
}
private String delUpload() {
return "delUpload() 私有方法被成功访问";
}
}
0x02 获取当前类名称的方法
0x02.1 getName()
getName() //得到类名称(包含路径)
// 例如现在获取 int, String, double, Double, void 的类名称(包含路径)
// 可以这样操作
package 反射.java获取类信息3;
public class Test {
public static void main(String[] args) {
Class c1 = int.class;
Class c2 = String.class;
Class c3 = double.class;
Class c4 = Double.class;
Class c5 = void.class;
System.out.println(" ");
System.out.println("============int.class===============");
System.out.println(c1.getName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============String.class===============");
System.out.println(c2.getName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============double.class===============");
System.out.println(c3.getName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============Double.class===============");
System.out.println(c4.getName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============void.class===============");
System.out.println(c5.getName());
System.out.println("====================================");
System.out.println(" ");
}
}
// 运行结果
============int.class===============
int
====================================
============String.class===============
java.lang.String
====================================
============double.class===============
double
====================================
============Double.class===============
java.lang.Double
====================================
============void.class===============
void
====================================
// 获取普通类的路径,也是一样的例如获取一下 0x01.2 例子-Word类 的类名称(包含路径)
package 反射.java获取类信息3;
public class Test {
public static void main(String[] args) {
Class w = Word.class;
System.out.println(w.getName());
}
}
// 运行结果
反射.java获取类信息3.Word
0x02.2 getSimpleName()
getSimpleName() //得到类的简写名称(不包含包路径)
// 例如现在获取 int, String, double, Double, void 的类名称(不包含包路径)
// 可以这样操作
package 反射.java获取类信息3;
public class Test {
public static void main(String[] args) {
Class c1 = int.class;
Class c2 = String.class;
Class c3 = double.class;
Class c4 = Double.class;
Class c5 = void.class;
System.out.println(" ");
System.out.println("============int.class===============");
System.out.println(c1.getSimpleName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============String.class===============");
System.out.println(c2.getSimpleName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============double.class===============");
System.out.println(c3.getSimpleName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============Double.class===============");
System.out.println(c4.getSimpleName());
System.out.println("====================================");
System.out.println(" ");
System.out.println("============void.class===============");
System.out.println(c5.getSimpleName());
System.out.println("====================================");
System.out.println(" ");
}
}
// 运行结果
============int.class===============
int
====================================
============String.class===============
String
====================================
============double.class===============
double
====================================
============Double.class===============
Double
====================================
============void.class===============
void
====================================
// 获取普通类的路径,也是一样的例如获取一下 0x01.2 例子-Word类 的类名称(不包含包路径)
package 反射.java获取类信息3;
public class Test {
public static void main(String[] args) {
Class w = Word.class;
System.out.println(w.getSimpleName());
}
}
// 运行结果
// 只返回类一个 Word.java 的类名称 Word
Word
0x03 获取当前类所有的方法
0x03.1 getMethods()
getMethods() // 获取的是所有的public的方法,包括父类继承而来的
// 例如现在要获取 0x01.2 例子-Word类 所有public的方法,包括父类继承而来的
package 反射.java获取类信息3;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
// 获取Runtime类对象
Class w = Class.forName("反射.java获取类信息3.Word");
// 通过类类型,创建该类对象
Object wObject = w.newInstance();
// 获取类对象的运行时类的Class对象
Class wc = wObject.getClass();
/**
* Method类, 方法对象
* 一个成员方法就是一个Method类对象
* getMethods()方法 获取的是所有的public的函数方法, 包括父类继承而来的
*/
Method[] ms = wc.getMethods();
for (int i = 0; i < ms.length; i++) {
System.out.println(" ");
System.out.println("====================================");
System.out.println("方法名称是: " + ms[i].getName());
// 获取参数类型-->得到的是参数列表的类型的类类型
Class[] paramTypes = ms[i].getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
System.out.println(
" " +
"参数" + (j+1) +
"类型: " + paramTypes[j].getName() + ","
);
}
System.out.println("方法的返回值的类类型: " + ms[i].getReturnType());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 运行结果
// 其中 add, start, save, end 是 Word类的公共方法
// 其他的都是 Word类的默认父类方法
====================================
方法名称是: add
参数1类型: java.lang.String,
参数2类型: java.lang.String,
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: start
方法的返回值的类类型: void
====================================
方法名称是: save
参数1类型: int,
参数2类型: java.lang.String,
参数3类型: java.lang.String,
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: end
方法的返回值的类类型: void
====================================
方法名称是: wait
参数1类型: long,
参数2类型: int,
方法的返回值的类类型: void
====================================
方法名称是: wait
参数1类型: long,
方法的返回值的类类型: void
====================================
方法名称是: wait
方法的返回值的类类型: void
====================================
方法名称是: equals
参数1类型: java.lang.Object,
方法的返回值的类类型: boolean
====================================
方法名称是: toString
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: hashCode
方法的返回值的类类型: int
====================================
方法名称是: getClass
方法的返回值的类类型: class java.lang.Class
====================================
方法名称是: notify
方法的返回值的类类型: void
====================================
方法名称是: notifyAll
方法的返回值的类类型: void
0x03.2 getDeclaredMethods()
getDeclaredMethods() // 获取的是所有该类自己声明的方法,不问访问权限
package 反射.java获取类信息3;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
// 获取Runtime类对象
Class w = Class.forName("反射.java获取类信息3.Word");
// 通过类类型,创建该类对象
Object wObject = w.newInstance();
// 获取类对象的运行时类的Class对象
Class wc = wObject.getClass();
/**
* Method类, 方法对象
* 一个成员方法就是一个Method类对象
* getDeclaredMethods()方法 获取的是所有该类自己声明的方法
* 不问访问权限,父类继承来的就没有类,必须是该类自己声明的,才能获取
*/
Method[] mds = wc.getDeclaredMethods();
for (int i = 0; i < mds.length; i++) {
System.out.println(" ");
System.out.println("====================================");
System.out.println("方法名称是: " + mds[i].getName());
// 获取参数类型-->得到的是参数列表的类型的类类型
Class[] paramTypes = mds[i].getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
System.out.println(
" " +
"参数" + (j+1) +
"类型: " + paramTypes[j].getName() + ","
);
}
System.out.println("方法的返回值的类类型: " + mds[i].getReturnType());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 运行结果
// 获取的是 Word这个类所有的方法
====================================
方法名称是: add
参数1类型: java.lang.String,
参数2类型: java.lang.String,
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: start
方法的返回值的类类型: void
====================================
方法名称是: save
参数1类型: int,
参数2类型: java.lang.String,
参数3类型: java.lang.String,
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: upload
参数1类型: [Ljava.lang.String;,
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: delUpload
方法的返回值的类类型: class java.lang.String
====================================
方法名称是: end
方法的返回值的类类型: void
0x04 调用某个类指定的成员方法
通过 getMethods() 与 getDeclaredMethods() 方法, 我们学习到了如何去获取类的名称和参数类型与返回类型。
那么如果我现在想要调用 某个类的指定方法 那就可以使用此方法。
0x04.1 getMethod()
getMethod() // 获取的是当前类某个public的方法,包括父类继承而来的
# 使用方法:
# 方法1:
Method method = clazz.getMethod("方法名");
# 方法2:
Method method = clazz.getMethod("方法名", 方法参数类型,多个参数用","号隔开);
Method method = clazz.getMethod("方法名",String.class, int.class);
0x04.2 getDeclaredMethod()
getDeclaredMethod() // 获取的是该类自己声明的某个方法,不问访问权限
# 使用方法:
# 方法1:
Method method = clazz.getDeclaredMethod("方法名");
# 方法2:
Method method = clazz.getDeclaredMethod("方法名", 方法参数类型,多个参数用","号隔开);
Method method = clazz.getDeclaredMethod("方法名",String.class, int.class);
0x04.3 invoke() - 通过反射调用方法
# 反射调用方法
获取到java.lang.reflect.Method对象以后我们就可以通过Method对象的invoke方法来调用类方法
# 调用类方法代码例子:
method.invoke(方法实例对象, 方法参数值,多个参数用","号隔开);
method.invoke(方法实例对象, "参数值1", "参数值2", "参数值3");
0x04.4 getMethod() 与 getDeclaredMethod() 使用例子
因为 getMethod() 与 getDeclaredMethod() 两个在实际调用中是一样的,
所以就不一个个区分啦
# 例子1-调用无参数的公共start()方法
# 使用的getMethod()
package 反射.java获取类信息3;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class w = Class.forName("反射.java获取类信息3.Word");
// 通过类类型,创建该类对象
Object wObject = w.newInstance();
// 获取Word类 start方法
Method a = w.getMethod("start");
// 调用Word类 start方法
Object aa = a.invoke(wObject);
System.out.println(aa);
} catch (Exception e) {
e.printStackTrace();
}
}
}
# 运行结果
start() 公共方法被成功访问
null
# 例子2-调用有参数的公共save()方法
# 使用的getMethod()
package 反射.java获取类信息3;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class w = Class.forName("反射.java获取类信息3.Word");
// 通过类类型,创建该类对象
Object wObject = w.newInstance();
// 获取Word类 save方法
Method a = w.getMethod("save", int.class, String.class, String.class);
// 调用Word类 save方法
Object aa = a.invoke(wObject, 1, "标题1", "内容1");
System.out.println(aa);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 运行结果
id: 1; title: 标题1; content: 内容1
# 例子3-调用有数组参数的私有upload()方法
# 使用的getDeclaredMethod()
# 注意: 在调用私有方法的时候
# 必须要在使用 getDeclaredMethod() 的时候设置 setAccessible(true);
# 不然无法调用私有方法
package 反射.java获取类信息3;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class w = Class.forName("反射.java获取类信息3.Word");
// 通过类类型,创建该类对象
Object wObject = w.newInstance();
// 获取Word类 upload方法
Method a = w.getDeclaredMethod("upload", String[].class);
// 忽略访问修饰符的检查,这样就可以调用私有方法或是成员变量
a.setAccessible(true);
// 这里有个坑
// 当我们的参数是数组的时候, 不能想当然的传个数组进去
// 不然会提示:
// java.lang.IllegalArgumentException: wrong number of arguments
// 这是因为在java中 对方法传一个数组的时候, java会认为是多个参数
// 解决方案: 把 fileArr 改为 new Object[]{fileArr} 传进去即可
String[] fileArr = new String[]{"上传1", "上传2"};
// 调用Word类 upload方法
Object aa = a.invoke(wObject, new Object[]{fileArr});
System.out.println(aa);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 运行结果
upload() 私有方法被成功访问