请问,获取对象有几种方式?
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;}@Overridepublic 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());}}
}