什么是反射?
* 反射就是获取一个类的字节码文件,然后加载该类的所有的成员
* 成员变量所在类---->Field
* 成员方法所在类---->Method
* 构造方法所在类--->Constructor
* 给成员变量赋值通过Field,调用成员方法Method,通过构造器创建的对象...
*
* 获取一个类的字节码文件 (三种)
*
*
* Class类:
* public static Class<?> forName(String className):参数为当前类的全限定名称
* throws ClassNotFoundException
public class RelectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//获取一个类的字节码文件对象
//1)Object类的getClass()
Person p = new Person() ;
Class c1 = p.getClass();
System.out.println(c1);//class 包名.类名
//Integer-->java.lang.Integer
//Class
//public String getName()
System.out.println(c1.getName());//获取当前Person类的全限定名称 com.qf.reflect_01.Person
System.out.println("-------------------------");
//2)任意Java类型的class属性
Class c2 = Person.class ;
System.out.println(c2);
System.out.println(c2.getName());
System.out.println(c1==c2);
System.out.println("-------------------------");
//3)Class的静态功能
Class c3 = Class.forName("com.qf.reflect_01.Person") ;
System.out.println(c3);//class com.qf.reflect_01.Person
}
}
通过反射获取指定的构造方法(非公共),并创建该类实例
*
* 私有的构造方法不能直接new的
public class Reflect_getCon2 {
public static void main(String[] args) throws Exception {
//获取Person类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person");
//获取指定的构造方法:Constructor
//private Person(String name,int age)
//获取指定的构造方法(包括私有),参数为当前参数类型的字节码文件对象
// public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor con = clazz.getDeclaredConstructor(String.class,int.class) ;
//Constructor:构造器 Method:成员方法,Field:成员变量
//公共的基类:AccessibleObject
//public void setAccessible(boolean flag):取消Java语言访问检查 (参数为true)
con.setAccessible(true);
//创建当前类的实例
// Object obj = con.newInstance("高圆圆",41) ;
// System.out.println(obj);//Person的toString方法
// //Person{name='高圆圆', age=41, address='null'}
System.out.println("----------------------------");
// Person p = new Person("高圆圆",41) ;//已经私有化
}
}
访问Person类的默认修饰符的构造方法,并且创建当前类实例
*
* 类似于 Person p = new Person("高圆圆",41,""西安) ;
*/
public class Refelect_getCon3 {
public static void main(String[] args) throws Exception {
//获取当期类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//获取构造器Constructor
Constructor con = clazz.getDeclaredConstructor(String.class,int.class,String.class) ;
//构造方法:默认修饰符
//取消Java语言访问检查
con.setAccessible(true);
//创建该类实例
Object obj = con.newInstance("高圆圆",41,"鄠邑区") ;
System.out.println(obj);
}
}
/通过反射获取一个类的构造器并且创建当前类对象呢
*
*
* 之前的写法:
* Person perons = new Person() ;
public class Reflect_getCon {
public static void main(String[] args) throws Exception {
//1)获取指定的类的字节码文件对象: com.qf.reflect_01.Person的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//2)通过字节码文件对象获取构造器(Constructor)
//public Constructor<?>[] getConstructors() throws SecurityException
//获取类的所有公共的构造方法
// Constructor[] constructors = clazz.getConstructors();
//public Constructor<?>[] getDeclaredConstructors():可获取当前类中的所有构造方法(包括私有以及默认)
/*Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor con:constructors){
System.out.println(con);
*//**
* public com.qf.reflect_01.Person() :
*
*
* com.qf.reflect_01.Person(java.lang.String,int,java.lang.String)
* private com.qf.reflect_01.Person(java.lang.String,int)
* public com.qf.reflect_01.Person()
*//*
}*/
//通过字节码文件对象获取单个构造方法:公共的
//参数为:可变参数 ...(类似于数组:参数可以有很多个)
//如果存在参数:必须参数类型的Class String ---->java.lang.String
//Person(String name,Integer i)---->参数:java.lang.String, java.lang.Integer
//无参的构造方法:不需要传参
//public Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor con = clazz.getConstructor() ;
//获取了构造器之后:通过构造器创建当前类的实例
// public T newInstance(Object... initargs):参数是给构造方法中赋值的实际参数
Object obj = con.newInstance();
System.out.println(obj);
System.out.println("--------------------");
//之前写法
Person p = new Person() ;
System.out.println(p);
// Person p1 = new Person("高圆圆",20) ;
}
}
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//1)获取指定的类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//方式1:通过无参构造器创建实例
//2)通过反射获取单个公共的构造方法,无参
/* Constructor constructor = clazz.getConstructor();
//System.out.println(constructor);
//3)通过构造器创建当前类实例
Object obj = constructor.newInstance();
System.out.println(obj);*/
//方式2:直接创建当前类实例
//Class类的功能:直接通过当前类的字节码文件对象创建当前类对象
//public T newInstance()
Object obj = clazz.newInstance();
System.out.println(obj);
//public Field[] getFields():获取当前类或者指定接口中的所有的公共的字段
//public Field[] getDeclaredFields():获取当前类中所有的字段(公共的,受保护的,私有的,默认的)
// Field[] fields = clazz.getFields();
/* Field[] fields =clazz.getDeclaredFields() ;
for(Field field:fields){
System.out.println(field);
//公共的字段(成员变量)
//public java.lang.String com.qf.reflect_01.Person.name
*//**
* public java.lang.String com.qf.reflect_01.Person.name
* private int com.qf.reflect_01.Person.age
* java.lang.String com.qf.reflect_01.Person.address
*//*
}*/
//获取指定的单个的字段(成员变量):公共字段
//name:公共的字段
//public Field getField(String name):参数名称为"成员变量名称"
Field nameField = clazz.getField("name");
//给当前Field所代表的的指定的字段name来进行赋值
// public void set(Object obj,Object value)
//将指定的值绑定在当前类的实例上
nameField.set(obj,"高圆圆");
//age:私有的属性
//address:默认修饰符
//在设置值之前,需要取消Java语言访问检查
System.out.println(obj);
System.out.println("---------------------");
//获取age所在的Field对象,为其赋值
//Field getDeclaredField(String name):获取指定的字段Field
Field ageField = clazz.getDeclaredField("age");
//取消Java语言访问检查
//私有属性
ageField.setAccessible(true);
//赋值
ageField.set(obj,41);
System.out.println(obj);
System.out.println("----------------------------");
Field addressField = clazz.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"西安市");
System.out.println(obj);
}
}
通过反射方式来调用Person类中的成员方法(非静态的)
通过反射方式来调用Person类中的成员方法(非静态的)
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//获取Person类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person");
//获取当前类的所有的公共的成员方法:有自己的,还有继承的
//public Method[] getMethods()
//public Method[] getDeclaredMethods():获取类或者接口中的指定的成员方法(公共,默认,私有,受保护)
/* Method[] methods = clazz.getDeclaredMethods() ;
// Method[] methods = clazz.getMethods();
for(Method method :methods){
System.out.println(method);
}*/
//之前的写法:
//无参构造方法创建对象:
//Person p = new Person() ;
// p.show() ;
Constructor con = clazz.getConstructor();
//创建Person类的实例
Object obj = con.newInstance();
//通过反射获取成员方法所代表的的Method对象
//获取公共的成员方法
//参数1:方法名
//参数2:当前该方法的形式参数类型的Class
//public Method getMethod(String name ,Class<?>... parameterTypes)
Method showMethod = clazz.getMethod("show");
//要执行showMethod方法: show()
//Method
//参数1:当前类的实例
//参数2:给方法形式参数传递的实际参数
//返回值:就是调用当前方法本身的时候,如果方法是没有具体返回值,那么直接单独调用
//如果有返回值类型,那么就使用Object来结束即可!
//public Object invoke(Object obj, Object... args):
Object returnObj = showMethod.invoke(obj);
System.out.println(returnObj);
System.out.println("----------------------");
//获取function方法并调用
//Method getDeclaredMethod(String name,Class...parameterNames)
//获取指定的Method
Method functionMethod = clazz.getDeclaredMethod("function", int.class);
//取消Java语言访问检查
functionMethod.setAccessible(true);
Object retunrObj2 = functionMethod.invoke(obj, 27);
System.out.println(retunrObj2);
System.out.println("----------------------");
Method methodM = clazz.getDeclaredMethod("method") ;
methodM.setAccessible(true );
Object returnObj3 = methodM.invoke(obj);
System.out.println(returnObj3);
/* Person p = new Person() ;
System.out.println(p.show());*/
//通过反射调用function方法以及method 方法
}
}
反射的应用1
* 面试题
* 现在有一个ArrayList<String>,如何实现给里面存储Integer类型呢?
*
* 可以,通过反射方式操作:-----获取Class---->Method--->invoke(当前类实例,方法实际参数)
*/
public class Test {
public static void main(String[] args) throws Exception {
//创建一个ArrayList<String>
ArrayList<String> array = new ArrayList<String>() ;
array.add("hello") ;
array.add("world") ;
array.add("javaee") ;
System.out.println(array);
System.out.println("--------------------");
// array.add(100) ;
//通过反射方式调用add方法
//Object的getClass()获取字节码文件对象
Class clazz = array.getClass() ;
//clazz创建当前类实例
Object obj = clazz.newInstance();//通过反射创建
//获取Method对象:方法名 add
Method addMethod = clazz.getMethod("add", Object.class);
//调用方法
addMethod.invoke(obj,"mysql") ;
addMethod.invoke(obj,100) ;
addMethod.invoke(obj,50) ;
System.out.println(obj);
}
}
反射的应用2:
* Class.forName("全限定名称"):参数为字符串:被经常用在配置文件中
public class Test2 {
public static void main(String[] args) throws IOException, ClassNotFoundException,
IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//创建一个学生类
Student s = new Student() ;
s.love();
//代码不断变化
//工人类
Worker worker = new Worker() ;
worker.love();
//Java设计开发原则:
//开闭原则: 对现有代码的修改关闭,在现有代码基础进行扩展!
System.out.println("-----------------------------------");
//提供了一个扩展:在src下(类路径下)配置文件class.properties
//读取配置文件获取里面keyvalue属性列表,将它载入到Properties属性集合类中
InputStream inputStream = Test2.class.getClassLoader().
getResourceAsStream("class.properties");
//创建属性集合列表
Properties prop = new Properties() ;
prop.load(inputStream);
System.out.println(prop);
//通过key获取value
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//反射获取当前className里面的类的字节码文件对象
Class clazz = Class.forName(className) ;
// System.out.println(clazz);
//直接当前类实例
Object obj = clazz.newInstance();
//反射获取Method对象
Method method = clazz.getMethod(methodName);
method.invoke(obj) ;
}
}