目录
1.构建反射目标类 ReflectTarget 【在原先的基础上添加了一些成员变量】
1.尝试引入简单工厂模式
简单工厂并不是一种设计模式,更多算是一种编程习惯,
定义:定义一个工厂类,根据传入的参数的值不同返回不同的实例。
特点:被创建的实例具有共同的父类或接口。
1.共同接口 Mouse :
public interface Mouse {
void sayHi();
}
2. 两个实现类:
DellMouse 类:
public class DellMouse implements Mouse {
@Override
public void sayHi() {
System.out.println("我是戴尔鼠标");
}
}
HpMouse类:
public class HpMouse implements Mouse {
@Override
public void sayHi() {
System.out.println("我是惠普鼠标");
}
}
3. 简单工厂类:
public class MouseFactory {
public static Mouse createMouse(int type){
switch (type){
case 0 :return new DellMouse();
case 1: return new HpMouse();
default: return new DellMouse();
}
}
public static void main(String[] args) {
Mouse mouse=MouseFactory.createMouse(1);
mouse.sayHi();
}
}
使用场景: 1. 需要创建的对象较少。 2. 客户不关心对象创建的具体细节。
2.尝试引入工厂方法模式:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。
1. 定义一个 MouseFactory 接口:
public interface MouseFactory {
Mouse createMouse();
}
2. 每一个特定的鼠标类对应一个创建工厂:
DellMouseFactory 工厂类
public class DellMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
}
HpMouseFactory 工厂类
public class HpMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
}
3. 创建shilling:
public class FactoryMouseDemo {
public static void main(String[] args) {
MouseFactory mouseFactory =new HpMouseFactory();
Mouse mouse =mouseFactory.createMouse();
mouse.sayHi();
}
}
1. 工厂方法模式优点:1.符合开闭原则,
2.单一职责原则,
3. 对客户隐藏对象的创建具体细节。
2. 当需要新增一个 联想鼠标类时:
1. 对于简单工厂来说 需要修改 MouseFactory 类中的代码,违反了开闭原则。
2. 对于工厂方法模式来说:只需要新增一个LenovoMouseFactory 类,不需要改变现有的代码
3.
由于没有像简单工厂模式一样使用静态的 工厂方法,工厂方法模式可以形成继承的等级结构,扩展出子工厂的子类。
比如:IBM 被 联想收购
联想鼠标:
public class LenovoMouse implements Mouse {
@Override
public void sayHi() {
System.out.println("我是联想鼠标");
}
}
联想工厂:
public class LenovoMouseFactory implements MouseFactory {
@Override
public Mouse createMouse() {
return new LenovoMouse();
}
}
IBM鼠标:
public class IBMMouse implements Mouse {
@Override
public void sayHi() {
System.out.println("我是联想旗下的IBM鼠标");
}
}
IBM鼠标工厂:
public class IBMMouseFactory extends LenovoMouseFactory {
@Override
public Mouse createMouse(){
return new IBMMouse();
}
}
工厂方法模式 是简单工厂模式 进一步的抽象和扩展,在保留简单工厂封装优点的同时,让扩展变得简单,让继承变得可行,
增加了多态的体现。
但是工厂方法模式 也有 两个严重缺点:
添加新产品类时,也要添加与之对应的工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度。
只支持同一类产品的创建,随着业务的增长,不可能只有鼠标,还可能有键盘,电脑等等。
总结:后续不利于扩展。
3.尝试引入抽象工厂模式:
提供一个 创建一系类 相关或相互依赖对象的接口
1. 键盘 接口:
public interface Keyboard {
void sayhello();
}
戴尔键盘:
public class DellKeyboard implements Keyboard{
@Override
public void sayhello() {
System.out.println("我是戴尔键盘");
}
}
惠普键盘:
public class HpKeyboard implements Keyboard {
@Override
public void sayhello() {
System.out.println("我是惠普键盘");
}
}
2. 电脑工厂 接口:
public interface ComputerFactory {
Mouse createMouse();
Keyboard createKeyboard();
}
惠普的:
public class HpComputerFactory implements ComputerFactory {
@Override
public Mouse createMouse() {
return new HpMouse();
}
@Override
public Keyboard createKeyboard() {
return new HpKeyboard();
}
}
戴尔的:
public class DellComputerFactory implements ComputerFactory {
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public Keyboard createKeyboard() {
return new DellKeyboard();
}
}
3. 实现:
public class AbstractFactoryDemo {
public static void main(String[] args) {
ComputerFactory cf =new HpComputerFactory();
Mouse mouse=cf.createMouse();
Keyboard keyboard=cf.createKeyboard();
mouse.sayHi();
keyboard.sayhello();
}
}
抽象工厂模式 是工厂方法模式 的升级版本,解决了工厂模式只能 生产一种产品的弊端。
抽象工厂模式的缺点:
添加新产品时依旧违背开闭原则,比如惠普新增耳机,依旧要在ComputerFactory 接口进行修改,并且也要在 HpComputerFactory 类中修改。
4.反射:
反射的主要用法
1.获取构造方法并使用【公有,私有】
/*
* 通过Class对象可以获取某个类中的:构造方法;
*
* 获取构造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
* 2).获取单个的方法,并调用:
* public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
*
* 调用构造方法:
* Constructor-->newInstance(Object... initargs)
*/
1.构建反射目标类 ReflectTarget: 共有6中构造方法
public class ReflectTarget {
//---------构造函数-----------
//(默认的带参数构造函数)
ReflectTarget(String str) {
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造函数
public ReflectTarget() {
System.out.println("调用了公有的无参构造方法 。。。");
}
//有一个参数的构造函数
public ReflectTarget(char name) {
System.out.println("调用了带有一个参数的构造方法,参数值为 " + name);
}
//有多个参数的构造函数
public ReflectTarget(String name, int index) {
System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + " 【序号】" + index);
}
//受保护的构造函数
protected ReflectTarget(boolean n){
System.out.println("受保护的构造方法 n :" + n);
}
//私有的构造函数
private ReflectTarget(int index){
System.out.println("私有的构造方法 序号:" + index);
}
}
2. 获取构造方法:
public class ConstructorCollector {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class clazz = Class.forName("demo.reflect.ReflectTarget");
//1.获取所有的公有构造方法
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
//2.获取所有构造方法
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
//3.获取单个带参数的公有方法
System.out.println("*****************获取公有、有两个参数的构造方法*******************************");
Constructor con = clazz.getConstructor(String.class, int.class);
System.out.println("con = " + con);
//4.获取单个私有的构造方法
System.out.println("******************获取私有构造方法*******************************");
con = clazz.getDeclaredConstructor(int.class);
System.out.println("private con = " + con);
System.out.println("******************调用私有构造方法创建实例*******************************");
}
}
3.创建实例:
调用私有的构造:
//4.获取单个私有的构造方法
System.out.println("******************获取私有构造方法****************************");
Constructor con = clazz.getDeclaredConstructor(int.class);
System.out.println("private con = " + con);
System.out.println("******************调用私有构造方法创建实例*****************");
//暴力访问(忽略掉访问修饰符,如果没有,则不能访问)
con.setAccessible(true);
ReflectTarget reflectTarget = (ReflectTarget) con.newInstance(1);
调用公有的构造方法:
//5.获取单个公有的构造方法
System.out.println("******************获取私有构造方法*******************************");
con = clazz.getConstructor(String.class, int.class);
System.out.println("public con = " + con);
System.out.println("******************调用公有构造方法创建实例*******************************");
ReflectTarget rt = (ReflectTarget) con.newInstance("公有的拉拉",1);
2.获取类的成员变量并使用:
/*
* 获取成员变量并调用:
*
* 1.批量的
* 1).Field[] getFields():获取所有的"公有字段" 【包含继承的字段】
* 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;【不包含继承的字段】
* 2.获取单个的:
* 1).public Field getField(String fieldName):获取某个"公有的"字段;【包含继承的字段】
* 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的) 【不包含继承的字段】
*
* 设置字段的值:
* Field --> public void set(Object obj,Object value):
* 参数说明:
* 1.obj:要设置的字段所在的对象;
* 2.value:要为字段设置的值;
*
*/
1.构建反射目标类 ReflectTarget 【在原先的基础上添加了一些成员变量】
public class ReflectTarget {
//---------构造函数-----------
//(默认的带参数构造函数)
ReflectTarget(String str) {
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造函数
public ReflectTarget() {
System.out.println("调用了公有的无参构造方法 。。。");
}
//有一个参数的构造函数
public ReflectTarget(char name) {
System.out.println("调用了带有一个参数的构造方法,参数值为 " + name);
}
//有多个参数的构造函数
public ReflectTarget(String name, int index) {
System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + " 【序号】" + index);
}
//受保护的构造函数
protected ReflectTarget(boolean n){
System.out.println("受保护的构造方法 n :" + n);
}
//私有的构造函数
private ReflectTarget(int index){
System.out.println("私有的构造方法 序号:" + index);
}
//**************字段*******************//
public String name;
protected int index;
char type;
private String targetInfo;
@Override
public String toString(){
return "ReflectTarget [name=" + name + ", index=" + index + ", type=" + type
+ ", targetInfo=" + targetInfo + "]";
}
}
2. 构建获取成员变量的类:
public class FieldCollector {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class reflectTargetClass = Class.forName("demo.reflect.ReflectTarget");
//1.获取所有公有的字段
System.out.println("************获取所有公有的字段********************");
Field[] fieldArray = reflectTargetClass.getFields();
for (Field f : fieldArray){
System.out.println(f);
}
//2.获取所有的字段
System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
fieldArray = reflectTargetClass.getDeclaredFields();
for (Field f : fieldArray){
System.out.println(f);
}
//3.获取单个特定公有的field
System.out.println("*************获取公有字段并调用***********************************");
Field f = reflectTargetClass.getField("name");
System.out.println("公有的field name : " + f);
// 调用的是无参的构造函数
ReflectTarget reflectTarget = (ReflectTarget)reflectTargetClass.getConstructor().newInstance();
//4.给获取到的field赋值
f.set(reflectTarget, "待反射一号");
//5.验证对应的值name
System.out.println("验证name : " + reflectTarget.name);
//6.获取单个私有的Field
System.out.println("**************获取私有字段targetInfo并调用********************************");
f = reflectTargetClass.getDeclaredField("targetInfo");
System.out.println(f);
f.setAccessible(true);
f.set(reflectTarget, "13810592345");
System.out.println("验证信息" + reflectTarget);
}
}
3.获取类的成员方法并使用:
1. 构建目标类:ReflectTarget
package demo.reflect;
public class ReflectTarget extends ReflectTargetOrigin{
//---------构造函数-----------
//(默认的带参数构造函数)
ReflectTarget(String str) {
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造函数
public ReflectTarget() {
System.out.println("调用了公有的无参构造方法 。。。");
}
//有一个参数的构造函数
public ReflectTarget(char name) {
System.out.println("调用了带有一个参数的构造方法,参数值为 " + name);
}
//有多个参数的构造函数
public ReflectTarget(String name, int index) {
System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + " 【序号】" + index);
}
//受保护的构造函数
protected ReflectTarget(boolean n){
System.out.println("受保护的构造方法 n :" + n);
}
//私有的构造函数
private ReflectTarget(int index){
System.out.println("私有的构造方法 序号:" + index);
}
//**************字段*******************//
public String name;
protected int index;
char type;
private String targetInfo;
@Override
public String toString(){
return "ReflectTarget [name=" + name + ", index=" + index + ", type=" + type
+ ", targetInfo=" + targetInfo + "]";
}
//***************成员方法***************//
public void show1(String s){
System.out.println("调用了公有的,String参数的show1(): s = " + s);
}
protected void show2(){
System.out.println("调用了受保护的,无参的show2()");
}
void show3(){
System.out.println("调用了默认的,无参的show3()");
}
private String show4(int index){
System.out.println("调用了私有的,并且有返回值的,int参数的show4(): index = " + index);
return "show4result";
}
}
2.构建获取成员方法的类:
MethodCollect
public class MethodCollect {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 1. 获取 Class 对象
Class reflectTargetClass =Class.forName("demo.reflect.ReflectTarget");
//2. 获取所有公有方法
System.out.println("*****************获取所有public方法,包括父类 和Object ********************");
Method[] methodArray = reflectTargetClass.getMethods();
for (Method m :methodArray){
System.out.println(m);
}
//3. 获取该类的所有方法
System.out.println("*****************获取该类所有方法,包括私有 ********************");
methodArray = reflectTargetClass.getDeclaredMethods();
for (Method m :methodArray){
System.out.println(m);
}
//4.获取公有的show1方法
System.out.println("*****************获取公有的show1方法 ********************");
Method m =reflectTargetClass.getMethod("show1",String.class);
System.out.println(m);
//5. 调用show1 并执行
//获取实例
ReflectTarget reflectTarget=(ReflectTarget)reflectTargetClass.getConstructor().newInstance();
m.invoke(reflectTarget,"待反射方法一号");
// 6. 获取一个私有的成员方法
System.out.println("*****************获取私有的show4方法 ********************");
m=reflectTargetClass.getDeclaredMethod("show4",int.class);
System.out.println(m);
m.setAccessible(true);
// invoke的 返回类型是Object,需要强转
String result=String.valueOf(m.invoke(reflectTarget,20));
System.out.println("返回值:"+result);
}
}
即使是反射也需要获取 类名 和类所在的包名
1.可以用xml来保存类相关的信息以供反射调用
2.也可以用注解:
5.注解:
提供一种为程序元素设置元数据的方法
1.注解的功能:
2.注解分类
元注解:
3.自定义注解的实现:
自动继承 java.lang.annotation.Annotation
不能继承其他的注解,也不能实现其他的接口类
格式: 访问修饰符只能是 public 或 缺省 【缺省 只能在同一个package内使用】,一般都是定义成public
属性名就是字段名,只不过是以方法的形式定义的,返回值是字段的类型
比如: 姓名这个字段
定义: public String name() ; 【public String name() default "学生";】 默认值有没有都可以。
目的:用上自定义注解,并用上注解信息
想要通过反射来获得注解信息@Retention 必须是 (RetentionPolicy.RUNTIME)
1. 定义两个注解 :
CourseInfoAnnotation
//作用在类上和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CourseInfoAnnotation {
//课程名称
public String courseName();
//课程标签
public String courseTag();
//课程简介
public String courseProfile();
//课程序号
public int courseIndex() default 303;
}
PersonInfoAnnotation
//作用在类的成员变量上
@Target(ElementType.FIELD)
//后续要在反射中获取注解相关的信息,即需要在程序运行时获取
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonInfoAnnotation {
//姓名
public String name() default "学生";
//年纪
public int age() default 19;
//性别
public String gender() default "男";
//开发语言
public String[] language();
}
2.创建一个类:ImoocCourse
在类上 使用了 @CourseInfoAnnotation 注解,并且将其属性都赋值
@CourseInfoAnnotation(courseName = "剑指java面试", courseTag = "面试",
courseProfile = "不仅讲解Java相关的核心知识,还涉及网络、数据库、缓存框架等核心知识,"
+ "帮助大家构建海陆空一体化的面试护城河。"
+ "全面提升大家的内功。"
)
public class ImoocCourse {
@PersonInfoAnnotation(name = "翔仔", language = {"Java","C++","Go","Python","PHP","JS"})
private String author;
@CourseInfoAnnotation(courseName = "校园商铺",
courseTag = "实战",
courseProfile = "手把手教会从前端到后端开发多店铺商铺管理系统,"
+ "可以用在毕设创业中,学习完会对SSM以及Springboot有一个"
+ "全面的了解",
courseIndex = 144)
public void getCourseInfo() {
}
}
3.创建解析注解类:
A.isAnnotationPresent(B.class);意思就是:注释B是否在此A上。如果在则返回true;不在则返回false。
public class AnnotationParser {
//解析类的注解
public static void parseTypeAnnotation() throws ClassNotFoundException {
Class clazz = Class.forName("demo.annotation.ImoocCourse");
//这里获取的是class对象的注解,而不是其里面的方法和成员变量的注解,
// 比如是获得ImoocCourse 类上的注解
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annotation : annotations){
CourseInfoAnnotation courseInfoAnnotation = (CourseInfoAnnotation) annotation;
System.out.println("课程名:" + courseInfoAnnotation.courseName() + "\n" +
"课程标签:" + courseInfoAnnotation.courseTag() + "\n" +
"课程简介:" + courseInfoAnnotation.courseProfile() + "\n" +
"课程序号:" + courseInfoAnnotation.courseIndex() );
}
}
//解析成员变量上的标签
public static void parseFieldAnnotation() throws ClassNotFoundException {
Class clazz = Class.forName("demo.annotation.ImoocCourse");
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
//判断成员变量中是否有指定注解类型的注解
boolean hasAnnotation = f.isAnnotationPresent(PersonInfoAnnotation.class);
if(hasAnnotation){
PersonInfoAnnotation personInfoAnnotation = f.getAnnotation(PersonInfoAnnotation.class);
System.out.println("名字:" + personInfoAnnotation.name() + "\n" +
"年龄:" + personInfoAnnotation.age() + "\n" +
"性别:" + personInfoAnnotation.gender() + "\n");
for(String language : personInfoAnnotation.language()){
System.out.println("开发语言:" + language);
}
}
}
}
//解析方法注解
public static void parseMethodAnnotation() throws ClassNotFoundException{
Class clazz = Class.forName("demo.annotation.ImoocCourse");
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
/*
* 判断方法中是否有指定注解类型的注解
*/
boolean hasAnnotation = method.isAnnotationPresent(CourseInfoAnnotation.class);
if(hasAnnotation){
CourseInfoAnnotation courseInfoAnnotation = method.getAnnotation(CourseInfoAnnotation.class);
System.out.println("课程名:" + courseInfoAnnotation.courseName() + "\n" +
"课程标签:" + courseInfoAnnotation.courseTag() + "\n" +
"课程简介:" + courseInfoAnnotation.courseProfile() + "\n"+
"课程序号:" + courseInfoAnnotation .courseIndex() + "\n");
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
parseTypeAnnotation();
// parseFieldAnnotation();
//parseMethodAnnotation();
}
}
执行结果: