反射与设计模式
一、反射应用
调属性
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);
}
}
调方法
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);
}
}
应用场景
反射应用,往往可以灵活动态的调用属性,方法,构造方法
在程序中,使用了反射,可以使程序的维护性更强
//反射应用场景:灵活获取对象及属性资源
//案例:灵活动态地获取对象,例如:调指定方法返回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.构造方法私有化
好处:节省内存资源
单例分类
//单例设计的分类: 饿汉式,懒汉式
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
}
}
懒汉隐患
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注解类: 定义当前类中只能使用属性
注解回顾
//回顾注解的用法:
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");
}
}
注解类
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) {
}
}
七、Lambda
概述:Lambda是jdk8提供的新特性;就是匿名内部类的简写;能用匿名内部类,则可使用lambda表达式
匿名内部类往往常用于接口实现多态的方式中,所以lambda表达式语法也类似,需要有接口引用
语法:
接口引用 = (重写方法参数)->{重写方法体}
应用
//案例:
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
};
Thread th = new Thread(run);
th.start();
//lambda表达式
Runnable run2 = ()->System.out.println("lambda表达式");
Thread th2 = new Thread(run2);
th2.start();
函数式接口
函数式接口也是lambda表达式的应用场景,只不过接口有特殊定义:接口中的抽象方法只有一个
//函数式接口的应用:
//案例:飞天娃具有飞天的能力
@FunctionalInterface //函数式接口的注解
interface Flyable{
void fly(); //函数式接口只能有一个抽象方法
}
public class Test2 {
public static void main(String[] args) {
new Flyable() {
@Override
public void fly() {
System.out.println("匿名的飞天能力");
}
}.fly();
//lambda表达式
Flyable ff = ()->System.out.println("lambda的飞天能力");
ff.fly();
//lambda细节:
//1.根据接口引用可以自动识别lambda表达式结构及调用重写方法
//2.重写方法体中如果只有一句,则可省略{}以及省略return
//3.如果只有一个参数,则可省略()
//4.lambda不能生成独立的内部类文件
}
}
系统提供的函数式接口
//函数式接口主要有4个:消费型接口,供给型,函数型,断言型
//消费型接口:有参数无返回值方法
//供给型接口:无参数有返回值方法
//函数型接口:有参数有返回值方法-参数和返回值只要是引用类型即可
//断言型接口:有参数有返回值方法-返回类型为boolean类型
//消费型接口:Consumer
Consumer<Integer> con = s->System.out.println("消费了--"+s);
con.accept(666);
//供给型接口:Supplier
Supplier<Integer> sup = ()->new Random().nextInt(6);
System.out.println(sup.get());
八、总结与作业
总结
作业
1. 自定义Person类,并给定一个带参构造, 当Person类的反射对象调用newInstance时会报错,写个例子演示,并说明为什么?
2. 有一个电脑类和手机类都有一个brand属性,在工厂类的静态方法中,传入反射对象及属性值,灵活获取到对应的实体对象,返回的对象中包含属性值
3、配置文件中user.properties中有一组键值对为: key=xx.xx.xx.Person
请加载配置文件后,根据key获取出value,并通过反射机制获取对应的实体对象
晨考
请写出单例的懒汉式和饿汉式代码,并注释标明:
class L{
private static final L e = new L();//饿汉
private static L l;//懒汉
private L(){}
public static L getInstance{
if(l == null){
l = new L();
}else{
return l;
}
}
}