java中的反射与设计模式

目录

一、反射概述

1.创建类对象

2.常用方法:

二、反射应用

1.调属性

2.调方法

三、设计模式

四、工厂模式

五、单例模式

1.单例分类

2.懒汉隐患

六、枚举

七、注解

1.注解回顾

2.注解类



一、反射概述

概述:反射其实就是类对象,类加载的产物;将类加载到内存中,会产生类对象(class文件);有了类对象,即可得到所有类资源的信息: 类,方法,属性,构造器,包,父类,接口... 

 即通过反射得到类对象,通过类对象可以得到类的实例对象,属性对象,方法对象,在反射中 对类的资源的操作都通过资源的对象进行操作

为什么要用反射?

通过反射,可以在编译时不需要知道类的名字,从而在程序运行时根据需要动态的确定要使用的类,并且动态创建类的实例对象、操作属性对象(甚至是私有的)、方法对象,使得程序更加的灵活、维护性更强

1.创建类对象

创建类对象可以通过三种方式:

1. 类名.class

2. 对象.getClass()

3.Class.forName("全限定名")


无论哪种方式获取的类对象都是同一个类对象(因为类对象其实就是class对象,类在编译时只会生成一份解释文件 .class文件,所以通过这三种方法得到的都是同一个class对象(类对象))

演示:

//1.通过类名获取类对象
Class<?> c1 = Person.class;  //<?>:通配所有类型,用在接收数据据时

Class c2 = new Person().getClass();

Class c3 = Class.forName("com.qf.f_reflect.Person");

System.out.println(c1==c2); //true
System.out.println(c1==c3); //true

2.常用方法:

//反射的相关方法
Class c1 = Student.class;  //获取反射对象
System.out.println("获取类名:"+c1.getName());
System.out.println("获取包名:"+c1.getPackage());
System.out.println("获取父类:"+c1.getSuperclass());
System.out.println("获取接口:"+Arrays.toString(c1.getInterfaces()));

//getField或getFields获取公开的属性的
System.out.println("获取属性:"+Arrays.toString(c1.getFields()));
//System.out.println("获取指定属性:"+c1.getField("name"));

//获取非空开属性;甚至放开权限后,私有的也可以获取
System.out.println("获取属性2:"+Arrays.toString(c1.getDeclaredFields())); //常用

System.out.println("获取方法:"+Arrays.toString(c1.getMethods())); //常用
//参数1:方法名  参数2:多个参数
System.out.println("获取指定方法:"+c1.getMethod("hi",String.class,int.class));
System.out.println("获取构造器:"+Arrays.toString(c1.getConstructors()));
System.out.println("实例化对象:"+c1.newInstance()); //(常用)

二、反射应用

1.调属性

class Person{
	private String name;
	private int    age;
}
public class Test1 {
	public static void main(String[] args) throws Exception{
		//通过反射对象调属性:
		//1.获取类对象
		Class c1 = Person.class;
		//2.获取Field对象
		Field field = c1.getDeclaredField("name");
		//3.给定权限,即可调用私有属性
		field.setAccessible(true);
		//4.field调用set方法进行赋值
		Object o = c1.newInstance();
		field.set(o, "张三丰");
		
		//验证数据是否存进去:get
		System.out.println(field.get(o));
		//System.out.println(((Person)o).name);
	}
}

2.调方法

class Student {
	public void hello(String name,int age) {
		System.out.println("姓名:"+name+";年龄:"+age);
	}
	public void test() {
	}
}
public class Test2 {
	public static void main(String[] args) throws Exception {
		//类对象调方法:
		//1.获取类对象
		Class c1 = Student.class;
		//2.获取Method对象
		Method method = c1.getMethod("hello", String.class,int.class);
		//3.调用invoke方法
		method.invoke(c1.newInstance(), "zs",33);
	}
}

3.应用场景:

反射应用,往往可以灵活动态的调用属性,方法,构造方法

在程序中,使用了反射,可以使程序的维护性更强

field.set(t, name);  给实例对象t的属性filed 设置值为name 

//反射应用场景:灵活获取对象及属性资源
//案例:灵活动态地获取对象,例如:调指定方法返回Dog对象,或返回Cat
class Cat{
	String name;
	@Override
	public String toString() {
		return "Cat [name=" + name + "]";
	}
}
class Dog{
	String name;
	@Override
	public String toString() {
		return "Dog [name=" + name + "]";
	}
}
class Factory{
	public final static int F_DOG=1;
	public final static int F_CAT=2;
	
	public static Dog getDog() {
		return new Dog();
	}
	public static Cat getCat() {
		return new Cat();
	}
	public static Object getObject(int f) {
		if(f==F_DOG) { //违背ocp原则:对内修改的代码要持关闭状态
			return new Dog();
		}else if(f==F_CAT) {
			return new Cat();
		}else {
			return null;
		}
	}
	//泛型方法定义:<T>
	public static <T> T getObject(Class<T> c1,String name) throws Exception {
		Field field = c1.getDeclaredField("name");
		field.setAccessible(true);
		T t = c1.newInstance();
		field.set(t, name);
		return t;
	}
}
public class Test3 {
	public static void main(String[] args) throws Exception {
		//1.面向对象方式获取对象:
		//问题:如果获取30个不同对象,则需要30个方法; 冗余代码太多
		Dog dog = Factory.getDog();
		Cat cat = Factory.getCat();
		
		//2.传入标记获取对象(调一个方法)
		//问题:违背ocp原则;耦合性太强; 维护性太差
		Dog d = (Dog)Factory.getObject(Factory.F_DOG);
		Cat c = (Cat)Factory.getObject(Factory.F_CAT);
		
		//3.反射用法
		Dog dd = Factory.getObject(Dog.class,"旺财");
		Cat cc = Factory.getObject(Cat.class,"加菲猫");
		System.out.println(dd+"---"+cc);
	}
}

三、设计模式

概述:反复被使用的一套设计标准;也可以理解为特定问题的固定解决方案。

好处:可读性,复用性,维护性更强

分类:23种设计模式,总共分3类

对象型模式:针对对象的获取 例如:单例,工厂

结构型模式:针对对象的组织结构 例如:装饰者,代理

行为型模式:针对对象的行为跟踪 例如:观察者

四、工厂模式

概述:从工厂类中根据标记获取不同的对象

//动物的工厂类; 里面获取出不同的对象
class Factory{
	public static final int F_DOG=1;
	public static final int F_CAT=2;
	public static Object getObject(int f) {
		if(f==F_DOG) {  //违背ocp原则
			return new Dog();
		}else if(f==F_CAT) {
			return new Cat();
		}else {
			return null;
		}
	}
	//泛型方法:
	public static <T> T getObject(Class<T> c) throws Exception {
		return c.newInstance();
	}
}
class Dog{}
class Cat{}
public class Test1 {
	public static void main(String[] args) throws Exception {
		//1.基本工厂设计模式:
		//a.静态工厂: 调静态方法(常用)
		//b.实例工厂: 实例化工厂对象调成员方法
		Dog dog = (Dog) Factory.getObject(Factory.F_DOG);
		
		//2.工厂+反射+配置文件
		//“约定大于配置(约定规则取代配置-框架常用);配置大于编码(硬编码->软编码)”
		Properties p = new Properties();
		p.load(new FileInputStream("factory.properties"));
		String path = p.getProperty("1"); //key已知;value变为的
		System.out.println(Factory.getObject(Class.forName(path)));
	}
}

五、单例模式

概述:每次获取到的对象都是同一个对象

单例设计:

1.类名调用静态方法; 2.返回静态属性 3.构造方法私有化

好处:节省内存资源

1.单例分类

/单例设计的分类: 饿汉式,懒汉式
class MySingle{
	//private static final MySingle single = new MySingle();  //饿汉式(常用)
	private static MySingle single;   //懒汉式:调用方法时才去new对象
	
	private MySingle() {}
	
	public static MySingle getInstance() {
		if(single==null) {
			single = new MySingle();
		}
		return single;
	}
}
public class Test1 {
	public static void main(String[] args) {
		//单例:
		MySingle my = MySingle.getInstance();
		MySingle my2 = MySingle.getInstance();
		System.out.println(my==my2);  //true
	}
}

2.懒汉隐患

如果多个线程去通过懒汉模式创建单例对象,那么多个线程可能执行到 判断对象为空,但是还没执行创建对象的操作,那么这个时候可能就存在多个线程创建对象,这样就不能确保每次获取的都是同一个对象

如何解决懒汉隐患:当对象为空的时候,加锁,然后继续判断对象是否为空,为空则创建对象

为什么外层还需要判断线程是否为空,因为不加判断,每个线程都会等待锁资源的释放,加了后只有在对象没有被创建、为空的时候,线程才会等待锁资源的释放,尝试去创建对象,当对象不为空直接将这个对象返回,通过外层的判断使得不需要所有的线程都需要等待,提高了性能

代码案例:

class MySin{
	private static MySin sin; 
	private MySin() {}
	
	public static MySin getInstance() {
		//隐患问题:共享数据sin,有复合操作---安全隐患
		if(sin==null) { //完整的线程安全处理--性能高
			synchronized("lock") {
				if(sin==null) {
					System.out.println("------");
					sin = new MySin();
				}
			}
		}
		return sin;
	}
} 
public class Test2 {
	public static void main(String[] args) {
		for(int i=1;i<=10;i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					MySin.getInstance();
				}
			}).start();
		}
	}
}

六、枚举

概述:枚举和静态常量类似,都是作为状态值来使用;

当状态值设置的比较少,可以选择静态常量;状态值设置的较多,则选择枚举(写法上更;简洁)

枚举的定义: 创建枚举类后,里面可以生成很多枚举值;这些枚举值的维护性较好

案例:

//枚举的本质:继承Enum的最终类   枚举值则是封装后的静态常量
enum MyEnum{  //创建枚举类
	M_DOG,M_CAT
}
class Factory{
	//public static final int F_DOG=1;  //静态常量
	//public static final int F_CAT=2;
	public static Object getObject(MyEnum f) {
		if(f==MyEnum.M_DOG) {  //违背ocp原则
			return new Dog();
		}else if(f==MyEnum.M_CAT) {
			return new Cat();
		}else {
			return null;
		}
	}
}
class Dog{}
class Cat{}
public class Test1 {
	public static void main(String[] args) throws Exception {
		//1.基本工厂设计模式:
		Dog dog = (Dog) Factory.getObject(MyEnum.M_DOG);
	}
}

七、注解

概述:注解可以参与程序代码中的执行;往往在框架中可以取代相关配置信息

回顾使用过的注解:@Test(单元测试-功能型注解) @Override(重写注解-检测型注解)

@interface注解类: 定义当前类中只能使用属性

1.注解回顾

//回顾注解的用法:
class Animal{
	public void bark() {}
}
@Deprecated //定义该类为过时的类
class Dog extends Animal{
	
	@Deprecated //定义该方法是过时的方法
	@Override  //检测型注解-检测是否为重写方法
	public void bark() {}
}
public class Test1 {
	public static void main(String[] args) {
	}
	@Test //JVM会生成Test1类的对象调成员方法
	public void show() {
		System.out.println("xxxx");
	}
}

2.注解类

enum MyEnum{
	A,B
}
@interface MyAnno{}
//@interface注解类:定义当前类中只能使用属性
@interface MyAnnotation{
	int age() default 66;    //定义int类型属性
	String name();           //定义String类型
	Class  c1();             //类对象类型
	MyEnum enum1() default MyEnum.A;  //枚举类型
	MyAnno anno();
}
public class Test2 {
	public static void main(String[] args) {
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值