文章目录
1.反射是什么?(W)
反射是运行中的程序检查自己和软件运行环境的能力,它可以根据它发现的进行改变。反射可以在运行时根据指定的类名获得类的信息。(无需使用new 就能实例化对象)
2.为什么要有反射?(W)
利用反射,可以实现更好的解耦合操作。(代替new来实现对象实例化操作)
3.Object类中的getClass()方法:
作用:通过对象取得此对象所在类的信息。
当我们使用getClass方法时,返回的类型为java.lang.class,这是反射操作的源头类,即所有的反射操作都需要通过此类开始。
4.java.lang.Class类对象实例化:
有如下三种方法:
I.调用Object类中的getClass()方法,此类操作必须有实例化对象。
import java.util.Date;
public class Demo {
public static void main(String[] args) {
Date date = new Date();
Class<?> cls = date.getClass();
System.out.println(cls.getName());
}
}
java.util.Date
II.使用"类.class"取得,此时可以不用通过指定类的实例化对象取得
public class Demo {
public static void main(String[] args) {
Class<?> cls =java.lang.Object.class;
System.out.println(cls.getName());
}
}
java.lang.Object
III.调用Class类提供的方法:
public static 类<?> forName(String className)throws ClassNotFoundException
public class Demo {
public static void main(String[] args)throws Exception {
Class<?> cls =Class.forName("java.lang.Object");
System.out.println(cls.getName());
}
}
java.lang.Object
III中调用了Class类中forname()方法。
5.反射怎么用?(H)
掌握了Class类对象实例化的三种操作形式,就可以利用Class类来进行类的反射控制了。
Class类中有如下重要方法:
public T newInstance()
throws InstantiationException,
IllegalAccessException
public static 类<?> forName(String name,
boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
最重要的就是newInstance()方法,作用是反射实例化对象。(不使用new也可以生成对象),此方法返回的类型为Object。
如果要使用此方法反射实例化对象,则类中一定要提供无参构造方法。
利用反射实例化对象:
class Book {
public Book() {
System.out.println("*****这是无参构造");
}
@Override
public String toString() {
return "《*****》";
}
}
public class Demo {
public static void main(String[] args)throws Exception {
Class<?> cls =Class.forName("Book"); //设置要操作对象的类名称
// 反射实例化后的对象返回的结果都是Object类型
Object obj = cls.newInstance(); //相当于使用new调用无参构造
Book book = (Book) obj; //向下转型
System.out.println(book);
}
}
*****这是无参构造
《*****》
6.使用反射调用构造:
利用Class类的newInstance()方法可以实现反射实例化对象的操作,但是类中必须提供有无参构造方法。如果类中只提供有参构造方法时,就必须通过java.lang.reflect.Constructor类来实现对象的反射实例化操作。
另外,java.lang.reflect是所有反射操作类的程序包,类中的每一个结构都有相应的类进行操作定义,如:构造方法会使用Constructor类。
java.lang.Class类中取得类中的构造方法:
public Constructor<?>[] getConstructors()
//取得全部构造方法 throws SecurityException
public Constructor<T> getConstructor(类<?>... parameterTypes)
//取得指定参数类型的构造方法 throws NoSuchMethodException,
SecurityException
利用以上两个方法可以取得java.lang.reflect.Construcor,而Constructor类的最重要的方法如下:
调用指定参数的构造实例化类对象
public T newInstance(Object... initargs)
throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
明确调用类中的有参构造方法:
import java.lang.reflect.Constructor;
class Book {
private String name;
private double price;
public Book(String name,double price){
this.name=name;
this.price=price;
}
@Override
public String toString() {
return "图书名"+name +",价格"+price ;
}
}
public class Demo {
public static void main(String[] args)throws Exception {
Class<?> cls =Class.forName("Book"); //设置要操作对象的类名称
//找到Book类中两个参数的构造
Constructor<?> cst =cls.getConstructor(String.class,double.class);
Object obj =cst.newInstance("Java开发",66.6); //实例化对象,传递内容
System.out.println(obj);
}
}
以上程序首先利用Class类取得此构造方法,返回Constructor对象,然后利用Constructor类的newInstance()方法传递指定数据,就完成了对象的反射实例化。
7.反射调用方法:
java.lang.Class类取得普通方法的操作:
public 方法[] getMethods()
//取得类中的全部方法 throws SecurityException
public 方法 getMethod(String name,
//取得类中指定方法名称与参数类型的方法 类<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException
java.lang.reflect.Method类的最重要方法:
public Object invoke(Object obj,
Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
8.反射调用成员:
java.lang.Class类中取得成员的操作:
//取得本类继承父类的全部成员
public Field[] getFields()
throws SecurityException
//取得本类继承父类中指定名称的成员
public Field getField(String name)
throws NoSuchFieldException,
SecurityException
//取得本类定义的全部成员
public Field[] getDeclaredFields()
throws SecurityException
//取得本类指定名称的成员
public Field getDeclaredField(String name)
throws NoSuchFieldException,
SecurityException
java.lang.reflect.Field类常用方法:
//取得该成员的类型
public 类<?> getType()
//取得指定对象成员中的内容,相当于直接调用成员
public Object get(Object obj)
throws IllegalArgumentException,
IllegalAccessException
//设置指定对象成员中的内容,相当于直接调用成员设置内容
public void set(Object obj,
Object value)
throws IllegalArgumentException,
IllegalAccessException
利用反射直接操作私有成员:
import java.lang.reflect.Field;
class Book {
private String name;
}
public class Demo {
public static void main(String[] args)throws Exception {
Class<?> cls =Class.forName("Book"); //取得反射对象
Object obj =cls.newInstance(); //实例化对象
Field titleField =cls.getDeclaredField("title");//取得类中的title属性
titleField.setAccessible(true); //取消封装
titleField.set(obj,"第一行代码------");
System.out.println(titleField.get(obj));
}
}
titleField.setAccessible(true);作用就是取消封装,如果没有特殊需要尽量不适用这种。所有属性访问还是要通过setter、getter方法操作。
无论是使用反射调用普通还是方法类中的成员,都必须存在实例化对象,因为类中的属性必须在类产生实例化对象(有堆内存空间)后才可以正常使用。