反射
什么是反射:
- 反射就是通过获取类的字节码文件对象:Class
- 创建该类的实例(通过构造方法:Constroctor类),调用成员方法(Method类),
- 给成员变量赋值(Field类)
获取字节码文件的方式有几种
三种方式
- 1)Object类的getClass():表中正在运行的Java类(当前类字节码文件)
- 2)任意Java类型的.class属性
- 3)反射Class类中forName(“类或者接口的全限定名称”) ;
- com.XXXXX.reflect_10.ReflectDemo
举例:
public class Person {
//属性
private String name ;//私有的属性
int age ;
public String address ;//地址
//一些列构造方法
public Person() {}
private Person(String name) {
this.name = name ;
}
Person(String name,int age){
this.name = name ;
this.age = age ;
}
public Person(String name,int age,String address) {
this.name = name ;
this.age = age ;
this.address = address ;
}
//成员方法
public void show() {
System.out.println("show person");
}
public String method(int num) {
return "helloJavaEE"+num ;
}
private void function(String str) {
System.out.println(str);
}
public void function2() {
System.out.println("helloJavaEE,i'm coming...");
}
}
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//创建两个Person对象
Person p1 = new Person("美女", 22) ;
Person p2 = new Person("美女", 22) ;
System.out.println(p1==p2);//false
System.out.println(p1.getClass()==p2.getClass());
Class c1 = p1.getClass() ; //class com.qianfeng.reflect_10.Person
Class c2 = p2.getClass() ;
System.out.println(c1==c2);
System.out.println("--------------------------");
//方式2:获取字节码文件
Class c3 = Person.class ;
System.out.println(c3);//class com.qianfeng.reflect_10.Person
Class c4 = Person.class ;
System.out.println(c3==c4);
System.out.println("----------------------------");
//方式3:获取类的字节码文件对象
//public static Class<?> forName(String className)
Class c5 = Class.forName("com.qianfeng.reflect_10.Person") ;
System.out.println(c5);//class com.qianfeng.reflect_10.Person
//推荐:第三种:里面参数一个字符串:可以放在配置文件中使用!
}
}
之前的写法
- Person p = new Person();通过无参构造方法创建对象
- Person p = new Person(“美女”); 形参String—String类型字节码文件格式-> java.lang.String
使用反射获取构造方法并使用,(Constructor)
Class 类的实例表示正在运行的 Java 应用程序中的类和接口
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//获取Person类的字节码文件对象
//public static Class<?> forName(String className)
Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
//获取构造方法(构造器)对象
//public Constructor<?>[] getConstructors():表示获取当前类中的所有的公共的构造方法
//public Constructor<?>[] getDeclaredConstructors():
//获取当前类中所有的构造方法:包括私有的,公共的,默认,受保护的(proteted)
/*
Constructor[] cons = c.getConstructors() ;
for(Constructor con: cons) {
System.out.println(con);
/**
* public com.qianfeng.reflect_01.Person(java.lang.String,int,java.lang.String)
public com.qianfeng.reflect_01.Person(
*/
//}
/*
Constructor[] cons = c.getDeclaredConstructors() ;
for(Constructor con: cons) {
System.out.println(con);
}
*/
/**
* public com.qianfeng.reflect_01.Person(java.lang.String,int,java.lang.String)
com.qianfeng.reflect_01.Person(java.lang.String,int)
private com.qianfeng.reflect_01.Person(java.lang.String)
public com.qianfeng.reflect_01.Person()
*/
//获取某一个构造方法所在对象:Constructor
//public Constructor<T> getConstructor(Class<?>... parameterTypes)
//获取指定的公共构造方法
//参数:parameterTypes可变参数 里面相当于数组
//参数是当前的字节码文件Class
//Person p = new Person();通过无参构造方法创建对象
//直接输出p----->如果重写toString():成员信息的表达式
Constructor con = c.getConstructor() ;//Person类的无参构造方法
//System.out.println(con);//public com.qianfeng.reflect_01.Person()
//通过构造器如何获取当前Person类的实例
//Constructor创建该类的实例
//public T newInstance(Object... initargs):参数为当前实际参数
Object obj = con.newInstance() ;
System.out.println(obj);//p
System.out.println("--------------------");
Person p = new Person() ;
System.out.println(p);
}
//...:jdk5提供的可变参数 相当于数组
public static void add(int...a) {
}
}
之前的写法
- Person p = new Person(“美女”) ;
- System.out.println§ ; toString()
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//获取Person类的字节码文件
Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
//获取单个的构造方法
//Person(String) :是一个私有的,不是公共的
// public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取指定的构造方法
//Constructor con = c.getDeclaredConstructor(String.class) ;
//获取单三个参数的构造方法
Constructor con = c.getConstructor(String.class,int.class,String.class) ;
//public void setAccessible(boolean flag):参数为true,取消java语言访问检查
con.setAccessible(true);
//取消Java语言的访问检查
//非法访问异常:
//java.lang.IllegalAccessException: Class com.qianfeng.reflect_02.ReflectDemo can not access a member of
//class com.qianfeng.reflect_01.Person with modifiers "private"
//创建该类实例
Object obj = con.newInstance("美女",27,"西安市鄠邑区") ;
System.out.println(obj);
//Person [name=美女, age=27, address=西安市鄠邑区]
}
}
之前的写法:
- Person p = new Person() ;
- p.字段名(属性名) = “赋值”;
- 通过反射获取成员变量Field并使用
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
//获取Person类字节码文件对象
Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
//获取构造器:Constructor:无参构造方法
Constructor con = c.getConstructor() ;// public com.qianfeng.reflect_01.Person(){}
//创建该类实例
Object obj = con.newInstance() ; //p对象
//获取成员变量
//public Field[] getDeclaredFields():获取所有的Field成员变量(公共的,私有的,默认的,受保护的)
//public Field[] getFields():获取所有的公共的字段
//Field[] fields = c.getDeclaredFields() ;
/*
Field[] fields = c.getFields() ;
for(Field f : fields) {
System.out.println(f);
}
*/
//给name进行赋值 private String name;
//public Field getDeclaredField(String name)
//参数为:字段名(属性)
Field field = c.getDeclaredField("name") ;
//取消Java语言访问检查
field.setAccessible(true);
//public void set(Object obj,Object value)
//参数1:当前该Person类的实例
//参数2:给当前成员字段"name"设置的内容
field.set(obj, "美女"); // 相当于:p.name = "美女"
System.out.println(obj);
//Person [name=美女, age=0, address=null]
System.out.println("-------------------");
//age,address进行赋值
}
}
之前的写法:
- 通过无参构造方法创建对象
- Person p = new Pereson() ;
- p.show();
- 使用反射获取Person类的字节码文件对象,并获取成员方法Method并使用
@SuppressWarnings("all") //压制警告
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
//获取Person类的字节码文件对象
Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
//获取该类的无参构造方法
Constructor con = c.getConstructor() ;
//创建该类的实例
Object obj = con.newInstance() ;
//通过获取成员方法
//public Method[] getDeclaredMethods():获取所有的方法:仅限本类,不包括继承的
//public Method[] getMethods():获取所有的公共的成员方法:不仅有本类的,还有它父类的
// Method[] methods = c.getDeclaredMethods() ;
/*
Method[] methods = c.getMethods() ;
for (Method method : methods) {
System.out.println(method);
}
*/
//public Method getDeclaredMethod(String name,
//Class<?>... parameterTypes)获取指定的方法
//public Method getMethod(String name,Class<?>... parameterTypes)
//获取公共的成员方法
//参数1:方法名
//参数2:当前如果该方法有形式参数,跟上行驶时参数类型的Class
Method m = c.getMethod("show") ;
//Method类:
//底层调用方法
//public Object invoke(Object obj, Object... args)
//参数1:当前类的实例
//参数2:跟的实际参数
m.invoke(obj) ; // 相当于 之前:使用对象名p.show();
/*
System.out.println("-------------------");
Person p = new Person() ;
p.show();
*/
System.out.println("-----------------------------------");
/**
* public String method(int num) {
return "helloJavaEE"+num ;
}
*/
Method m2 = c.getMethod("method", int.class) ;
Object object = m2.invoke(obj, 100) ;
System.out.println(object);
System.out.println("-------------------------------------");
/**
* private void function(String str) {
System.out.println(str);
}
*/
Method m3 = c.getDeclaredMethod("function", String.class) ;
//取消Java语言访问检查
m3.setAccessible(true);
m3.invoke(obj, "hello,张佳宁") ;
}
}
如何读取src目录下的properties配置文件
class.properties
className=com.qianfeng.reflect_03.Student
methondName=love
public class Test2 {
public static void main(String[] args) throws Exception {
//1)读取src下面的class.properties配置文件
//获取当前类的类加载器
//Class
//public ClassLoader getClassLoader()
ClassLoader classLoader = Test2.class.getClassLoader() ;
//public InputStream getResourceAsStream(String name)
//读取指定资源的输入流
//参数是文件名称 文件必须是在src目录下(类路径)
//方式1
InputStream inputStream = classLoader.getResourceAsStream("class.properties") ;
//方式2:通过类加载器获取网络资源地址对象:URL
//public URL getResource(String name)
//public String getPath()
//创建属性集合类对象
Properties prop = new Properties() ;
//将流中的数据加载到属性集合类中
prop.load(inputStream);
//System.out.println(prop);//className=com.qianfeng.reflect_03.Worker, methondName=love}
//通过键的名称获取值
String className = prop.getProperty("className") ;
String methodName = prop.getProperty("methondName") ;
//获取当前类的Class
Class c = Class.forName(className) ;
//直接获取该类实例
Object obj = c.newInstance() ;
//获取Method成员方法
Method m = c.getMethod(methodName) ;
m.invoke(obj) ;
}
}
需求:有一个ArrayList集合,需要给里面添加String类型的数据,如何实现呢?
public class Test3 {
public static void main(String[] args) throws Exception{
//创建ArrayList<Integer>集合
ArrayList<Integer> array = new ArrayList<Integer>() ;
//添加元素
array.add(100) ;
array.add(200) ;
//array.add("javaee") ;
//array.add("hello") ;
//获取类的字节码文件对象有三种
//直接获取arrayList集合的字节码文件对象
Class clazz = array.getClass() ;
//System.out.println(c);//class java.util.ArrayList
//获取当前Method类对象:成员方法
//public boolean add(Object e)
Method m = clazz.getMethod("add", Object.class) ;
//调用add方法
m.invoke(array, "hello") ;
m.invoke(array, "world") ;
System.out.println(array);
}
}