反射概率以及一些基本API的使用
请问,获取对象有几种方式?
1、通过构造函数来new一个对象;
2、通过clone来克隆一个对象;
3、通过序列化反序列化来构建一个对象;
4、通过反射来创建对象;a、通过Class类来创建;b、通过Constructor类来创建;
什么是反射
JAVA反射机制是指在运行状态(非编译状态)中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
说的直白点,就是我们可以通过反射机制,来把类的各个组成部分(属性、构造函数、方法)给获取到。
反射能干嘛?
1:获取类的相关信息
2:动态调用方法
3:动态构造对象
Class类
我们发现该类没有构造函数,我们可以通过forName静态方法来获取到类对象。
Class类提供的API分类
获取到类信息的相关方法
获取到类中属性相关的方法
获取到类中方法相关的方法
获取到类中构造器相关的方法
反射相关类的简介
此处并没有列出这三个类中的所有方法, 只是这几个方法能够反映出该类的特点, 具体方法请参考API文档。
Field代表类的成员变量(成员变量也称为类的属性)
Method代表类的方法
Constructor类
反射案例:反射操作Book类
反射操作的Book类
class Book{
//提供一个公开访问权限的属性
public int bid;
//提供一个私有的属性;
private String bname;
//提供一个默认的属性
double price;
//构建多个不同参数的构造函数
public Book() {
System.out.println("这是无参构造函数");
}
public Book(String bname) {
this.bname = bname;
System.out.println("这是一个参数构造函数");
}
public Book(int bid, String bname) {
this.bid = bid;
this.bname = bname;
System.out.println("这是两个参数构造函数");
}
//构建两个方法,分别是私有的和共有的方法
public void read(String bname) {
System.out.println(bname+"这是一本好书,需要好好读!");
}
private void write(String content) {
System.out.println("我在写一本书,这本书的内容是:"+content);
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
@Override
public String toString() {
return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + "]";
}
}
三种方法获得字节码对象
//获取到类的字节码对象
//1、通过Class.forName来获取到指定路径下的类的字节码对象
Class<?> classObj1 = Class.forName("lession14.reflect.Book");
//2、通过对象来获取
Book bookObj2 = new Book();
Class<?> classObj2 =bookObj2.getClass();
//3、通过类来获取到指定类的字节码对象
Class<?> classObj3 = Book.class;
//1.1、我们可以通过字节码对象来做哪些事情
//1.1.1、获取到实例对象
Book bookObj1 = (Book)classObj1.newInstance();
System.out.println(bookObj1);
//1.1.2、获取到类的相关信息
System.out.println(classObj1.getName());
System.out.println(classObj1.getPackage());
操作属性,构造函数以及方法
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//获取到类的字节码对象
//1、通过Class.forName来获取到指定路径下的类的字节码对象
Class<?> classObj1 = Class.forName("lession14.reflect.Book");
//2、通过对象来获取
Book bookObj2 = new Book();
Class<?> classObj2 =bookObj2.getClass();
//3、通过类来获取到指定类的字节码对象
Class<?> classObj3 = Book.class;
//1.1、我们可以通过字节码对象来做哪些事情
//1.1.1、获取到实例对象
Book bookObj1 = (Book)classObj1.newInstance();
System.out.println(bookObj1);
//1.1.2、获取到类的相关信息
System.out.println(classObj1.getName());
System.out.println(classObj1.getPackage());
//1.1.3、获取到相关的属性对象
//1.1.4、获取到相关的方法对象
//1.1.5、获取到相关的构造函数对象
//4、通过字节码对象和对应的实例对象来操作他们的属性
// operateField(classObj1,bookObj1);
//5、通过字节码对象和对应的实例对象来操作他们的构造函数
// operateConstructor(classObj1,bookObj1);
//4、通过字节码对象和对应的实例对象来操作他们的方法
operateMethod(classObj1,bookObj1);
}
private static void operateMethod(Class<?> classObj, Book book) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//1、获取到一个公有方法
Method read = classObj.getMethod("read", String.class);
System.out.println(read.getName());
//2、调用该方法
read.invoke(book, "红楼梦");
//3、获取到私有方法
Method write = classObj.getDeclaredMethod("write", String.class);
write.setAccessible(true);
write.invoke(book, "今天天气真好");
//4、获取所有方法
Method [] methods = classObj.getDeclaredMethods();
for(Method method:methods) {
System.out.println(method.getName());
}
}
private static void operateConstructor(Class<?> classObj, Book book) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//1、使用字节码对象来调用无参的构造函数对象
Constructor<?> constructor = classObj.getConstructor();
//查看下构造函数对象
System.out.println(constructor);
//2、通过刚刚创建的无参构造函数对象来创建一个实例对象
Book book1 = (Book)constructor.newInstance();
//3、输出看是否正常
System.out.println(book1);
//4、使用字节码对象来调用有参的构造函数对象
Constructor<?> constructor1 = classObj.getConstructor(String.class);
//注意:通过构造函数对象创建实例对象的时候,参数一定要进行对应匹配,否则会报非法参数异常!
Book book2 = (Book)constructor1.newInstance("三国演义");
System.out.println(book2);
}
private static void operateField(Class<?> classObj, Book book) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
//1、首先为Book对象中的公开属性进行一个赋值
book.bid = 1001;
//2、通过字节码对象来获取到该属性
Field bidField = classObj.getField("bid");
//3、通过对象来获取到刚刚通过字节码对象拿到的属性对象
Integer bid = (Integer) bidField.get(book);
//4、测试,是否能获取到book对象中的bid的属性值
System.out.println(bid);
//5、测试通过属性对象来更改属性值
bidField.set(book, 1002);
//6、测试,查看是否更改成功
System.out.println(book.bid);
//7、如果属性不是public修饰呢?
//8、先把私有的属性值给进行一个赋值
book.setBname("西游记");
// Field bnameField = classObj.getField("bname");//报错,找不到该属性的异常错误
//9、通过专门获取非公有属性的方法来拿到具体的属性对象
Field bnameField = classObj.getDeclaredField("bname");
//10、设置私有的属性权限可见
bnameField.setAccessible(true);//暴力破解私有特点
//11、来拿到指定的Field对象在指定实例对象里面的值
String bname = (String)bnameField.get(book);
//12、测试是否能够正常的获取到类里的私有属性值
System.out.println(bname);
//13、只要你的属性是非公有的,你都需要通过getDeclaredField来获取
book.price = 19.9;
Field priceField = classObj.getDeclaredField("price");
// Field priceField = classObj.getField("price");
// priceField.setAccessible(true);//暴力破解私有特点
double price = (double)priceField.get(book);
System.out.println(price);
//14、同时获取到所有的属性
Field [] fields = classObj.getDeclaredFields();
for(Field field:fields) {
System.out.println(field.getName());
}
}
}