Java 反射


一、我们来讲Class类的使用。首先我们要理解两个方面

  1. 理解类类型。类类型实际上就是类的类,什么意思,我们知道万事万物皆对象,那么类也是对象,那么这个类的对象是什么谁呢,是Class。
     创建类类型有三种方式:
     a. 直接调用类的class()方法如:
Class c1 = Foo.class;
     b. 用对象的getClass()方法。如:
Foo foo = new Foo();
Class c2 = foo.getClass();     
     c. 使用Class类的 forName()方法
Class c3 = null;
c3=Class.forName("test.Foo"); //注意要有try catch ,此处忽略   

   2. 理解如何通过类类型创建对象      

try {
		Foo foo = (Foo)c1.newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
这里使用 Foo foo = (Foo)c1.newInstance();来创建对象

二、如何理解Class加载类,即Class.forName
    上一节我们讲到了创建类类型的三种方式,第三种是通过Class的加载类实现的。那么怎么理解呢?
     Class.forName("类的全称");
     a. 不仅表示了类的类类型,还代表了动态加载类。
     b. 在运行时加载。怎么理解在运行时加载呢?在我们的IDE工具下,我们不能分清哪是编译哪是运行时,因为工具已经帮你做了。
     c. 编译时刻加载类是静态加载类,运行时刻加载类是动态加载类
       举例,加入有如下程序:

  class  Office
		{
			public static void main(String[] args) 
			{
				if("Word".equals(args[0])){
					//System.out.println("word")
					Word word = new Word();
					word.start();
				}

				if(args[0].equals("exel")){
					//system.out.println("word")
					Exel exel = new Exel();
					exel.start();
				}
			}
		}

		class Word
		{
			public void start(){
				System.out.println("word start");
			}
		}

分析:我们说首先编译是不能通过的,因为没有Exel类。但是,假如一个软件只需要Word启动呢,那就不好办了。运用编译加载的缺点是:只要有一个出错,则都不能通过使用,而我们在实际
       使用过程中,当然是希望Word能用,而当使用Exel时才给我们报错的。也就是说,如果我们的软件如果有100个功能,加入一个有问题,整个功能就会有问题。
       而动态加载可以解决这个问题。如改成下面的程序:

	class  Office
		{
			public static void main(String[] args) 
			{
				try
				{
					Class c = Class.forName(args[0]);
					//通过类类型创建对象,这里有个问题:即要求根据输入参数创建类,不能写死。为此我们要用到接口,即符合这个标准的类我才认为你是Office的一个功能。(很重要,接口的重要作用)
					Ioffice ioffice =(Ioffice)c.newInstance();
					ioffice.start();


				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
			}
		}

		interface Ioffice
		{
			public void start();
		}

		class Word implements Ioffice
		{
			public void start(){
				System.out.println("word start");
			}
		}

		class Exel implements Ioffice
		{
		public void start(){
				System.out.println("exel start");
			}
		}
  结论:以后功能型的创建,尽量使用动态加载

三、通过反射获取方法信息(属性,方法,构造方法)
         写一个方法,获取类的全部信息

  public class DemoUtil {	
	/**
	 * 打印类的信息,包括类的成员函数,成员变量
	 * @param obj
	 */
	public static void printClassInfo(Object obj){
		Class c =	obj.getClass();// 它是native方法,JNI,这中方法用Java语言来声明,用C语音实现
		//传递的是哪个子类的对象,c就是该子类的类类型
		
		//1.获取类的名称
		System.out.println("类的名称是:"+c.getName());
		
		//2.获取类的方法
		Method[] methods= c.getMethods(); //获取类中所有public的函数,包括父类继承而来的
		methods= c.getDeclaredMethods();//获取所有该类的自己声明的方法,不问访问权限
		for(int i=0;i<methods.length;i++){
			//2.1 得到返回值类的类类型
			Class returnType=methods[i].getReturnType();
			System.out.println(returnType.getName()+" ");
			
			//2.2 得到方法名称
			String methodName=methods[i].getName();
			System.out.println(methodName+" ");
			
			//2.3 得到方法参数类型---》得到的是参数列表类型的类类型
			Class[] paramTypes=methods[i].getParameterTypes();
			for(Class class1 : paramTypes){
				System.out.print(class1.getName()+",");
			}
		}
		
		//3.获取类的属性,包含所有访问权限的属性,public private proteced
		System.out.println();
		for(Field f:c.getDeclaredFields()){ 
			System.out.println(f);
		}
		
		//4. 获取构造函数		
		for(Constructor f:c.getConstructors()){ 
			System.out.println(f);
		}

	}
	
	public static void main(String[] args) {
		//Demo demo = new Demo();
		DemoUtil.printClassInfo(new String());
	}
}

class Demo{
	public int a=0;
	private String b="jkj";
	protected int c=10;
	
	public void starts(int a,int b,String d) {
		System.out.println("XXXX");
	}
}

四、 方法的反射

    1.如何获取某个方法
    获取 方法名称和方法参数列表才能唯一决定某个方法
    2. 方法反射的操作
    method.invoke(对象,参数列表)

    如下代码:
    method m =c.getMethod("print",new Class[]{int.class,int.class});
    或者: method m =c.getMethod("print",int.class,int.class);

    //调用print方法  a1.print(10,20)
    Object o =m.invoke(a1,new Object[]{10,20})
     Object o =m.invoke(a1,10,20)


五、通过Class,Method 认识泛型的本质

ArrayList list = new ArrayList<>();
   ArrayList<String> list1=new ArrayList<String>(); 
			//list1.add(100);在这里是出错的。因为类型不一致,但是在后面运用反射是可以的。
			
			Class c1=list.getClass();
			Class c2=list1.getClass();
			
			System.out.println(c1==c2); //为true,说明编程之后,集合的泛型是去泛型化的。
			//Java中集合的泛型,是防止错误输入的,只在编译阶段有效。
			//验证:我们可以通过方法的反射来操作,绕过编译
			try {
				Method m = c1.getMethod("add", Object.class);
				m.invoke(list1, 100);
				System.out.println(list1.size());//大小为1,说明加进去了
			} catch (Exception e) {
				e.printStackTrace();
			}
总结:定义:泛型只是编译时的概念,是供编译器进行语法检查用的。所谓泛型,就是在定义(类型的定义,方法的定义,形式参数的定义,成员变量的定义等等)的时候,指定它为通用类型,也就是数据类型可以是任意的类型,如List<?> list = null,具体调用时,要将通用类型转换成指定的类型。泛型提高了大型程序的类型安全和可维护性。



内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值