【java】对反射的理解

要是小编理解不当,欢迎吐槽

什么是反射?

既然有反,那么就有正,在正常思路中,只有知道一个类之后才可以产生实例化对象

看看通常我们怎么实例化对象呢?

例如

Date date=new Date() //通过new 关键字实例化对象^_^

System.out.println(date);

都是习惯先声明后使用的(*^▽^*)。那么这里所谓的反射指的就是通过对象找到来源。来个比喻(⊙o⊙)…就像是熊孩子打坏人家玻璃,户主要找到孩子父母找赔款。那么在程序中,对象想找到它的来源,依靠Object类提供的一个getClass方法

public final Class<?> getClass()   已经定义为final,所以不可以重写和覆盖啦!!!

现在发现通过getClass()取得Class类对象,就可以直接找到该对象的来源,是不是超级简单(*^▽^*)!!!

class类是反射操作的源头,也就是说所有的反射操作都应该通过Class类完成

但是最有意思的是这个类的对象可以通过以下三种方式获得

1.利用Object类中的getClass()方法,但是必须有明确的实例化对象后可以调用

Date date=new Date();
Class<?> cls=date.getClass();

System.out.println(cls);

System.out.println("全名"+cls.getName());

System.out.println(“类名”+cls.getSimpleName());

输出:class java.util.Date

          java.util.Date

           Date

O(∩_∩)O哈哈~这能看懂直接输出cls,和调用cls.getName()、getSimpleName()的区别吧

2.利用“类.class’取得Class类的实例化对象

Class<?> cls=java.util.Date.class;

3.利用Class类的static方法(Class.forName)取得实例化Class类的对象

public static Class<?> forName(String className)throws ClassNotFoundException//java中API给的定义,方便大家理解

Class<?> cls=Class.forName("java.util.Date");//字符串

♪(^∇^*)得到类的对象,那咱们看看怎么实例化???

正常的实例化

例如

Date date = new Date();//不知道的童鞋(⊙o⊙)…

通过反射实例化对象,利用newInstance()

Class<?>cls = Class.forName("java.util.Date");//先得到对象

Date date = (Date)cls.newInstance();//调用newInstance()方法,会去调用Date的无参构造函数,记得把Object类强制转化

//方便大家理解,放官方解释(*╹▽╹*)

T    newInstance()

Creates a new instance of the class represented by this Class object.

♪(^∇^*)  注意:利用newInstance()只能调用无参构造函数哦!!!!要是没有无参构造函数会报错滴!!!

看到这很多童鞋一定想问,利用反射实例化对象比new有什么优势呢?简单举个例子
对于工厂设计模式 其本质在于想取得接口的实例化对象不要直接使用关键字new,而应该通过工厂取得,只要自己写的接口要想取得实例化对象,99%要写工厂类。
例如
interface Fruit{
public void eat(){
}
}
class Apple implements Fruit{
@override
public void eat(){
System.out.println("***吃苹果***);
}
}
//工厂
class Factory{
public static Fruit getInstance(){
return new Apple();//只有苹果
}
}
但是现在对于工厂设施模式出现了一个挑战,如果现在增加了子类,比如以上例子增加橘子、栗子什么的水果,那么意味着工厂类需要修改。那么假如这个接口可能源源不断的产生新的子类,所以这个时候的工厂类的设计就存在有新的问题了,那么现在的关键性问题就在于new上了,new造成本次设计失败的最大元凶。所以这个时候就可以通过反射来实现此时的工厂类

class Factory{
public static Fruit getInstance(String classname){
try{
return new (Fruit)Class.forName(className).newInstance();//不管是哪个子类都可以返回其实例
}catch(Exception e) {}
return null;
}
}

(*^▽^*)不知道这个例子有没有让大家深刻的感觉到了反射的好处!!!

很多童鞋肯定很想问,很多时候我们的构造函数都是带参数的,那怎么办呢???

看看官方怎么说的

    • java.lang.Class<T>

Constructor<T> getConstructor(Class<?>... parameterTypes)
Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object.
Constructor<?>[] getConstructors()
Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object.
找到了java.lang.reflect.Constructor类之中在此类中提供有一个实例化对象的方法

public T newInstance(Object... initargs)
              throws InstantiationException,
                     IllegalAccessException,
                     IllegalArgumentException,
                     InvocationTargetException

给大家看看例子,可能更好理解

class Person{

private String name;

private int age;

Person(String name,age){

this.name=name;

this.age=age;

}

}

Class<?> cls=Class.forName("test.Person");

Constructor<?> cons=cls.getConstructor(String.class,int.class);//设置参数类型

Person p=(Person)cons.newInstance("张三",20);
system.out.println(p);

(^U^)ノ~YO大家现在知道怎么利用反射实例化有参数的构造函数了吗?有没有觉得很繁杂,所以大家在创建类的时候记得定义无参的构造方法~

知道了反射来实例化类,那怎么通过反射调用对象的方法呢???

先看看人家怎么说

java.lang.Class<T>

Method getMethod(String name, Class<?>... parameterTypes)
Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object.
Method[] getMethods()
Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces.

在Class类中定义有取得方法对象的操作getMethod(String name, Class<?>... parameterTypes)getMethods()

在Method中有一个很重要的invoke方法

看看哈。。

java.lang.reflect.Method

Object  invoke(Object obj, Object... args)

Invokes the underlying method represented by this Method object, on the specified object with the specified parameters.

看看例子

public static String initcap(String str){
return str.substring(0,1).toUpperCase()+str.substring(1);//第一个字母要大写
}

String attribute="name";
Class<?> cls=Class.forName("test.Person");
Object obj=cls.newInstance();
Method setMethod=cls.getMethod("set"+initcap(attribute),String.class);//设置Name属性Person类中存在setName方法
Method getMethod=cls.getMethod("get"+initcap(attribute),String.class);//获得Name属性Person类中存在getName方法
setMethod.invoke(obj,"张三“);//等价于:对象.setName("张三“);

System.out.println(getMethod.invoke(obj));//等价于:对象.getName();

知道了怎么调用类的方法,那怎么获取类中成员的内容呢???

看看人家怎么说的

java.lang.Class<T>

Field getDeclaredField(String name)

Returns a Field object that reflects the specified declared field of the class or interface represented by this Class object.

在java中使用Java.lang.reflect.Field类描述成员,在这个类中有两个重要的方法

Object get(Object obj)

Returns the value of the field represented by this Field, on the specified object.
void   set(Object obj, Object value)
Sets the field represented by this Field object on the specified object argument to the specified new value.

但是需要注意的是所有的属性几乎都要使用private封装,所以要想解决封装的困扰有 setAccessible方法,可以取消private属性

在java.lang.reflect.AccessibleObject中有

static void setAccessible(AccessibleObject[] array, boolean flag)

Convenience method to set the accessible flag for an array of objects with a single security check (for efficiency).

放例子

Class<?> cls=Class.forName("test.Person");
Field nameField = cls.getDeclareField("name");
namefield.setAccessible(true);//private消失
nameField.set(obj,"张三"); //对象.name="张三" 

到这,大家学会反射对成员变量内容操作了吗?(*^▽^*)

是不是感觉几乎类中的一切定义形式都可以用反射完成???

♪(^∇^*)每天进步一点点

猜你喜欢

转载自blog.csdn.net/qq_33511234/article/details/79992432