2018年4月21日星期六
1. 理解反射做用户
2. 利用反射来调用类的结构
利用对象找到对象的出处,Object类里面提供有一个方法:
取得Class对象 :publicfinal 类> getClass()
示例:
import java.util.Date; public class Reflect { public static void main(String[] args) { Date date = new Date(); System.out.println(date.getClass()); } }
发现调用了getClass()方法后的输出就输出了类的完整名称,等于是找到了对象的出处。
Java.lang.Class 是一个类,这个类是反射的操作的对象,这个类有三种实例化方式
1.调用Object中的getClass方法;
public class Reflect { public static void main(String[] args) { Date date = new Date(); System.out.println(date.getClass()); Class> cls = date.getClass(); System.out.println(cls); } }
2.使用:类.class取得
示例:
import java.util.Date; public class Reflect { public static void main(String[] args) { Class> cls = Date.class; System.out.println(cls); } }
之前是在产生了类的实例化对象之后取得的Class类对象,但此时并没有实例化对象的产生。
3. 调用Class类提供的一个方法
实例化Class类对象 public static Class > forName(String name,boolean initialize,ClassLoader loader)throws ClassNotFoundException
public class Reflect { public static void main(String[] args) throws Exception { Class> cls = Class.forName("java.util.Date"); System.out.println(cls); } }
此时可以不使用import语句导入一个明确的类,而类名称是采用字符串的方式进行描述的。
一般情况的用new去实例化一个对象,如果有了Class类对象,那么就可以做到利用反射来实现对象实例化操作。
实例化对象方法:public T newInstance()throws InstantiationException,IllegalAccessException
package com.company.javabase.relfect;
class Book { public Book() { System.out.println("**********无参构造方法*******"); }
@Override public String toString() { return"这是一本书"; } }
publicclass Relfect { publicstaticvoid main(String[] args) throws Exception { Class> class1 = Class.forName("com.company.javabase.relfect.Book"); Object object = class1.newInstance(); // 相当于使用new调用无参构造实例化对象 Book book = (Book) object; System.out.println(book); System.out.println(object); } }
|
有了反射之后,以后进行实例化操作的时候可以用new和反射来操作了
在任何的开发之中,new是造成耦合度的最大元凶,一切的耦合都起源于new。
package com.company.javaadvance; interface Fruit{ public void eat(); } class Apple implements Fruit{ @Override public void eat() { System.out.println("吃苹果!"); } } class Factory{ public static Fruit getInstance (String classname) { if ("apple".equals(classname)) { return new Apple(); } return null; } } public class Reflect { public static void main(String[] args) throws Exception { Fruit fruit = Factory.getInstance("apple"); fruit.eat(); } }
如果此时要添加一个新的Fruit接口子类,那么久表示程序要修改工厂类。
每增加一个类就要去修改工厂类,那么如果随时都可能增加子类呢。
因为现在工厂类中的对象都是通过关键字new直接实例化,而new就成了所有问题的关键点,要想解决这一问题,就只能依靠反射来解决。
package com.company.javabase.relfect;
interface Fruit{ publicvoid eat(); }
class Apple implements Fruit{ @Override publicvoid eat() { System.out.println("吃苹果!"); } }
class Orange implements Fruit{ @Override publicvoid eat() { System.out.println("吃橘子!"); } }
class Factory{ publicstatic Fruit getInstance (String classname) { Fruit f = null; try { f = (Fruit)Class.forName(classname).newInstance(); } catch (Exception e) { e.printStackTrace(); } returnf; } }
publicclass Relfect { publicstaticvoid main(String[] args) throws Exception { Fruit fruit = Factory.getInstance("com.company.javabase.relfect.Orange"); fruit.eat(); } } |
此时的程序就会变得耦合度很低,而且可扩展性很强。
示例:当前Book类里没有无参构造方法
package com.company.javabase.po;
publicclass Book { private String title; privatedoubleprice;
public Book(String title, doubleprice) { this.title = title; this.price = price; }
@Override public String toString() { return"图书名称:" + this.title + "\t图书价格" + this.price; } } |
publicclass Relfect { publicstaticvoid main(String[] args) throws Exception { Class> class1 = Class.forName("com.company.javabase.po.Book"); Object object = class1.newInstance(); // 相当于使用new调用无参构造实例化对象 System.out.println(object); } }
Exception in thread "main" java.lang.InstantiationException: com.company.javabase.po.Book at java.lang.Class.newInstance(Class.java:427) at com.company.javabase.relfect.Relfect.main(Relfect.java:58) Caused by: java.lang.NoSuchMethodException: com.company.javabase.po.Book. at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 1 more |
因为Book类里面没有无参构造方法,所以程序无法进行对象的实例化。在这中情况下,只能够明确的调用有参构造方法
在Class类里面有明确的方法取得构造:
|
以上两个方法返回的都是java.lang.reflect.Constructor类的对象。
在这个类中我们有一个明确传递有参构造内容对象的实例化方法。
publicclass Relfect { publicstaticvoid main(String[] args) throws Exception { Class> class1 = Class.forName("com.company.javabase.po.Book"); Constructor> con = class1.getConstructor(String.class,double.class); Object object = con.newInstance("java开发",99.99); System.out.println(object); } } |
简单Java类的开发之中不管提供有多少个构造方法,请至少保留无参构造。
类中的普通方法只有在一个类产生实例化对象之后才可以调用。并且实例化的方式有三种。
示例:定义一个类
package com.company.javabase.po;
publicclass Book { private String title;
publicvoid setTitle(String title) { this.title = title; } public String getTitle() { returntitle; } } |
这个类有无参构造方法,所以实例化对象的时候可以直接利用Class类中提供的newInstance()方法完成。
在Class类里面有提供有以下取得类中Method的操作:
取的一个类中的全部方法:public Method[] getMethods()throws SecurityException
取得一个类中的指定的方法
public Method getMethod(Stringname,Class>... parameterTypes)throwsNoSuchMethodException,SecurityException
以上两个操作返回的都是java.lang.reflect.Method的对象
在这个类里面有一个方法叫调用方法:public Object invoke(Objectobj,Object... args)throwsIllegalAccessException,IllegalArgumentException,InvocationTargetException
示例:通过反射调用方法
import java.lang.reflect.Method;
publicclass Relfect { publicstaticvoid main(String[] args) throws Exception { String filedName = "title"; //要操作的成员 Class> class1 = Class.forName("com.company.javabase.po.Book"); Object object = class1.newInstance(); //必须给出实例化对象 Method setMethod = class1.getMethod("set"+initcap(filedName), String.class); Method getMethod = class1.getMethod("get"+initcap(filedName)); setMethod.invoke(object, "java开发"); //等价于:Book类对象.setTitle("java开发"); System.out.println(getMethod.invoke(object)); } publicstatic String initcap(String str){ returnstr.substring(0,1).toUpperCase() + str.substring(1); } } |
完全看不见具体操作的类型,也就是说利用反射可以实现任意类的指定的方法的的调用。
类中的属性一定要在本类实例化对象之后才可以分配内存空间。在我们Class类里提供有取得成员的方法。
1、 取得全部成员
public Field[]getDeclaredFields()
throws SecurityException
2、 取得指定成员
public Field getDeclaredField(String name)
throwsNoSuchFieldException,SecurityException
返回类型是 java.lang.reflect.Field类,在这个类里面有两个方法分别是:
取得属性内容
public Object get(Object obj)
throwsIllegalArgumentException,IllegalAccessException
设置属性内容
public void set(Object obj,Object value)
throws IllegalArgumentException,IllegalAccessException
示例:提供有如下类
package com.company.javabase.po; publicclass Book { private String title; } |
这个类里面只定义了一个私有属性,一般无法被外部所使用
示例:反射调用
java.lang.reflect.AccessibleObject 类里面(JDK1.8之后修改)
Executable:下面继承了 Constructor 、 Method
Field:
在这个类里面有提供有个方法
public void setAccessible(boolean flag)
throws SecurityException
设置是否封装
publicclass Relfect { publicstaticvoid main(String[] args) throws Exception{ Class> class1 = Class.forName("com.company.javabase.po.Book"); Object object = class1.newInstance(); //必须给出实例化对象 Field titileField = class1.getDeclaredField("title"); titileField.setAccessible(true); //取消封装 titileField.set(object, "java开发"); //想到与:Book类对象.title = "java开发"; System.out.println(titileField.get(object)); } } |
构造方法和普通方法也是可以取消封装的,只不过很少去用