java反射基础

反射定义

反射:(运行时发现和使用类的信息)指的是对象的反向处理。根据对象倒推类的组成。(比如根据汽车倒退他的设计图纸,通过,可以拿到零件,并更换零件)

反射的核心类class类(专门描述其他类的组成)

Object类中的取得对象的Class对象

public final native Class<?> getClass();

class类描述接口与类的组成,Class对象由JVM在第一次加载类时产生,并且全局唯一。

1.三种取得任意类Class对象的方法
  • I.调用对象.getClass()取得Class对象

  • II. 类名称.class取得Class对象

  • III.Class.forName(类全称)

1.1 public T newInstance():通过反射实例化类对象

synchronized(Test.class){
//全局锁
//通过类.class (全局唯一)
}

    Class<Date> cls = Data.class;
    Date date = cls.newInstance();通过反射实例化对象
1.2 反射与工厂方法模式

反射与工场方法模式

工厂方法模式:
一个接口, 多个实现子类 , 一个工厂,
通过客户端传入的name来判断要生产神魔,当添加子类时,
在工厂中需要添加新增的类的判断,(这正是他的弊端)

使用反射的工场方法模式: 当有 新的子类产生时,不用修改工场

通过想工厂中传入 类名.class Class对象 ,就可以不论是那个类,都可以通过反射产生新对象

interface Computer{
		void buy();
}
class DellComputer implements Computer{

		@Override
		public void buy() {
				System.out.println("买一个戴尔笔记本");
		}
}
class HUAWEIComputer implements Computer{

		@Override
		public void buy() {
				System.out.println("买个华为笔记本");
		}
}

class LenovoComputer implements Computer{

		@Override
		public void buy() {
				System.out.println("买一个联想笔记本呢");
		}
}

class ComputerFactory{
		public Computer buyComputer(Class<?> cls) throws IllegalAccessException, InstantiationException {
				return (Computer) cls.newInstance();
		}
}
public class FactoryMethod2 {
		public static void main(String[] args) throws InstantiationException, IllegalAccessException {
				ComputerFactory computerFactory = new ComputerFactory();
				Computer computer = computerFactory.buyComputer(HUAWEIComputer.class);
				computer.buy();
		}
}
2.反射与类操作
2.1取得父类&父接口信息
  • I.取得包信息- Package(描述包信息的类)

    public Package getPackage();

  • II.取得父类的Class对象

     getSuperClass()    Class<? super T>
    
  • III.取得实现的父接口Class对象

    getInterfaces()  : Class<?>[]  
    
2.2反射与构造方法 - Constructor(描述类的构造方法信息)
  • I.取得本类中指定参数的构造方法

    getConstructor(类<?>... parameterTypes)
    返回一个 Constructor对象,权限为public。
    
    
     getDeclaredConstructor(类<?>... parameterTypes) 
     返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 类函数
    
  • II.取得本类中所有构造方法

      getConstructors() 
      返回包含一个数组 Constructor对象,取得权限为public的
      
    getDeclaredConstructors() 
      返回一个反映 Constructor对象,取得所有的构造方法
    

Class类的newInstance()实际上调用的是类中的无参构造,如果类中没有无参构造或者权限为private,此方法无法使用!!!!

2.3 Constructor类中的方法(调用有参构造的.class)
public T newInstructce(Object ... initargs);
若类中没有无参构造,则只能使用Constructor类提供的newInStance方法使用有参构造
2.4 普通方法
2.4.1 取得指定名称的方法
	getMethod(String name, 类<?>... parameterTypes) 
	返回一个 方法对象,权限为public修饰。
	getDeclaredMethod(String name, 类<?>... parameterTypes) 
	返回一个 方法对象,所有方法,不考虑修饰符。  
2.4.2 取得所有方法
 1. public Method[] getMethods() throws SecurityException :
 取得本类以及父类所有权限为public的普通方法(public,包含静态方法)
 2. public Method[] getDeclaredMethods() throws SecurutyException
 只能取得本类中的的所有方法(包含private)
2.4.3 Method类 - 提供的方法(重要)

反射调用普通方法

obj:类的实例化对象
args:普通方法参数

通过对象调用:参数不同则方法的执行结果不同,所以要找到对象

public Object invoke(Object obj,Object …args);

2.5 普通属性
2.5.1 取得类中指定名称的属性
public Field getField(String name)

public Field getDeclaredField(String name)
2.5.2 取得类中所有属性
找本类与父类中所有public权限的属性:public Field[] getFields() throws SecurityException 
只找本类中的所有属性:public Field[] getDeclaredFields() throws SecurityException 
2.5.3 Filed类 - 提供的设置和取得值(重要)

obj:obj的实例化对象

value:要设置的值

   public void set(Object obj,Object vlaue);

    //取得属性值
    public Object get(Object obj){
        
    }
    //取得属性类型
    public Class<?> getType();

代码:

interface  IA{}
interface  IB{}
class  SuperC{}
class SubD extends  SuperC implements IA,IB {
		private String name;
		public int age;
		public  SubD(){

		}
		public SubD(String name){
				this.name = name;
		}

		public String getName() {
				return name;
		}

		public void setName(String name) {
				this.name = name;
		}

		public int getAge() {
				return age;
		}

		public void setAge(int age) {
				this.age = age;
		}
}

/**
 * Class类中的方法
 *
 */
public class Reflex_Parents {
		public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
				//1. 基本方法
				Class<SubD> cls = SubD.class;
				System.out.println("getPackage = "+cls.getPackage());//获取包名
				System.out.println("getSuperclass ="+cls.getSuperclass());//父类全名称
				System.out.println("getInterfaces = "+cls.getInterfaces());//接口数组

				Class<SubD>[] clsInterfaces= (Class<SubD>[]) cls.getInterfaces();
				for(Class<SubD> d: clsInterfaces){
						System.out.println(d);
				}

				System.out.println("getTypeName = "+cls.getTypeName());//本类包名
				//2. 构造方法
				//调用无参构造
				Class<SubD> cls2 = SubD.class;
	   			cls.newInstance();  //默认调用无参构造 -> 所以无参构造不能是private修饰
				//调用有参构造
				Constructor<SubD> constructor = cls.getConstructor(String.class);//指定参数类型
				SubD subD=  constructor.newInstance("zhanga");

				//3. 重点):反射调用普通方法;
				//通过cls.getMethod(方法名称,参数类型.class)方法获取到方法的对象

				/*
				1. public Method[] getMethods() throws SecurityException :4
				取得本类以及父类所有权限为public的普通方法(public,包含静态方法)
				2. public Method[] getDeclaredMethods() throws SecurutyException
				只能取得本类中的的所有方法(包含private)
				 */
				Class<SubD> cls3 = SubD.class;
				Method setName = cls.getMethod("setName",String.class);
				Method getName = cls.getMethod("getName");
				SubD ret = cls.newInstance();
				setName.invoke(ret,"zhang");
				System.out.println(getName.invoke(ret));

				//4.调用类中的属性
				/*
				2.4.1 取得类中指定名称的属性
							public Field getField(String name)
							public Field getDeclaredField(String name)
				2.4.2 取得类中所有属性
							找本类与父类中所有public权限的属性:public Field[] getFields() throws SecurityException
							只找本类中的所有属性:public Field[] getDeclaredFields() throws SecurityException
				 */
				Class<SubD> cls4 = SubD.class;
                SubD subD1= cls.newInstance();
				 Field field = cls.getDeclaredField("name");
				 field.setAccessible(true);
				 field.set(subD1,"zhag");
				System.out.println(field.get(subD1));
                // 5.破坏封装
				/*
					Field field = cls.getDeclaredField("name");
					field.setAccessible(true);
				 */
				Class<SubD> cls5 = SubD.class;
				SubD subD5= cls.newInstance();
				Field field5 = cls.getDeclaredField("name");
				field.setAccessible(true);
				field.set(subD5,"zhag");
				System.out.println(field.get(subD5));
		}
}

动态破坏封装(反射特性) - 在一次JVM进程中

Constructor,Method,Field类都继承AccessibleObject类,
此类中有一个破坏封装的方法

public class BrackPackage {
		public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
				Class<Child> cls = Child.class;
				//1.创建一个Field对象
				Field field = cls.getDeclaredField("age");
				Child ch = cls.newInstance();
				//调用属性的setAccessible方法
				field.setAccessible(true);
				field.set(ch,20);
				System.out.println(field.get(ch));
		}
}

public void setAccessible(bollean flag);

(重点)反射与单极VO操作

输入字符串“属性名称:属性值|属性名称:属性值|属性名称:属性值”

BeanOpenation类

public class BeanOpenation {
		public static void setBeanValue(Object actionObj,String msg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
				String[]  ret = msg.split("\\|");
				//emp.name:zhang            emp.job:programmer
				for(int i = 0; i< ret.length; i++){
						String[] temp = ret[i].split(":");
						//emp.name              zhang
						String attritube = temp[0];
						String value = temp[1];//值
						String[] filed = attritube.split("\\.");//属性类名.属性名
						//获取当前对象emp          name
						Object curObj = getObject(actionObj,filed[0]);
						//name
						setObject(curObj,filed[1],value);
				}
		}
		private static void setObject(Object curObj, String s, String value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
				//返回的是一个emp对象,要调用Emp类中的"set"+"Name/Job"方法设置值
				//首先还是要判断属性存不存在
				Field field = curObj.getClass().getDeclaredField(s);
				if(field == null){
						field = curObj.getClass().getField(s);
				}
				if(field == null){
						return ;
				}
				//获取到当前类中的方法,并调用该方法设置值
				String methodName = "set"+initCap(s);//setName
				Method method = curObj.getClass().getDeclaredMethod(methodName,field.getType());
				method.invoke(curObj,value);
		}
		public static String initCap(String s){
				return s.substring(0,1).toUpperCase()+s.substring(1);
		}
		private static Object getObject(Object actionObj, String s) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
				//emp
				String ret = "get"+initCap(s);//getEmp
				//判断是否由emp属性
				Field field = actionObj.getClass().getDeclaredField(s);
				if(field == null){
						//从父类中获取这个属性
						field = actionObj.getClass().getField(s);
				}
				if(field ==null){
						return null;
				}
				//使用getEmp方法对象
				Method method = actionObj.getClass().getDeclaredMethod(ret);
				return method.invoke(actionObj);//当前的对象调用getEmp返回一个emp对象
		}
}

EmpAction类

public class EmpAction {
		private Emp emp = new Emp();
		public void setValue(String value) throws InvocationTargetException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
				BeanOpenation.setBeanValue(this,value);
		}
		public Emp getEmp(){
				return emp;
		}
}

Emp类

public class Emp {
		private String name;
		private String  job;

		public Emp(){

		}
		public Emp(String name) {
				this.name = name;
		}

		public String getName() {
				return name;
		}

		public void setName(String name) {
				this.name = name;
		}

		public String getJob() {
				return job;
		}

		public void setJob(String job) {
				this.job = job;
		}

		@Override
		public String toString() {
				return "Emp ="+"{ name:  "+this.name+ "     "+"job:  "+this.job+"  }";
		}
}

反射与简单java类

3.ClassLoader类加载器

3.1定义:

类加载定义:通过一个类的全名称来获取此类的二进制字节流

类加载器: 实现类加载功能的代码模块;

3.2JDK内置的三大类加载器
3.2.1:BootStrap(启动类加载器)

I.独立于JVM外部,并且无法被Java程序直接引用。

II.负责将存放于JAVA_HOME/lib目录下的能被识别的所有类库加载到JVM中

能被JVM识别的所有的类库(例如rt.jar - java基础类库)加载到JVM中。

jar文件 = 压缩文件 - 存放编译好的若干个class文件

3.2.2ExtClassLoader(扩展类加载器)

I.使用java语言实现,可以被java程序直接引用的

II.负责将存于JAVA_HOME\lib\ext(Xml文件解析类,页面框架类)

目录下的所有能被JVM识别的类库。

3.2.3 AppClassLoader(应用程序加载器)

I.使用JAVA程序实现,如果用户没有自定义类加载器

II.负责加载用户classPath指定的类库

3.3(重点)类加载器的双亲委派模型(定义,工作流程,存在意义)
定义:四种类加载器的层次关系
工作流程:

如果一个类加载器收到一个类加载请求,首先自己不会加载此类,而是将类加载请求委托给父类加载器完成,每层的类加载器都是如此,只用当夫类加载器无法加载此类时,子加载器才会尝试自己去加载。

存在意义:

双亲委派模型对于保证JAVA程序的稳定运行十分重要。

例如:java.lang.Object,存放在rt.jar中,由于双亲委派模型的存在,无论哪一类累加载器要加载此类,最终都是委派给处于顶端的启动类加载器进行加载,因此,Object类在程序的各种类加载器环境中都是一个类

比较两个类是否是相等的前提条件:这两个类是由同一个类加载器加载的,
否则即使两个类来源与同一个Class文件,被同一个JVM加载,
只要加载这两个类的类加载器不同,这两个类的注定不相等。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值