JAVA反射
-什么是反射
-反射机制:反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息;这种通过Class
实例获取class
信息的方法称为反射(Reflection)。
通过反射可以越过泛型检查。
-class类
除了int
等基本类型外,Java的其他类型全部都是class
(包括interface
)。例如:
String
Object
Runnable
Exception
而class
是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class
类型时,将其加载进内存。
每加载一种class
,JVM就为其创建一个Class
类型的实例,并关联起来
-反射机制的功能/作用
[在运行中]:
判断任意对象所属的类。
判断任意类所具有的成员变量和方法。
构造任意类的对象。
调用任意对象的方法。
生成动态代理(在运行时创建新类对象)。
-反射的优缺点
优点:
反射提高了程序的灵活性、扩展性和低耦合。它允许程序创建和控制任何类的对象,无需提前硬编码目标类
缺点:
(1)性能问题:反射基本上是解释操作,字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
(2)模糊程序内内部逻辑:程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。比相应的直接代码更复杂。
-实现反射机制的类
Java中主要由以下的类来实现Java反射机制(这些类都位于java.lang.reflect包中):
Class类:代表一个类。
Field类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
-如何使用反射
-获取class类对象的方式:
1、字节码未加载到内存
class.forName("全类名"):将字节码文件加载到内存,为程序返回class对象。
2、字节码文件以加入内存
类名.class:通过类名class属性获取
3、对象已存在
对象.getClass()
Class
实例在JVM中是唯一的,所以,上述方法获取的Class
实例是同一个实例。可以用==
比较两个Class
实例
Integer n = new Integer(123); boolean b1 = n instanceof Integer; // true,因为n是Integer类型 boolean b2 = n instanceof Number; // true,因为n是Number类型的子类 boolean b3 = n.getClass() == Integer.class; // true,因为n.getClass()返回Integer.class boolean b4 = n.getClass() == Number.class; // false,因为Integer.class!=Number.class
用
instanceof
不但匹配指定类型,还匹配指定类型的子类。而用==
判断class
实例可以精确地判断数据类型,但不能作子类型比较。
反射应用:
调用某个字段进行赋值、调用某个放法去做需求、
例:
package reflectTest; public class Person { private String name; private int age; public String a; protected String b; String c; //构造方法 public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } //成员方法 public void eat(){ System.out.println("吃........."); } public void eat(String xx,String zz){ System.out.println("吃"+xx+"、"+zz); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + '}'; } 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; } }
package reflectTest; public class ReflectDemo01 { public static void main (String [] args) throws ClassNotFoundException { //1、获取全类名方式 Class<?> clazz1 = Class.forName("reflectTest.Person"); System.out.println(clazz1);//class reflectTest.Person //2、类名.Class Class<Person> clazz2 = Person.class; System.out.println(clazz2);//class reflectTest.Person //3、对象.getClass() Person ps =new Person(); Class<? extends Person> clazz3 = ps.getClass(); System.out.println(clazz3);//class reflectTest.Person //比较对象引用是否相同 System.out.println(clazz1==clazz2);//true System.out.println(clazz1==clazz3);//true } }
从上面可以看出,他们三个字符串表现形式是一样的,对象引用是相同的。
-Class对象的功能
1、获取成员变量
1)、clz.getFields("变量名"):获得某个类的所有的公共(public)的字段,包括父类中的字段。
2)、clz.getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段 .
Field [] getFields()、Field getField(String name)、getDeclaredFields()、getDeclaredField()
package reflectTest; import java.lang.reflect.Field; public class ReflectGetMemberVar { public static void main(String[] args) throws Exception { Class<Person> personClass = Person.class; /* *Field操作: * 1.获取值 * 2.设置值 */ System.out.println("==========getFields()=========="); //getFields():获取所有public修饰的成员变量 Field[] fields = personClass.getFields(); for (Field field : fields) { System.out.println(field);//public java.lang.String reflectTest.Person.a } System.out.println("==========getField()=========="); //getField(" "):获取指定内容的public修饰的成员变量 //获取a的值:get(Object obj) Field a = personClass.getField("a"); Person person = new Person(); Object o = a.get(person); System.out.println(o);//null:未赋值默认空 //设置a的值: void set(Object obj, Object value) a.set(person,"展示"); System.out.println(person.a);//展示 System.out.println("==========getDeclaredFields()=========="); //getDeclaredFields() Field[] declaredFields = personClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); /*private java.lang.String reflectTest.Person.name private int reflectTest.Person.age public java.lang.String reflectTest.Person.a protected java.lang.String reflectTest.Person.b java.lang.String reflectTest.Person.c*/ } System.out.println("==========getDeclaredField()=========="); //getDeclaredField() Field b = personClass.getDeclaredField("b"); //开启暴力反射:忽略访问私有时的非法访问异常 b.setAccessible(true); System.out.println(b.get(person));//null } }
2、获取成员方法
1) Clazz.getMethod(“方法名”,class……parameaType);(只能获取公共的)
2) Clazz.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有)
让方法执行
1)Method.invoke(obj实例对象,obj可变参数);-----(是有返回值的)
getMethods()、getMethods()、getDecaredMethods()、getDeclaredMehods()
package reflectTest; import java.lang.reflect.Method; public class ReflectGetMemberMethod { public static void main(String[] args) throws Exception { Class<Person> personClass = Person.class; /* 执行方法: Object invoke(Object obj, Object... args) */ //获取指定名称的方法。获取方法三要素(方法名,参数列表,返回值) Method eat = personClass.getMethod("eat"); Method eat1 = personClass.getDeclaredMethod("eat", String.class, String.class); Person person = new Person(); eat.invoke(person); eat1.invoke(person,"xxx","zzz"); } }
3、获取构造方法
1). Clazz.getConstructor([String.class]);
2). Con.newInstance([参数]);
其他方法:getConstructors()、getDecaredConstructors()、getDecaredConstructor()
package reflectTest; import java.lang.reflect.Constructor; public class ReflectGetConstruction { public static void main(String[] args) throws Exception { Class<Person> personClass = Person.class; /* 构造方法 作用:创建对象 T newInstance(Object... initargs) */ System.out.println("==========getConstructor()==========="); //获取构造方法 Constructor<Person> constructor1 = personClass.getConstructor(); System.out.println(constructor1); Constructor<Person> constructor = personClass.getConstructor(String.class, int.class); System.out.println(constructor);//public reflectTest.Person(java.lang.String,int) System.out.println("==========newInstance()==========="); //创建对象 Person person = constructor.newInstance("小红", 13); System.out.println(person);//Person{name='小红', age=13, a='null', b='null', c='null'} }
}
--获取继承关系
.getSuperclass()
public class Main { public static void main(String[] args) throws Exception { Class i = Integer.class; Class n = i.getSuperclass(); System.out.println(n); Class o = n.getSuperclass(); System.out.println(o); System.out.println(o.getSuperclass()); } }
/*
class java.lang.Number
class java.lang.Object
null
*/
--动态代理
静态代码:
//定义接口: public interface Hello { void morning(String name); }
//编写实现类: public class HelloWorld implements Hello { public void morning(String name) { System.out.println("Good morning, " + name); } }
//创建实例,转型为接口并调用: Hello hello = new HelloWorld(); hello.morning("Bob");
动态代码,仍然先定义了接口Hello
,但是并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()
创建了一个Hello
接口对象。
在运行期动态创建一个interface
实例的方法如下:
- 定义一个
InvocationHandler
实例,它负责实现接口的方法调用; - 通过
Proxy.newProxyInstance()
创建interface
实例,它需要3个参数:- 使用的
ClassLoader
,通常就是接口类的ClassLoader
; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
- 使用的
- 将返回的
Object
强制转型为接口。
public class Main { public static void main(String[] args) { InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); if (method.getName().equals("morning")) { System.out.println("Good morning, " + args[0]); } return null; } }; Hello hello = (Hello) Proxy.newProxyInstance( Hello.class.getClassLoader(), // 传入ClassLoader new Class[] { Hello.class }, // 传入要实现的接口 handler); // 传入处理调用方法的InvocationHandler hello.morning("Bob"); } } interface Hello { void morning(String name); }