转载出处:https://blog.csdn.net/sinat_38259539/article/details/71799078
1、Class类是被final修饰的类不能被继承
2、Class类的实例表示正在运行的Java应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象 。基本的Java类型(boolean,byte,char,short,int,long,float和double)和关键字void也表示为Class对象。Class对象没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的
一、获取构造方法并使用
自己写的练习demo
Student类
public class Student {
//--------构造方法---------------
//(默认的构造方法)
Student(String str) {
System.out.println("默认的构造方法="+str);
}
//无参的构造方法
public Student(){
System.out.println("调用了公有,无参构造方法");
}
//有一个参数的构造方法
public Student(char name){
System.out.println("姓名:"+name);
}
//有多个参数的构造方法
public Student(String name,int age){
System.out.println("姓名:"+name + "年龄:"+age);
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法n = "+n);
}
//私有方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+age);
}
}
测试类
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Constructors {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class class1 = Class.forName("com.sunj.test.Student");
//获取所有共有的构造方法
System.out.println("获取所有公有的构造方法");
Constructor [] con1=class1.getConstructors();
for (Constructor c1 : con1) {
System.out.println(c1);
}
//获取所有的构造方法
System.out.println("获取所有的构造方法,不管它的修饰符是公有,默认,保护,私有");
Constructor [] con2 = class1.getDeclaredConstructors();
for (Constructor c2 : con2) {
System.out.println(c2);
}
System.out.println("获取公有,无参的构造方法");
Constructor con3 = class1.getConstructor(null);//返回的是该构造方法的类对象
System.out.println(con3);
Object object = con3.newInstance(null);//调用该方法
System.out.println("获取私有构造方法并调用");
Constructor con4 = class1.getDeclaredConstructor(int.class);
System.out.println(con4);
//调用构造方法
con4.setAccessible(true);//忽略掉访问修饰符
object = con4.newInstance(22);
}
}
getDeclaredConstructors和getConstructors方法的区别
1、getDeclaredConstructors是获取所有的构造方法,而getConstructor是获取所有的公有方法
2、两者都可以通过传参拿到指定的构造方法,这里的参数是构造方法的参数的类型,比如构造方法传的String name,那么这里就传的是String.class
调用方法:
1.获取构造方法:
1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2).获取单个的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
调用构造方法:
Constructor-->newInstance(Object... initargs)
2、newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:
newInstance(Object... initargs)
使用此 Constructor
对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用
二、获取成员变量
public class User {
public User(){
}
//*************字段*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", sex=" + sex + ", phoneNum=" + phoneNum + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public String getPhoneNum() {
return phoneNum;
}
public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
}
}
测试类
import java.lang.reflect.Field;
public class Fields {
public static void main(String[] args) throws Exception {
//1、获取class对象
Class class1 = Class.forName("com.sunj.test.User");
//2、获取字段
System.out.println("获取所有的公有字段");
Field[] f1 = class1.getFields();
for (Field field1 : f1) {
System.out.println(field1);
}
//3、获取所有的字段
System.out.println("获取所有的字段");
Field [] f2 = class1.getDeclaredFields();
for (Field field2 : f2) {
System.out.println(field2);
}
//4、获取公有字段并调用
System.out.println("获取公有字段并调用");
Field field1 = class1.getField("name");
System.out.println(field1);
//获取一个对象
Object object = class1.getConstructor().newInstance();//相当于User user = new User();
//为字段设值
field1.set(object, "花花");//相当于user.setName("花花");
//验证
User user = (User)object;
System.out.println(user.name);
//5、获取私有字段并调用
System.out.println("获取私有字段并调用");
Field fi = class1.getDeclaredField("phoneNum");
System.out.println(fi);
fi.setAccessible(true);//忽略私有属性
fi.set(object, "18712111");
user = (User)object;
System.out.println(user.getPhoneNum());
}
}
调用字段时,第一个参数:要传入设置的对象,第二个参数:要传入实参,就相当于平时我们写的对象的set方法
三、获取成员方法并调用
public class Student {
// **************成员方法***************//
public void show1(String s) {
System.out.println("调用了:公有的,String参数的show1(): s = " + s);
}
protected void show2() {
System.out.println("调用了:受保护的,无参的show2()");
}
void show3() {
System.out.println("调用了:默认的,无参的show3()");
}
private String show4(int age) {
System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
return "abcd";
}
}
测试类:
import java.lang.reflect.Method;
public class Methods {
public static void main(String[] args) throws Exception {
Class class1 = Class.forName("com.sunj.test.Student");
// 1、获取所有的公有方法
System.out.println("获取所有的公有方法");
Method[] methods = class1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// 2、获取搜有的方法
System.out.println("获取所有的方法");
Method[] methods2 = class1.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}
// 3、获取公有的show1方法
System.out.println("获取公有的show1方法");
Method m1 = class1.getMethod("show1", String.class);
Object obj = class1.getConstructor().newInstance();
m1.invoke(obj, "你好呐");
// 获取私有的show4方法
System.out.println("获取私有的show4方法");
Method m2 = class1.getDeclaredMethod("show4", int.class);//调用定制方法(包括私有的),需要传入两个参数,第一个是调用的方法名称,第二个是方法的形参类型。
m2.setAccessible(true);//解除私有绑定
Object result = m2.invoke(obj, 18);//调用时需要两个参数,一个是要调用的对象(获取有反射),一个是实参
System.out.println(result);
}
}
注意:获取公有方法时,连父类Object的公有方法也会打印出来
而获取所有的方法时,Object类的方法并没有打印出来。
四、反射main方法
public class Student {
public static void main(String[] args) {
System.out.println("main方法已执行" + args[0]);
}
}
测试类
import java.lang.reflect.Method;
public class Methods {
public static void main(String[] args) throws Exception {
Class class1 = Class.forName("com.sunj.test.Student");
//获取main方法
Method methodMain = class1.getMethod("main", String[].class);
Object obj = class1.getConstructor().newInstance();
methodMain.invoke(null,(Object)new String[]{"a","b","c"});
}
}
反射main方法的调用:
methodMain.invoke(null,(Object)new String[]{"a","b","c"});
五、反射方法的其它使用之---通过反射运行配置文件内容
package com.sunj.test;
public class Student {
public void show(){
System.out.println("is show()");
}
}
配置文件
className = com.sunj.test.Student
methodName = show
测试类
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
* 我们只需要将新类发送给客户端,并修改配置文件
* @author vela_sun
*
*/
public class Demo {
public static void main(String[] args) throws Exception{
//通过反射获取class对象
Class class1 = Class.forName(getValue("className"));
//获取show方法
Object object = class1.getConstructor().newInstance();
Method method = class1.getMethod(getValue("methodName"));
method.invoke(object);
}
//此方法接收一个key,在配置文件获取相应的value
public static String getValue(String key) throws Exception{
Properties properties = new Properties();//获取配置文件
FileReader in = new FileReader("src\\main\\java\\com\\sunj\\test\\pro.txt");
properties.load(in);
in.close();
return properties.getProperty(key);
}
}
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
* 我们只需要将新类发送给客户端,并修改配置文件
* @author vela_sun
*
*/
public class Demo {
public static void main(String[] args) throws Exception{
//通过反射获取class对象
Class class1 = Class.forName(getValue("className"));
//获取show方法
Object object = class1.getConstructor().newInstance();
Method method = class1.getMethod(getValue("methodName"));
method.invoke(object);
}
//此方法接收一个key,在配置文件获取相应的value
public static String getValue(String key) throws Exception{
Properties properties = new Properties();//获取配置文件
FileReader in = new FileReader("src\\main\\java\\com\\sunj\\test\\pro.txt");
properties.load(in);
in.close();
return properties.getProperty(key);
}
}
注意:配置文件和测试类在同一个目录,获取属性文件时的路径也不能直接写名字
当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动
六、反射方法的其它使用之---通过反射越过泛型检查
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* 通过反射机制越过泛型检查
* 例如,有一个String泛型的集合,怎样像这个集合添加一个Integer类型的数据
* @author vela_sun
*
*/
public class Demo {
public static void main(String[] args) throws Exception{
ArrayList<String> list = new ArrayList<String>();
list.add("aa");
list.add("bb");
list.add("cc");
//获取Arraylist的Class对象,反向的调用add()方法,添加数据
Class class1 = list.getClass();
Method method = class1.getMethod("add", Object.class);
method.invoke(list, 100);
for (Object oo : list) {
System.out.println(oo);
}
}
}