Java语言入门
反射(内省)
- java程序在运行期间可以动态加载、解析和使用一些在编译阶段并不确定的类型,这一机制为反射。
- 反射机制提供的功能:
加载运行时才能确定的数据类型
解析类的结构,获取其内部信息
操作该类型或其实例(访问属性,调用方法,创建新对象) - Reflection API: java.lang.Class、java.lang.reflect
- 思考
(1)问题一:能否从一个对象反向推出类的信息
Object ob= new getInstance();
( )ob.after();
(2)问题二:谁来描述类:Class类
String s1=new String(); String s2=new String();
Date d1=new Date(); Date d2=new Date();
List l1=new ArrayList(); List l2=new ArrayList();
Class类和Class类的实例
- Class类的实例其实是Java中的JVM中的一份字节码, .class文件
- 所有的类和接口都是用Class来描述的
- 为了明确的区分Class实例表示的是哪一个类的实例,就提供了泛型机制
Class d= new Date();
Class s= new String(); - 对象:具体数据;类:描述对象(数据)【描述数据的数据】
如何获得Class的实例
- 类名.class
- 用new调用构造方法,但是Class类是没有构造方法的,因此不能用此方法
public static Class<?> forName(String className) throws ClassNotFoundException - 用对象的方式获得一个Class类的实例
public static Class<? extends Object> getClass()
package FanShe;
import java.util.ArrayList;
@SuppressWarnings("unchecked")
public class FanShe {
public static void main(String[] args) throws ClassNotFoundException{
//1. 使用类名.class的方法得到Class类的实例
Class<person> c=person.class;
System.out.println(c);
Class<String> s=String.class;
System.out.println(s);
}
}
package FanShe;
import java.util.ArrayList;
@SuppressWarnings("unchecked")
public class FanShe {
public static void main(String[] args) throws ClassNotFoundException{
//2.使用forName(String className) 得到一个class类的实例
//此时用的泛型一定是?通配符
Class c1=Class.forName("FanShe.person");//一定要全限定名,包括包名和类名
System.out.println(c1);
Class<?> s1=Class.forName("java.util.List");
System.out.println(s1);
}
}
package FanShe;
import java.util.ArrayList;
@SuppressWarnings("unchecked")
public class FanShe {
public static void main(String[] args) throws ClassNotFoundException{
//3.使用对象的getClass()方法去获取一个Class的实例。(每一个对象都有一个getClass()的方法,这个是Object类中的一个最终方法。)
person p = new person();
Class p1 = p.getClass();
System.out.println(p1);
Class l1=new ArrayList().getClass();
System.out.println(l1);
}
}
- 思考
(1)c==c1 ?? 同是person对象,是否为同一个?
结果:true
同一个.class文件。一个类在JVM中只有一份字节码
(2)public final Class<? extends Object> getClass()返回一个对象的运行时类。该 Class 对象是由所表示类的static synchronized 方法锁定的对象。
Java中九大内置Class实例和数组的Class实例
- 九大内置class实例 = Java八大基本数据类型 + void(void的应用很少)
byte,short,int,char,long,float,double,Boolean;void
结论:每一种基本的数据类型都有其相应的class属性,形式是 类型名.class - 包装类本身就是类,类就有.class
- 思考:int.class == ? == Integer.class
- public static final Class TYPE 表示基本类型int的实例
- 八种基本数据类型的包装类中,都有一个TYPE常量,用来表示基本类型的Class实例
- 数组的Class实例:数组定义类[].class ,对于维数相同,类型相同的数组,共享一份Class实例。和数组的大小,内容无关。
九大内置class实例-1
package FanShe;
public class FanS {
public static void main(String[] args){
Class<Integer> c=int.class;
System.out.println(c);
System.out.println(boolean.class);
System.out.println(void.class);
System.out.println(Integer.class);
System.out.println(Integer.class == int.class);
}
}
九大内置class实例-2
package FanShe;
public class FanS {
public static void main(String[] args){
System.out.println(Integer.class);
System.out.println(Integer.TYPE);
System.out.println(Integer.class == int.class);
System.out.println(Integer.TYPE == int.class);
}
}
数组的class实例
package FanShe;
public class FSshuzu {
public static void main(String[] args){
String []a={"a","b"};
String []b={"a","b","c"};
Class A1=a.getClass(); //字节码文件
Class B1=b.getClass();
System.out.println(A1);
System.out.println(String[].class==A1);
System.out.println(B1==A1);
}
}
获取类中的构造器
步骤:
- 明确操作的是哪一个类(字节码)(获取类的实例有三种方法)
- 获取构造方法(4种方法)
- 用反射的方法来创建对象
获取构造方法(四种)
Constructor类所对应的对象是:一个类中的构造方法。
- Constructor<?>[] getConstructors()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 - Constructor<?>[] getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 - Constructor< T> getConstructor(Class<?>… parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 - Constructor< T> getDeclaredConstructor(Class<?>… parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
创建对象
- Constructor类中的一个方法
public T newInstance(Object… initargs)
throws InstantiationException,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException
思考:newInstance()和new有什么区别? - Class类中也有这样一个方法,如果有一个构造器是public的,并且无参数,就可以使用此方法
public T newInstance()
throws InstantiationException,
IllegalAccessException
创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。
返回:此对象所表示的类的一个新分配的实例。
newInstance() 和 new 有什么区别?
- 从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载;
- 但是使用newInstance时候,就必须保证:(1)这个类已经加载;(2)这个类已经连接了。newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。
- newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程
setAccessible
- 在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。
public void setAccessible(boolean flag)
throws SecurityException - 将此对象的 accessible 标志设置为指示的布尔值。
- 实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问。
获取类中的方法
步骤:
- 明确操作的是哪一个类(字节码)(获取类的实例有三种方法)
- 获取方法(4种方法)
- 用反射的方法来调用方法。
获取方法(四种)
- Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 - Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 - Method getMethod(String name, Class<?>… parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 - Method getDeclaredMethod(String name, Class<?>… parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
String name:方法的名称,是一个字符串类型
调用方法
- java.lang.reflect.Method类中的一个方法
public Object invoke(Object obj,Object… args)throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException - 参数:
obj - 从中调用底层方法的对象
args - 用于方法调用的参数
返回:使用参数 args 在 obj 上指派该对象所表示方法的结果 - 总结:
因为反射可以调用私有的方法(或构造器),所以功能强大,比传统方法更加灵活,但是这些都是以消耗系统的性能方式为代价的。主要用于工具和框架。
用反射来获取字段
- 获取字段
在Class类中有相应的四个方法
(1)Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
(2)Field[] getFields()
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
(3)Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
(4)Field[] getDeclaredFields()
返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 - 给字段设置和获取值:
在Field类中的两个方法
(1)public void set(Object obj,Object value)
throws IllegalArgumentException, IllegalAccessException
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。如果底层字段的类型为基本类型,则对新值进行自动解包。
(2)public Object get(Object obj)
throws IllegalArgumentException,IllegalAccessException
返回指定对象上此 Field 表示的字段的值。如果该值是一个基本类型值,则自动将其包装在一个对象中。
和反射相关的其他API(在Class类中)
- String getName()
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 - Package getPackage() 获取此类的包。
- String getSimpleName()
返回源代码中给出的底层类的简称。 - int getModifiers()
返回此类或接口以整数编码的 Java 语言修饰符。