java----反射
动态语言
首先java不是一个动态语言,但是java具有一定的动态性,这个动态性实现方式之一:反射
String str = "xx"; Class<?> aClass = Class.forName(str); //根据字符串的不同,动态编译不同的类对象
反射的强大之处
指的是可以运行时加载、探知、使用编译期间完全未知的类。
程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
获取Class对象的三种方法
package com.first;
public class Demo {
public static void main(String[] args) {
Dog dog = new Dog("花花",10);
//方式一,通过对象获取class对象
Class<? extends Dog> aClass = dog.getClass();
//方式二,通过类来获取
Class<Dog> dogClass = Dog.class;
//方式三,通过Class.forName;(好处在于类不存在再编译期不会报错)
try {
Class.forName("com.first.Dog");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Dog{
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
}
一个类只有一个class对象
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> aClass1 = Class.forName("com.zy.Dog");
Class<?> aClass2 = Class.forName("com.zy.Dog");
Dog dog = new Dog();
Class<? extends Dog> aClass3 = dog.getClass();
Class<Dog> aClass4 = Dog.class;
System.out.println(aClass1.hashCode()==aClass2.hashCode()); //true
System.out.println(aClass2.hashCode()==aClass3.hashCode()); //true
System.out.println(aClass3.hashCode()==aClass4.hashCode()); //true
}
}
Class类的使用(通过反射,任何封装都可以被访问到)
通过反射实例化对象,实例化对象的类必须设置相应的构造方法;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Demo {
public static void main(String[] args) {
//test1(); //实例化对象
//test2(); //获取类对象的属性(字段)
test3(); //方法的调用;
}
public static void test1(){
Class<Dog> dogClass = Dog.class;
try {
//通过Class实例化对象,默认调用对象的无参构造方法;(jdk9不推荐使用)
Dog dog = dogClass.newInstance();
//实例化对象,调用有参构造方法;
Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class);
//dogClass.getConstructors() 获取所有的构造方法,生成一个[],列表
Dog dog1 = constructor.newInstance("花花",10);
} catch (InstantiationException|IllegalAccessException|NoSuchMethodException|InvocationTargetException e) {
e.printStackTrace();
}
}
public static void test2(){
Class<Dog> dogClass = Dog.class;
System.out.println(dogClass.getFields().length); //获取所有的公有属性,静态属性,私有属性获取不到
System.out.println(dogClass.getDeclaredFields().length);//获取所有的属性,(包括静态和私有)
for (int i = 0; i <dogClass.getDeclaredFields().length ; i++) {
System.out.println(Modifier.toString(dogClass.getDeclaredFields()[i].getModifiers())+" "+dogClass.getDeclaredFields()[i].getType()+" "+dogClass.getDeclaredFields()[i].getName());
}
}
public static void test3(){
Class<Dog> dogClass = Dog.class;
//System.out.println(dogClass.getPackage()); //获取包名
//访问公有的方法(包括继承的父类的方法)
for (int i = 0; i < dogClass.getMethods().length; i++) {
if (dogClass.getMethods()[i].getName().equals("toString")){
try {
//通过invoke调用方法,第一个参数传对象,第二个参数传参数的形参(没有就不用填)
String str = (String) dogClass.getMethods()[i].invoke(new Dog("花花",10));
System.out.println(str);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
//访问包括私有方法的所有的方法(不继承父类的任何一个方法)
Method[] methods = dogClass.getDeclaredMethods();
Method method = dogClass.getDeclaredMethod("setName",String.class); //获取指定的方法,但是如果方法有参数,右面需要填写参数的class对象,如果没有,传null
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals("test")){
//设置私有方法可以被访问
methods[i].setAccessible(true); //不能这样设置(没有效果,可能这种执行方法是没有保存数据):dogClass.getDeclaredMthods[i].setAccessible(true);
try {
methods[i].invoke(new Dog("花花",10));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
class Dog{
static String t1;
public String t2;
private String name;
private int age;
public Dog(){}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
private void test(){
System.out.println("我是私有方法");
}
@Override
public String toString() {
return "Dog{" +
"t2='" + t2 + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
利用反射来操作对象
首先通过三种方式的一种获取Class对象;
可以找到class对象的方法、属性等,传入我们实例化的对象,就可以进行操作了
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Dog dog = new Dog();
dog.setName("嘿嘿");
Class<Dog> dogClass = Dog.class;
Field name = dogClass.getDeclaredField("name");
name.setAccessible(true);
String o = (String) name.get(dog);
System.out.println(o);
name.set(dog,"大大");
String o1 = (String) name.get(dog);
System.out.println(o1);
}
}
class Dog{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
反射机制性能问题
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Dog dog = new Dog();
//普通方法调用
long l = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
dog.test();
}
long l2 = System.currentTimeMillis();
System.out.println(l2-l);
//反射:不跳过安全检查
//检查就是为了不然我们执行private方法
Class<? extends Dog> aClass = dog.getClass();
Method test = aClass.getDeclaredMethod("test");
for (int i = 0; i < 10000000; i++) {
test.invoke(dog);
}
long l3 = System.currentTimeMillis();
System.out.println(l3-l2);
//反射:跳过安全检查
//即使我们知道这是一个public方法,我们也设置setAccessible(true),可以加快执行效率
test.setAccessible(true);
for (int i = 0; i < 10000000; i++) {
test.invoke(dog);
}
long l4 = System.currentTimeMillis();
System.out.println(l4-l3);
}
}
class Dog{
public void test(){
}
}

浙公网安备 33010602011771号