Java - 基础 - 反射
反射机制
-
什么是反射
-
反射的作用
-
利用反射调用类结构
1.认识反射
正:正常情况下,先有类,之后才会有类的对象
反:可以利用对象找到对象的出处
取得Classs对象:
public final Class<?> getClass()
该方法继承自Object类,所以,所有的类都有这个方法
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.getClass());
}
//输出:
//class java.util.Date
2.Class类对象实例化
java.lang.Class是一个类。该类是反射的源头,该类有三种实例化方法,如下:
-
调用Object类中的getClass()方法
public static void main(String[] args) { Date date = new Date(); Class <?> cls = date.getClass(); System.out.println(cls); }
-
使用"类.class"取得
public static void main(String[] args) { Class <?> cls = Date.Class; System.out.println(cls); }
-
调用Class类提供的方法
实例化Class对象:
public static Class<?> forName(String className)
throws ClassNotFoundExceptionpublic static void main(String[] args) { Class <?> cls = Class.forName("java.util.Date"); System.out.println(cls); }
此时可以不使用import进行导入
3.反射实例化对象
当拿到一个类的时候,使用new 实例化对象。如果存在Class类对象,就可以通过反射进行对象的实例化
实例化对象方法:
public T newInstance() throws InstantiationException, IllegalAccessException
示例
class Book{
public Book() {
System.out.println("********************");
}
public String toString() {
return "这是一本书";
}
}
public class test {
public static void main(String[] args) throws Exception {
//1.常规方法,new对象
Book b = new Book();
System.out.println(b);
//2.反射对象
Class<?> cls = Class.forName("com.String.Book");
Object o = cls.newInstance();
Book book = (Book)o;
System.out.println(o);//输出b和o结果一样
}
}
4.反射调用构造
当类中只有有参构造的时候,通过反射调用,会产生异常
错误代码示例
package com.String;
public class test {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.t.Book");
Object o = cls.newInstance();
System.out.println(o);
}
}
Book类,位于其他包
package com.t;
public class Book{
private String title;
private double price;
public Book(String title , double price) {
this.title = title ;
this.price = price;
}
public String toString() {
return "书名:"+this.title+",价格:"+this.price;
}
}
异常信息
Exception in thread "main" java.lang.InstantiationException: com.t.Book
at java.lang.Class.newInstance(Unknown Source)
at com.String.test.main(test.java:11)
Caused by: java.lang.NoSuchMethodException: com.t.Book.<init>()
at java.lang.Class.getConstructor0(Unknown Source)
... 2 more
解决方法:
在Class类中,提供有获取构造方法的方法
-
取得全部构造方法:
public Constructor <?> [] getConstructors()
-
取得一个指定参数的构造方法:
public Constructor < T > getConstructor(Class<?>… parameterTypes)
上面两个方法的返回值**Constructor **是java.lang.reflect.Constructor类的对象,在这个类中提供有一个明确传递有参构造内容的实例化对象方法
public T newInstance(Object... initargs)
解决代码示例:
package com.String;
import java.lang.reflect.Constructor;
public class test {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.t.Book");
Constructor<?> con = cls.getConstructor(String.class,double.class);
Object o = con.newInstance("java开发",79.8);
System.out.println(o);
}
}
简单JAVA类的开发之中,至少保留一个无参构造,反射调用不方便
5 .反射调用方法
类中的普通方法,只有在类产生实例化对象之后才可以调用。
实例化对象的方式有三种
- new一个对象
- 克隆一个对象
- 反射一个对象
在Class类中,提供有取得方法的操作
-
取得一个类中的全部方法
public Method[] getMethods()
-
取得指定名称的方法
public Method getMethod(String name, Class<?>... parameterTypes)
name是方法名称
上面两个方法的返回值**Method **是java.lang.reflect.Method 类的对象
-
调用方法:
public Object invoke(Object obj, Object... args)
示例代码
Book类,位于其他包
package com.t;
public class Book{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
调用方法:
package com.String;
import java.lang.reflect.Method;
public class test {
public static void main(String[] args) throws Exception {
String fielName = "title";
Class<?> cls = Class.forName("com.t.Book");
Object o = cls.newInstance();
Method setMet = cls.getMethod("set" +initcap(fielName), String.class);
Method getMet = cls.getMethod("get" +initcap(fielName));
setMet.invoke(o, "java开发");
System.out.println(getMet.invoke(o));
}
//首字母大写
public static String initcap(String str) {
return str.substring(0, 1).toUpperCase()+str.substring(1);
}
}
6.反射调用成员
类中的属性,一定要在本类实例化对象产生之后才可以分配内存空间
-
取得全部成员
public Field[] getDeclaredFields()
-
取得指定成员
public Field getDeclaredField(String name)
上面两个方法的返回值Field是java.lang.reflect.Field类的对象,该类提供有如下常用方法
-
取得属性内容
public Object get(Object obj)
-
设置属性内容
public void set(Object obj,Object value)
使用示例:
Book类,位于其他包
package com.t;
public class Book{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
反射调用:
package com.String;
import java.lang.reflect.Field;
public class test {
public static void main(String[] args) throws Exception {
//1.实例化类对象
Class<?> cls = Class.forName("com.t.Book");
Object o = cls.newInstance();
//取得成员
Field titleField = cls.getDeclaredField("title");
//取消封装,不取消无法访问private变量
titleField.setAccessible(true);
//设置成员变量
titleField.set(o, "python");
System.out.println(titleField.get(o));
}
}
构造方法和普通方法也可以取消封装
7.总结
- 实例化对象的方式多了一种:反射
- 简单JAVA类需要使用无参构造以及使用set\get方法的原因