2019-04-16
2019-04-16 本文已影响0人
凨茗
Java使用反射机制生成对象的3种方式
一、在构造函数为空的情况下
普通对象Book,构造函数为空的情况下
Class Book{
public Book(){
System.out.println("初始化Book,无参构造函数!");
}
@Override
public String toString(){
System.out.println("这是一本书!“);
}
}
1.使用对象的getClass方法
public class TestBook{ //测试方法
public static void main(String[] args) throws Exception{
Book b = new Book();
Class<?> cls = b.getClass();
Object obj = cls.newInstance(); //进行实例化
Book book = (Book)obj;
System.out.println(book);
}
}
2.使用"类.class"取得
public class TestBook{ //测试方法
public static void main(String[] args) throws Exception{
Class<?> cls = Book.Class;
Object obj = cls.newInstance();
Book book = (Book)obj;
System.out.println(book);
}
}
3.调用Class对象提供的方法Class.forname
public class TestBook{ //测试方法
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Book");
Object obj = cls.newInstance();
Book book = (Book)obj;
System.out.println(book);
}
}
此时可以不使用import导入一个明确的类,可以使用字符串的方式进行描述
二、在构造函数不为空的情况下
普通对象Book,构造函数不为空的情况下
Class Book{
private Stirng title ;
String double price;
public Book(String title ,double price){
this.title = title ;
this.price = price ;
}
@Override
public String toString(){
System.out.println("图书:“+this.title+ ",价格:"+this.price);
}
}
此时不能直接调用getInstance 方法进行实例化,需要使用getConstructor方法,返回的是Constructor对象
具体如下
public class TestBook{
public static void main(String[] args){
Class<?> cls = Class.forName("Book");
Construcotr<?> con = cls.getConstructor(String.class,double.class);//参数的类型定位
Object obj = con.newInstance("Hadoop",49.9); //里面是构造函数的参数
System.out.println(obj);
}
}
所以最好在类中提供无参构造方法最好
三、反射调用方法
基本的对象Book
Class Book{
private String title;
public void setTitle(String title)(){
this.tile=title;
}
public String getTitle(){
return title;
}
}
在Class类中有以下几种取得类中方法的操作
- 取得全部方法getMethods
- 取得一个方法getMethod
以上方法返回的java.reflect.Method类的对象,在这个类中重点关注一个方法
- 调用方法public Object invoke(Object obj, Object…args)
反射调用
import java.lang.reflect.Method;
public class TestBook{ //测试方法
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Book");
Object obj = cls.newInstance(); //必须实例化对象才能调用方法
Method setMet= cls.getMethod("setTitle",String.class);
Method getMet= cls.getMethod("getTitle");
setMet.invoke(obj,"java开发"); //等价于:Book类对象.setTitle(“java开发”)
System.out.println(getMet.invoke(obj));
}
}
四.反射调用成员
类中的属性一定要在本类实例化对象产生之后才能分配内存空间。在class类里面提供有取得成员的方法:
- 取得全部成员 public Field[] getDeclaredFields()
- 取得指定成员 public Field getDeclaredField(String name)
返回的类型java.lang.reflect.Field类,在这两个类中有两个重要的方法
- 取得属性内容:public Object get(Object obj)
- 设置属性内容:public Object set(Object obj, Object value)
基本对象Book
Class Book{
public Book(){
private String title;
}
}
取得对象和设置对象
import java.lang.reflect.Field;
public class TestBook{ //测试方法
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("Book");
Object obj = cls.newInstance(); //必须实例化对象才能调用方法
Field titleField = cls.getDeclaredField("title");
titleField.set(obj,"java开发");//相当于:Book.title="java开发"
System.out.println(titleField.get(obj))
}
}
此时会提示错误,因为title是私有的属性
在java.lang.reflect.AccessibleObject类下面(jdk1.8之后修改)
-
Executable:下面继续继承了Constructor、Method
-
Field:在这个类里面提供了:public void setAccessible(boolean flag)方法。用来设置是否封装,此时
import java.lang.reflect.Field; public class TestBook{ //测试方法 public static void main(String[] args) throws Exception{ Class<?> cls = Class.forName("Book"); Object obj = cls.newInstance(); //必须实例化对象才能调用方法 Field titleField = cls.getDeclaredField("title"); titleField.setAccessible(true);//封装取消了 titleField.set(obj,"java开发");//相当于:Book.title="java开发" System.out.println(titleField.get(obj)) } }
此时就不会出错了,构造方法和普通的方法也可以取消封装,但是一般不这样做。所以属性设置最好还是使用setter和getter方法