反射

一.类对象

类的对象:基于某个类 new 出来的对象,也称为实例对象。

类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法) 。

二.获取类对象的方法

1.通过类的对象,获取类对象。

  • Student s = new Student();
  • Class c = s.getClass();

2.通过类名获取。

  • Class c = 类名.class;

3.通过静态方法获取类对象。

  • Class c=Class.forName(“包名.类名”);

三、反射通用操作*

1 常见方法

方法名 描述
public String getName() 获取类的完全名称
public Package getPackage() 获取包信息
public Class getSuperclass() 获取父类
public Class[] getInterfaces() 获取实现父接口
public Field[] getFields() 获取字段信息
public Method[] getMethods() 获取方法信息
public Constructor[] getConstructors() 获取构造方法
public T newInstance() 反射创建对象

 

 

 

 

 

 

 

 

 

//1 使用反射获取类的名字、包名、父类、接口
	public static void reflectOpe1() throws Exception {
		//(1)获取类对象 Person
		Class class1=Class.forName("com.qf.chap17_1.Person");
		//getName();
		System.out.println(class1.getName());
		//getPackage();
		System.out.println(class1.getPackage().getName());
		//getSuperClass();
		System.out.println(class1.getSuperclass().getName());
		//getInterfaces();
		Class[] classes=class1.getInterfaces();
		System.out.println(Arrays.toString(classes));
		
		System.out.println(class1.getSimpleName());
		System.out.println(class1.getTypeName());
//2使用反射获取类的构造方法,创建对象
	public static void reflectOpe2() throws Exception{
		//(1)获取类的类对象
		Class class1=Class.forName("com.qf.chap17_1.Person");
		//(2)获取类的构造方法 Constructor
		Constructor[] cons=class1.getConstructors();
		for (Constructor con : cons) {
			System.out.println(con.toString());
		}
		//(3)获取类中无参构造
		Constructor con=class1.getConstructor();
		Person zhangsan=(Person)con.newInstance();
		Person lisi=(Person)con.newInstance();
		System.out.println(zhangsan.toString());
		System.out.println(lisi.toString());
		//简便方法:类对象.newInstance();
		Person wangwu=(Person)class1.newInstance();
		System.out.println(wangwu.toString());
		//(4)获取类中带参构造方法
		Constructor con2=class1.getConstructor(String.class,int.class);
		Person xiaoli=(Person)con2.newInstance("晓丽",20);
		System.out.println(xiaoli.toString());
		
	}
//3使用反射获取类中的方法,并调用方法
	public static void reflectOpe3() throws Exception{
		//(1)获取类对象
		Class class1=Class.forName("com.qf.chap17_1.Person");
		//(2)获取方法  Method对象
		//2.1getMethods() 获取公开的方法,包括从父类继承的方法
		//Method[] methods=class1.getMethods();
		//2.2getDeclaredMethods() 获取类中的所有方法,包括私有、默认、保护的 、不包含继承的方法
		Method[] methods=class1.getDeclaredMethods();
		for (Method method : methods) {
			System.out.println(method.toString());
		}
		//(3)获取单个方法
		//3.1eat
		Method eatMethod=class1.getMethod("eat");
		//调用方法
		//正常调用方法  Person zhangsan=new Person();  zhangsan.eat();
		Person zhangsan=(Person)class1.newInstance();
		eatMethod.invoke(zhangsan);//zhangsan.eat();
		System.out.println("------------------");
		//3.2toString
		Method toStringMethod=class1.getMethod("toString");
		Object result=toStringMethod.invoke(zhangsan);
		System.out.println(result);
		System.out.println("-------------------");
		//3.3带参的eat 
		Method eatMethod2=class1.getMethod("eat", String.class);
		eatMethod2.invoke(zhangsan, "鸡腿");
		
		//3.4获取私有方法
		Method privateMethod=class1.getDeclaredMethod("privateMethod");
		//设置访问权限无效
		privateMethod.setAccessible(true);
		privateMethod.invoke(zhangsan);
		
		//3.4获取静态方法
		Method staticMethod=class1.getMethod("staticMethod");
		//正常调用 Person.staticMethod
		staticMethod.invoke(null);
		
	}
//4使用反射实现一个可以调用任何对象方法的通用方法
	public static Object invokeAny(Object obj,String methodName,Class[] types,Object...args) throws Exception {
		//1获取类对象
		Class class1=obj.getClass();
		//2获取方法
		Method method=class1.getMethod(methodName, types);
		//3调用
		return method.invoke(obj, args);
	}
	
	//5使用反射获取类中的属性
	public static void reflectOpe4() throws Exception{
		//(1)获取类对象
		Class class1=Class.forName("com.qf.chap17_1.Person");
		//(2)获取属性(字段) 公开的字段,父类继承的字段
		//Field[] fields=class1.getFields(); 
		//getDeclaredFields()获取所有的属性,包括私有,默认 ,包含,
		Field[] fields=class1.getDeclaredFields();
		System.out.println(fields.length);
		for (Field field : fields) {
			System.out.println(field.toString());
		}
		//(3)获取name属性
		Field namefield=class1.getDeclaredField("name");
		namefield.setAccessible(true);
		//(4)赋值  正常调用  Person zhangsan=new Person(); zhangsan.name="张三";
		Person zhangsan=(Person)class1.newInstance();
		namefield.set(zhangsan, "张三"); //zhangsan.name="张三";
		//(5) 获取值
		System.out.println(namefield.get(zhangsan));// zhangsan.name
	}
}

 

四.设计模式*

1.概念

  • 一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

  • 可以简单理解为特定问题的固定解决方法。

2.好处

使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、重用性。

3.工厂设计模式

开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭。

工厂模式主要负责对象创建的问题。

可通过反射进行工厂模式的设计,完成动态的对象创建。

 

4.单例模式

单例(Singleton):只允许创建一个该类的对象。

方式一:饿汉式(类加载时创建,天生线程安全)。

public class SingleTon {
	private static final SingleTon instance=new SingleTon();
	private SingleTon() {}
	public static SingleTon getInstance() {
		return instance;
	}
}

方式二:懒汉式1(使用时创建,线程不安全,加同步)。

public class SingleTon2 {
	// 创建对象
	private static SingleTon2 instance = null;

	// 私有化构造方法
	private SingleTon2() {
	}

	// 静态方法
	public static  SingleTon2 getInstance() {
		if(instance==null) {//提高执行效率
			synchronized (SingleTon2.class) {
				if (instance == null) {
					instance = new SingleTon2();
				}
			}
		}
		return instance;
	}
}

方式三:懒汉式2(静态内部类写法)

public class SingleTon3 {
	private SingleTon3() {}
	
	private static class Holder{
		static SingleTon3 instance=new SingleTon3();
	}
	
	public static SingleTon3 getInstance() {
		return Holder.instance;
	}
}

五.枚举

枚举是一个引用类型,枚举是一个规定了取值范围的数据类型。

  • 枚举变量不能使用其他的数据,只能使用枚举中常量赋值,提高程序安全性。

  • 定义枚举使用enum关键字。

  • 枚举的本质:

    • 枚举是一个终止类,并继承Enum抽象类。

    • 枚举中常量是当前类型的静态常量。

注意:

  • 枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法。

  • 枚举常量必须在前面,多个常量之间使用逗号隔开,最后分java号可写可不写。

六.注解

1.概念

注解(Annotation):是代码里的特殊标记, 程序可以读取注解,一般用于替代配置文件。

开发人员可以通过注解告诉类如何运行。

  • 在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

2.定义注解

定义注解使用@interface关键字,注解中只能包含属性。

常见注解:@Override、@Deprecated

案例:

public @interface MyAnnotation {
	//属性(类似方法)
	String name() default "张三";
	int age() default 20;
	
}

3.注解类型

  • String类型
  • 基本数据类型
  • Class类型
  • 枚举类型
  • 注解类型
  • 以上类型的一维数组

4.元注解

元注解:用来描述注解的注解。

@Retention:用于指定注解可以保留的域。

  • RetentionPolicy.CLASS: 注解记录在class文件中,运行Java程序时, JVM不会保留,此为默认值。

  • RetentionPolicy.RUNTIME: 注解记录在 class文件中,运行Java程序时,JVM会保留,程序可以通过反射获取该注释

  • RetentionPolicy.SOURCE: 编译时直接丢弃这种策略的注释。

@Target:

  • 指定注解用于修饰类的哪个成员。

你可能感兴趣的:(JAVASE,java,设计模式,反射)