【Java进阶】Java反射的使用

Class类的使用

 

1.      类是谁的对象? 类是对象,类是java.lang.Class类的实例对象。

2.      这个对象如何表示?有三种表达方式

public class ClassDemo1 {
	public static void main(String[] args) {
		//Foo的对象如何表示
		Foo foo1 = new Foo();//fool1就被表示出来了
		//Foo这个类 也是一个实例对象,Class类的实例对象,如何表示
		//任何一个类都是Class类的实例对象,这个实例对象有三种表达方式
		
		//第一种表达方式--实际在告诉我们任何一个类都有一个隐含的静态成员变量class
		Class c1 = Foo.class;
		
		//第二种表达方式--已经知道该类的对象通过getClass()方法
		Class c2 = foo1.getClass();
		
		/*c1 c2 表示了Foo类的类类型(class type)*/
		//不管从 c1 c2 都代表了Foo类的类类型
		System.out.println(c1 == c2);
		
		//第三种表达方式
		Class c3 = null;
		try {
			c3 = Class.forName("com.reflect.Foo");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		System.out.println(c2 == c3);
		
		//我们完全可以通过类的类类型创建该类的对象实例--通过 c1 c2 或 c3创建Foo的对象
		try {
			Foo foo = (Foo)c1.newInstance();
			foo.print();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
}

class Foo{
	
	public void print(){
		System.out.print("foo");
	}
}

Class.forName(“类的全称”)

         不仅代表了类的类类型,还代表了动态加载类。

请注意区分编译、运行。

编译时刻加载类是静态加载类,运行时刻加载类是动态加载类

 

动态加载和静态加载

 

我们创建一个Office.java类

class Office{
    public static void main(String[] args){
        if("Word".equals(args[0])){
            /*使用new 方法创建的类是静态加载,在编译时就要加载所有有可能使用到的类*/
            Word w = new Word();
            w.start();
        }
        if("Excel".equals(args[0])){
            Excel e = new Excel();
            e.start();
        }
    }
}

如上面的类,直接编译会报找不到Word类,找不到Excel类。

 

假如我们只需要用到Word类,而不需要Excel类,我们创建Word.java 类

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

在编译时,我们会发现仍然会报错,找不到Excel类,我们此时不需要用到Excel类,但是还是会去编译加载它,如果有很多的类,如ppt … 一旦某个类出了问题,我们的程序就不能运行了,一招出错,满盘皆输。

 

下来我们采用动态加载的方式,创建OfficeBetter类

class OfficeBetter{
    public static void main(String[] args){
        try{
            //动态加载类,在运行时
Class c = Class.forName(args[0]);
//通过类类型创建对象
Word w = (Word)c.newInstance();//强制类型转换为Word,如果传递的参数是Excel就报错
w.start();
}catch(Exception e){
            e.printStackTrace();
        }
    }
}

上面通过类类型来创建对象,如果传递java OfficeBetter Excel ,Excel转Word就会报错,所以我们用另一种方法,创建一个统一的接口,让Word和Excel都实现这个接口。

OfficeAble.java

interface OfficeAble{
    public void start();
}
让Word和EXCEL实现这个接口

class Word implements OfficeAble{
    public void start(){
        System.out.println("start Word");
    }
}
改进我们的OfficeBetter.java

class OfficeBetter{
    public static void main(String[] args){
        try{
            //动态加载类,在运行时
            Class c = Class.forName(args[0]);
            OfficeAble oa = (OfficeAble)c.newInstance();
            oa.start();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

此时如果我们需要Word功能就去实现Word功能,要实现ppt功能就去实现ppt,不需要再对上面的代码进行修改,也不需要重新编译。一般功能性的类使用动态加载,注意这种设计思想。

 

基本数据类型 void 关键字都存在类类型

public class ClassDemo2 {
	public static void main(String[] args) {
		Class class1 = int.class;//int的类类型
		Class class2 = String.class;//String 类的类类型
		Class class3 = double.class;
		Class class4 = Double.class;
		Class class5 = void.class;
		
		System.out.println(class1.getName());
		System.out.println(class2.getName());
		System.out.println(class2.getSimpleName());//不包含包名的类名称
		System.out.println(class5.getName());
	}
}


通过反射获取构造函数、成员变量、成员方法

public class ClassUtil {
	/**
	 * 打印类的成员方法
	 * 
	 * @param obj
	 */
	public static void printClassMethodMessage(Object obj) {
		// 要获取类的信息 首先需要获取类的类类型
		Class c = obj.getClass();// 传递的是那个子类对象,c就是该子类的类类型
		// 获取类的名称
		System.out.println("类的名称是:" + c.getName());
		/**
		 * Method 类,方法对象 一个成员方法就是一个Method对象
		 * getMethods()方法获取的是所有public的函数,包括父类继承而来
		 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
		 * 
		 */
		Method[] ms = c.getMethods();// c.getDeclaredMethods()
		for (int i = 0; i < ms.length; i++) {
			// 得到方法的返回值类型的类类型
			Class returnType = ms[i].getReturnType();
			System.out.print(returnType.getName() + " ");
			// 得到方法的名称
			System.out.print(ms[i].getName() + "(");
			// 获取参数类型--> 得到的是参数列表的类型的类类型
			Class[] paramTypes = ms[i].getParameterTypes();
			for (Class class1 : paramTypes) {
				System.out.print(class1.getName() + ",");
			}
			System.out.println(")");
		}
	}

	/**
	 * 获取打印类的成员变量的方法
	 * @param obj
	 */
	public static void printClassFieldMessage(Object obj) {
		Class c = obj.getClass();
		/**
		 * 成员变量也是对象 java.lang.reflect.Field Field 封装了关于成员变量的操作
		 * getFields()方法获取的是所有public的成员变量的信息
		 * getDeclaredFields获取的是该类自己的声明的成员变量的信息
		 */
		Field[] fs = c.getDeclaredFields();
		// Field[] fs = c.getFields();
		for (Field field : fs) {
			// 得到成员变量的类型的类类型
			Class fieldType = field.getType();
			// 类型名称
			String typeName = fieldType.getName();
			// 变量名称
			String fieldName = field.getName();
			System.out.println(typeName + " " + fieldName);
		}
	}
	
	/**
	 * 获取一个类的构造函数的信息
	 */
	public static void printConMessage(Object obj){
		Class c = obj.getClass();
		/**
		 * 构造函数也是对象
		 * java.lang.Constructor 中封装了构造函数的信息
		 * getConstructors 获取所有的public的构造函数
		 * getDeclaredConstructors得到所有的构造函数
		 */
		//Constructor[] cs = c.getDeclaredConstructors();
		Constructor[] cs = c.getDeclaredConstructors();
		for(Constructor constructor : cs){
			System.out.print(constructor.getName()+"(");
			//获取构造函数的参数列表--- 得到的是参数李彪的类类型
			Class[] paramTypes = constructor.getParameterTypes();
			for(Class class1: paramTypes){
				System.out.print(class1.getName()+",");
			}
			System.out.println(")");
		}
	}
}

方法的反射

1.      如何获取某个方法:方法的名称和方法的参数列表才能唯一决定某个方法。

2      方法反射的操作:method.invoke(对象,参数列表)

public class MethodDemo1 {
	public static void main(String[] args){
		/*要获取print(int ,int )方法 
		 * 1.要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型*/
		A a1 = new A();
		Class c = a1.getClass();
		/*
		 * 2.获取方法 名称和参数列表来决定
		 * getMethod 获取的是public的方法
		 * getDeclaredMethod 自己声明的方法
		 */
		try {
			//Method m = c.getMethod("print", new Class[]{int.class,int.class});
			Method m = c.getMethod("print", int.class,int.class);
			
			//方法的反射操作
			//a1.print(10, 20);
			/*
			 * 方法的反射操作是用m对象来调用,和a1.print的效果一样
			 */
			//方法如果没有返回值返回null,有返回值返回具体的返回值
			Object o = m.invoke(a1, new Object[]{10,20});
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
class A{
	public void print(int a,int b){
		System.out.println(a+b);
	}
	public void print(String a,String b){
		System.out.println(a.toUpperCase()+","+b.toLowerCase());
	}
}

通过Class Method 认识泛型的本质


/**
 * 
 * @author meng.li
 *说明什么是泛型,泛型什么时候有效
 */
public class MethodDemo2 {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		
		ArrayList list = new ArrayList();
		
		ArrayList<String> list1 = new ArrayList<String>();
		list1.add("hello");
		//list1.add(20);//错误的
		
		Class c1 = list.getClass();
		Class c2 = list1.getClass();
		System.out.println(c1 == c2);
		
		//反射的操作都是编译之后的操作
		/**
		 * c1 == c2 结果返回true说明编译之后集合的泛型是去泛型化的
		 * Java中集合的泛型,是防止错误输入的,只在编译阶段有效
		 * 绕过编译就无效了
		 * 验证:我们通过方法的反射来操作,绕过编译
		 */
		Method m = c2.getMethod("add",Object.class);
		m.invoke(list1, 20);//绕过编译操作就绕过了泛型
		System.out.println(list1.size());
		System.out.println(list1);
		/*
		for(String str : list1){
			System.out.println(str);
		}*///现在不能这样遍历,会报类型转换异常
	}
}










以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值