反射是什么?
1.在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法、构造函数;
2.对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
问题一:
编写一个函数,可以接收一个类的全路径,输出该类的所有属性和方法。
问题二:
要求通过一个配置文件,创建Cat类的一个对象实例,并调用cry方法,怎么办?
1.通过反射查看类的信息
(1)每个类被加载后,系统都会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。
(2)Java程序中获得Class对象通常有如下三种方式:
使用Class的forName()
调用某个类的class属性
调用某个对象的getClass()
(3)一旦获取了某个类的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。
package com.reflection;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
//得到Cat的Class对象
//1.通过forName
Class clazz1=Class.forName("com.reflection.Cat");
//2.通过class属性
Class clazz2=Cat.class;
//3.通过Cat的对象实例,来获取
Cat cat=new Cat();
Class clazz3=cat.getClass();
//这三个Class是同一个对象,我们来验证一下
if(clazz1==clazz2) {
System.out.println("ok1");
}
if(clazz2==clazz3) {
System.out.println("ok2");
}
}
}
class Dog{
}
//class Cat{
// private String name;
//}
class Brid{
}
一个类的创建原理:
2.使用反射生成对象
通过反射来生成对象有如下两种方式:
(1)使用Class对象的newInstance()方法创建Class对象对应类的实例,这种方式要求该Class对象的对应类有默认的构造器,而执行newInstance()方法时实际上是利用默认的构造器来创建该类的实例
(2)先使用使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应的实例。通过这种方式可以选择使用某个类的指定的构造器来创建实例。
package com.reflection;
import java.lang.reflect.Constructor;
public class Test2 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 得到Cat的Class对象
// 1.通过forName
Class clazz1 = Class.forName("com.reflection.Cat");
//通过Class对象可以创建对象实例
// Cat cat1=(Cat)clazz1.newInstance();
// cat1.show();
//通过public Cat(String name,int age)来创建实例
//1.通过class对象来得到构造函数
//构造函数有多个,要怎么知道调用哪一个呢?这样做就可以了String.class,int.class
Constructor c1=clazz1.getConstructor(String.class,int.class);
Cat cat1=(Cat)c1.newInstance("小猫",6);
// cat1.show();
//2.通过 public Cat(String[] foods)来创建实例
Constructor c2=clazz1.getConstructor(String[].class);
String[] foods= {"鱼","老鼠"};
Cat cat2=(Cat)c2.newInstance((Object)foods);
cat2.show();
}
}
package com.reflection;
import java.util.List;
public class Cat {
// public String name;
// public int age;
public String name="小猫咪";
public int age;
public String[] foods;
public void show() {
System.out.println("猫名"+name);
for (int i = 0; i < foods.length; i++) {
System.out.println(foods[i]);
}
}
public Cat() {
}
public Cat(String[] foods) {
this.foods=foods;
}
public void show(String name) {
System.out.println("输入的名字是"+name);
}
public void show(String name,int age) {
System.out.println("输入的名字是"+name+" 年龄是"+age);
}
// public void show(List list) {
// for(int i=0;i<list.size();i++) {
// System.out.println(list.get(i));
// }
// }
private void show(List list) {
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
}
public Cat(String name,int age) {
this.name=name;
this.age=age;
}
}
3.使用反射调用方法
(1)当获取某个类对应的Class对象后,就可以通过Class对象的getMethods()或getMethod()方法来获取全部方法或指定的方法。
(2)每个Method对象对应一个方法,获得Method对象后,程序就可通过该Method来调用对应方法。在Method里包含一个invoke()方法。
package com.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
public class Test3 {
//通过反射来获取和调用指定的方法!
public static void main(String[] args) throws Exception {
//public void show
//1.通过反射创建Cat实例
Class clazz1=Class.forName("com.reflection.Cat");
//得到构造函数
Constructor constructor=clazz1.getConstructor(String[].class);
String[] foods= {"fish","mouse"};
Cat cat1=(Cat) constructor.newInstance((Object)foods);
//使用反射来调用show()
//获取show方法
//Method method=clazz1.getMethod("show", null);
// Method method=clazz1.getMethod("show", String.class);
// Method method=clazz1.getMethod("show", String.class,int.class);
//调用invoke的第一个参数表示对象实例
// method.invoke(cat1, "顺平",80);
// Method method=clazz1.getMethod("show", List.class);
// List list=new ArrayList();
// list.add("abc");
// list.add("中国");
// method.invoke(cat1, list);
//如何调用私有的函数,比如private void show(List list)
Method method=clazz1.getDeclaredMethod("show", List.class);
method.setAccessible(true);//暴力访问
List list=new ArrayList();
list.add("abc");
list.add("999");
method.invoke(cat1, list);
}
}
4.使用反射访问属性值
(1)通过Class对象的getFields()或getField()方法可以获取该类所包括的全部Field或指定的Field
(2)Field通过如下两组方法来访问属性
get(Object obj)[字段类型是引用类型,用此法]
getXXX(Object obj)[字段类型是基本数据类型,用此法]
getXXX(Object obj,XXX val)
package com.reflection;
import java.lang.reflect.Field;
public class Test4 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//需求:通过反射,获取Cat类的name属性值
//1.得到Class对象,创建实例
Class clazz1=Class.forName("com.reflection.Cat");
Cat cat1=(Cat)clazz1.newInstance();
cat1.setName("悟空");//如果这里把名字改成悟空呢?
//通过clazz1,获取cat1对象的属性name
Field field=clazz1.getField("name");
//通过field来得到值,传统的方法是:cat1.getValue('name'),但反射是反着来的
String nameVal=(String)field.get(cat1);
System.out.println("名字是"+nameVal);
}
}
package com.reflection;
import java.util.List;
public class Cat {
// public String name;
// public int age;
public String name="小猫咪";
public void setName(String name) {
this.name = name;
}
public int age;
public String[] foods;
public void show() {
System.out.println("猫名"+name);
for (int i = 0; i < foods.length; i++) {
System.out.println(foods[i]);
}
}
public Cat() {
}
public Cat(String[] foods) {
this.foods=foods;
}
public void show(String name) {
System.out.println("输入的名字是"+name);
}
public void show(String name,int age) {
System.out.println("输入的名字是"+name+" 年龄是"+age);
}
// public void show(List list) {
// for(int i=0;i<list.size();i++) {
// System.out.println(list.get(i));
// }
// }
private void show(List list) {
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
}
public Cat(String name,int age) {
this.name=name;
this.age=age;
}
}