Java语言入门(十四)——反射机制

反射(内省)

  1. java程序在运行期间可以动态加载、解析和使用一些在编译阶段并不确定的类型,这一机制为反射。
  2. 反射机制提供的功能:
    加载运行时才能确定的数据类型
    解析类的结构,获取其内部信息
    操作该类型或其实例(访问属性,调用方法,创建新对象)
  3. Reflection API: java.lang.Class、java.lang.reflect
  4. 思考
    (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类的实例

  1. Class类的实例其实是Java中的JVM中的一份字节码, .class文件
  2. 所有的类和接口都是用Class来描述的
  3. 为了明确的区分Class实例表示的是哪一个类的实例,就提供了泛型机制
    Class d= new Date();
    Class s= new String();
  4. 对象:具体数据;类:描述对象(数据)【描述数据的数据】

如何获得Class的实例

  1. 类名.class
  2. 用new调用构造方法,但是Class类是没有构造方法的,因此不能用此方法
    public static Class<?> forName(String className) throws ClassNotFoundException
  3. 用对象的方式获得一个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. 思考
    (1)c==c1 ?? 同是person对象,是否为同一个?
    结果:true
    同一个.class文件。一个类在JVM中只有一份字节码
    (2)public final Class<? extends Object> getClass()返回一个对象的运行时类。该 Class 对象是由所表示类的static synchronized 方法锁定的对象。

Java中九大内置Class实例和数组的Class实例

  1. 九大内置class实例 = Java八大基本数据类型 + void(void的应用很少)
    byte,short,int,char,long,float,double,Boolean;void
    结论:每一种基本的数据类型都有其相应的class属性,形式是 类型名.class
  2. 包装类本身就是类,类就有.class
  3. 思考:int.class == ? == Integer.class
  4. public static final Class TYPE 表示基本类型int的实例
  5. 八种基本数据类型的包装类中,都有一个TYPE常量,用来表示基本类型的Class实例
  6. 数组的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);
	}
}

获取类中的构造器

步骤:

  1. 明确操作的是哪一个类(字节码)(获取类的实例有三种方法)
  2. 获取构造方法(4种方法)
  3. 用反射的方法来创建对象

获取构造方法(四种)

Constructor类所对应的对象是:一个类中的构造方法。

  1. Constructor<?>[] getConstructors()
    返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
  2. Constructor<?>[] getDeclaredConstructors()
    返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
  3. Constructor< T> getConstructor(Class<?>… parameterTypes)
    返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
  4. Constructor< T> getDeclaredConstructor(Class<?>… parameterTypes)
    返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。

创建对象

  1. Constructor类中的一个方法
    public T newInstance(Object… initargs)
    throws InstantiationException,
    IllegalAccessException,
    IllegalArgumentException,
    InvocationTargetException
    思考:newInstance()和new有什么区别?
  2. Class类中也有这样一个方法,如果有一个构造器是public的,并且无参数,就可以使用此方法
    public T newInstance()
    throws InstantiationException,
    IllegalAccessException
    创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。
    返回:此对象所表示的类的一个新分配的实例。

newInstance() 和 new 有什么区别?

  1. 从jvm的角度看,我们使用new的时候,这个要new的类可以没有加载;
  2. 但是使用newInstance时候,就必须保证:(1)这个类已经加载;(2)这个类已经连接了。newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。
  3. newInstance()是实现IOC、反射、面对接口编程 和 依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程

setAccessible

  1. 在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序(比如 Java Object Serialization 或其他持久性机制)以某种通常禁止使用的方式来操作对象。
    public void setAccessible(boolean flag)
    throws SecurityException
  2. 将此对象的 accessible 标志设置为指示的布尔值。
  3. 实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问。

获取类中的方法

步骤:

  1. 明确操作的是哪一个类(字节码)(获取类的实例有三种方法)
  2. 获取方法(4种方法)
  3. 用反射的方法来调用方法。

获取方法(四种)

  1. Method[] getMethods()
    返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
  2. Method[] getDeclaredMethods()
    返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
  3. Method getMethod(String name, Class<?>… parameterTypes)
    返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
  4. Method getDeclaredMethod(String name, Class<?>… parameterTypes)
    返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
    String name:方法的名称,是一个字符串类型

调用方法

  1. java.lang.reflect.Method类中的一个方法
    public Object invoke(Object obj,Object… args)throws IllegalAccessException,
    IllegalArgumentException,
    InvocationTargetException
  2. 参数:
    obj - 从中调用底层方法的对象
    args - 用于方法调用的参数
    返回:使用参数 args 在 obj 上指派该对象所表示方法的结果
  3. 总结:
    因为反射可以调用私有的方法(或构造器),所以功能强大,比传统方法更加灵活,但是这些都是以消耗系统的性能方式为代价的。主要用于工具和框架。

用反射来获取字段

  1. 获取字段
    在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 对象所表示的类或接口所声明的所有字段。
  2. 给字段设置和获取值:
    在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类中)

  1. String getName()
    以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
  2. Package getPackage() 获取此类的包。
  3. String getSimpleName()
    返回源代码中给出的底层类的简称。
  4. int getModifiers()
    返回此类或接口以整数编码的 Java 语言修饰符。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的Handler机制是Android开发中非常重要的一个概念,它是用来处理线程之间的通信的。在Java中,也可以使用Handler机制来实现线程之间的通信,这里简要介绍一下Java中的Handler机制。 Java中的Handler机制是基于线程池的,它可以将任务提交到线程池中执行,并且可以将执行结果返回给调用者。在Java中,可以使用Executor框架来实现线程池,同时可以使用Future接口来获取执行结果。 在Java中,Handler机制可以通过以下几个步骤来实现: 1. 创建一个线程池,可以使用Executor框架来实现。 2. 创建一个Callable接口的实现类,该实现类用来执行任务并返回结果。 3. 将Callable实现类提交到线程池中执行,可以使用submit()方法来实现。 4. 获取执行结果,可以使用Future接口来获取。 下面是一个简单的示例代码: ```java import java.util.concurrent.*; public class HandleJava { public static void main(String[] args) throws Exception { // 创建线程池 ExecutorService executor = Executors.newFixedThreadPool(1); // 创建Callable实现类 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { // 执行任务 Thread.sleep(1000); return "Hello, world!"; } }; // 提交任务到线程池 Future<String> future = executor.submit(callable); // 获取执行结果 String result = future.get(); System.out.println(result); // 关闭线程池 executor.shutdown(); } } ``` 这个示例代码中,创建了一个线程池,然后创建了一个Callable实现类,将其提交到线程池中执行,并且使用Future接口来获取执行结果。最后关闭线程池。 需要注意的是,线程池一定要关闭,否则程序会一直运行下去,不会退出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值